⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 246073 in webkit


Ignore:
Timestamp:
Jun 4, 2019, 11:27:59 AM (7 years ago)
Author:
ysuzuki@apple.com
Message:

[JSC] InferredValue should not be a JSCell
https://bugs.webkit.org/show_bug.cgi?id=198407

Reviewed by Filip Pizlo.

Allocating InferredValue as a JSCell is too costly in terms of memory. Gmail has 90000 FunctionExecutables. And each gets
InferredValue, which takes 32 bytes. So it takes 2.7 MB memory footprint.

In this patch, we introduce a new container InferredValue<>. Which is similar to WriteBarrier<> container, but it replaces
the existing InferredValue cells with one pointer size field. The implementation of InferredValue<> is similar to
InlineWatchpointSet. But we encode JSCell* too to the pointer data of InlineWatchpointSet. So sizeof(InferredValue<>) is one
pointer size while it keeps Watchpoint feature and JSCell holder feature.

InferredValue<> needs validation in GC finalize phase. So this patch also makes SymbolTable Iso-allocated.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Sources.txt:
  • bytecode/ObjectAllocationProfileInlines.h:

(JSC::ObjectAllocationProfileBase<Derived>::initializeProfile):

  • bytecode/Watchpoint.h:
  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::get):
(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGClobbersExitState.cpp:

(JSC::DFG::clobbersExitState):

  • dfg/DFGDesiredWatchpoints.cpp:

(JSC::DFG::SymbolTableAdaptor::add):
(JSC::DFG::FunctionExecutableAdaptor::add):
(JSC::DFG::DesiredWatchpoints::addLazily):
(JSC::DFG::DesiredWatchpoints::reallyAdd):
(JSC::DFG::DesiredWatchpoints::areStillValid const):
(JSC::DFG::DesiredWatchpoints::dumpInContext const):
(JSC::DFG::InferredValueAdaptor::add): Deleted.

  • dfg/DFGDesiredWatchpoints.h:

(JSC::DFG::SymbolTableAdaptor::hasBeenInvalidated):
(JSC::DFG::SymbolTableAdaptor::dumpInContext):
(JSC::DFG::FunctionExecutableAdaptor::hasBeenInvalidated):
(JSC::DFG::FunctionExecutableAdaptor::dumpInContext):
(JSC::DFG::DesiredWatchpoints::isWatched):
(JSC::DFG::InferredValueAdaptor::hasBeenInvalidated): Deleted.
(JSC::DFG::InferredValueAdaptor::dumpInContext): Deleted.

  • dfg/DFGObjectAllocationSinkingPhase.cpp:
  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileNewFunction):
(JSC::DFG::SpeculativeJIT::compileCreateActivation):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileCreateActivation):
(JSC::FTL::DFG::LowerDFGToB3::compileNewFunction):

  • heap/Heap.cpp:

(JSC::Heap::finalizeUnconditionalFinalizers):

  • runtime/FunctionExecutable.cpp:

(JSC::FunctionExecutable::FunctionExecutable):
(JSC::FunctionExecutable::finishCreation):
(JSC::FunctionExecutable::visitChildren):

  • runtime/FunctionExecutable.h:
  • runtime/FunctionExecutableInlines.h: Copied from Source/JavaScriptCore/runtime/InferredValueInlines.h.

(JSC::FunctionExecutable::finalizeUnconditionally):

  • runtime/InferredValue.cpp: Removed.
  • runtime/InferredValue.h:

(JSC::InferredValue::inferredValue):
(JSC::InferredValue::InferredValue):
(JSC::InferredValue::~InferredValue):
(JSC::InferredValue::stateOnJSThread const):
(JSC::InferredValue::state const):
(JSC::InferredValue::hasBeenInvalidated const):
(JSC::InferredValue::isStillValid const):
(JSC::InferredValue::invalidate):
(JSC::InferredValue::isBeingWatched const):
(JSC::InferredValue::notifyWrite):
(JSC::InferredValue::isThin):
(JSC::InferredValue::isFat):
(JSC::InferredValue::decodeState):
(JSC::InferredValue::encodeState):
(JSC::InferredValue::isThin const):
(JSC::InferredValue::isFat const):
(JSC::InferredValue::fat):
(JSC::InferredValue::fat const):
(JSC::InferredValue::inflate):
(JSC::InferredValue<JSCellType>::InferredValueWatchpointSet::notifyWriteSlow):
(JSC::InferredValue<JSCellType>::notifyWriteSlow):
(JSC::InferredValue<JSCellType>::add):
(JSC::InferredValue<JSCellType>::inflateSlow):
(JSC::InferredValue<JSCellType>::freeFat):

  • runtime/InferredValueInlines.h:

(JSC::InferredValue<JSCellType>::finalizeUnconditionally):
(JSC::InferredValue::finalizeUnconditionally): Deleted.

  • runtime/JSFunctionInlines.h:

(JSC::JSFunction::createWithInvalidatedReallocationWatchpoint):

  • runtime/JSSymbolTableObject.h:

(JSC::JSSymbolTableObject::setSymbolTable):

  • runtime/SymbolTable.cpp:

(JSC::SymbolTable::finishCreation):
(JSC::SymbolTable::visitChildren):

  • runtime/SymbolTable.h:
  • runtime/SymbolTableInlines.h: Copied from Source/JavaScriptCore/runtime/InferredValueInlines.h.

(JSC::SymbolTable::finalizeUnconditionally):

  • runtime/VM.cpp:

(JSC::VM::VM):

  • runtime/VM.h:
Location:
trunk/Source/JavaScriptCore
Files:
1 deleted
25 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r246071 r246073  
     12019-06-04  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] InferredValue should not be a JSCell
     4        https://bugs.webkit.org/show_bug.cgi?id=198407
     5
     6        Reviewed by Filip Pizlo.
     7
     8        Allocating InferredValue as a JSCell is too costly in terms of memory. Gmail has 90000 FunctionExecutables. And each gets
     9        InferredValue, which takes 32 bytes. So it takes 2.7 MB memory footprint.
     10
     11        In this patch, we introduce a new container InferredValue<>. Which is similar to WriteBarrier<> container, but it replaces
     12        the existing InferredValue cells with one pointer size field. The implementation of InferredValue<> is similar to
     13        InlineWatchpointSet. But we encode JSCell* too to the pointer data of InlineWatchpointSet. So sizeof(InferredValue<>) is one
     14        pointer size while it keeps Watchpoint feature and JSCell holder feature.
     15
     16        InferredValue<> needs validation in GC finalize phase. So this patch also makes SymbolTable Iso-allocated.
     17
     18        * JavaScriptCore.xcodeproj/project.pbxproj:
     19        * Sources.txt:
     20        * bytecode/ObjectAllocationProfileInlines.h:
     21        (JSC::ObjectAllocationProfileBase<Derived>::initializeProfile):
     22        * bytecode/Watchpoint.h:
     23        * dfg/DFGAbstractInterpreterInlines.h:
     24        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     25        * dfg/DFGByteCodeParser.cpp:
     26        (JSC::DFG::ByteCodeParser::get):
     27        (JSC::DFG::ByteCodeParser::parseBlock):
     28        * dfg/DFGClobberize.h:
     29        (JSC::DFG::clobberize):
     30        * dfg/DFGClobbersExitState.cpp:
     31        (JSC::DFG::clobbersExitState):
     32        * dfg/DFGDesiredWatchpoints.cpp:
     33        (JSC::DFG::SymbolTableAdaptor::add):
     34        (JSC::DFG::FunctionExecutableAdaptor::add):
     35        (JSC::DFG::DesiredWatchpoints::addLazily):
     36        (JSC::DFG::DesiredWatchpoints::reallyAdd):
     37        (JSC::DFG::DesiredWatchpoints::areStillValid const):
     38        (JSC::DFG::DesiredWatchpoints::dumpInContext const):
     39        (JSC::DFG::InferredValueAdaptor::add): Deleted.
     40        * dfg/DFGDesiredWatchpoints.h:
     41        (JSC::DFG::SymbolTableAdaptor::hasBeenInvalidated):
     42        (JSC::DFG::SymbolTableAdaptor::dumpInContext):
     43        (JSC::DFG::FunctionExecutableAdaptor::hasBeenInvalidated):
     44        (JSC::DFG::FunctionExecutableAdaptor::dumpInContext):
     45        (JSC::DFG::DesiredWatchpoints::isWatched):
     46        (JSC::DFG::InferredValueAdaptor::hasBeenInvalidated): Deleted.
     47        (JSC::DFG::InferredValueAdaptor::dumpInContext): Deleted.
     48        * dfg/DFGObjectAllocationSinkingPhase.cpp:
     49        * dfg/DFGSpeculativeJIT.cpp:
     50        (JSC::DFG::SpeculativeJIT::compileNewFunction):
     51        (JSC::DFG::SpeculativeJIT::compileCreateActivation):
     52        * ftl/FTLLowerDFGToB3.cpp:
     53        (JSC::FTL::DFG::LowerDFGToB3::compileCreateActivation):
     54        (JSC::FTL::DFG::LowerDFGToB3::compileNewFunction):
     55        * heap/Heap.cpp:
     56        (JSC::Heap::finalizeUnconditionalFinalizers):
     57        * runtime/FunctionExecutable.cpp:
     58        (JSC::FunctionExecutable::FunctionExecutable):
     59        (JSC::FunctionExecutable::finishCreation):
     60        (JSC::FunctionExecutable::visitChildren):
     61        * runtime/FunctionExecutable.h:
     62        * runtime/FunctionExecutableInlines.h: Copied from Source/JavaScriptCore/runtime/InferredValueInlines.h.
     63        (JSC::FunctionExecutable::finalizeUnconditionally):
     64        * runtime/InferredValue.cpp: Removed.
     65        * runtime/InferredValue.h:
     66        (JSC::InferredValue::inferredValue):
     67        (JSC::InferredValue::InferredValue):
     68        (JSC::InferredValue::~InferredValue):
     69        (JSC::InferredValue::stateOnJSThread const):
     70        (JSC::InferredValue::state const):
     71        (JSC::InferredValue::hasBeenInvalidated const):
     72        (JSC::InferredValue::isStillValid const):
     73        (JSC::InferredValue::invalidate):
     74        (JSC::InferredValue::isBeingWatched const):
     75        (JSC::InferredValue::notifyWrite):
     76        (JSC::InferredValue::isThin):
     77        (JSC::InferredValue::isFat):
     78        (JSC::InferredValue::decodeState):
     79        (JSC::InferredValue::encodeState):
     80        (JSC::InferredValue::isThin const):
     81        (JSC::InferredValue::isFat const):
     82        (JSC::InferredValue::fat):
     83        (JSC::InferredValue::fat const):
     84        (JSC::InferredValue::inflate):
     85        (JSC::InferredValue<JSCellType>::InferredValueWatchpointSet::notifyWriteSlow):
     86        (JSC::InferredValue<JSCellType>::notifyWriteSlow):
     87        (JSC::InferredValue<JSCellType>::add):
     88        (JSC::InferredValue<JSCellType>::inflateSlow):
     89        (JSC::InferredValue<JSCellType>::freeFat):
     90        * runtime/InferredValueInlines.h:
     91        (JSC::InferredValue<JSCellType>::finalizeUnconditionally):
     92        (JSC::InferredValue::finalizeUnconditionally): Deleted.
     93        * runtime/JSFunctionInlines.h:
     94        (JSC::JSFunction::createWithInvalidatedReallocationWatchpoint):
     95        * runtime/JSSymbolTableObject.h:
     96        (JSC::JSSymbolTableObject::setSymbolTable):
     97        * runtime/SymbolTable.cpp:
     98        (JSC::SymbolTable::finishCreation):
     99        (JSC::SymbolTable::visitChildren):
     100        * runtime/SymbolTable.h:
     101        * runtime/SymbolTableInlines.h: Copied from Source/JavaScriptCore/runtime/InferredValueInlines.h.
     102        (JSC::SymbolTable::finalizeUnconditionally):
     103        * runtime/VM.cpp:
     104        (JSC::VM::VM):
     105        * runtime/VM.h:
     106
    11072019-06-04  Tadeu Zagallo  <tzagallo@apple.com>
    2108
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r246060 r246073  
    17751775                E33F50851B8437A000413856 /* JSInternalPromiseDeferred.h in Headers */ = {isa = PBXBuildFile; fileRef = E33F50831B8437A000413856 /* JSInternalPromiseDeferred.h */; settings = {ATTRIBUTES = (Private, ); }; };
    17761776                E33F50871B8449EF00413856 /* JSInternalPromiseConstructor.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = E33F50861B8449EF00413856 /* JSInternalPromiseConstructor.lut.h */; };
     1777                E3400EC122A1CC7B009DED54 /* FunctionExecutableInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E3400EC022A1CC78009DED54 /* FunctionExecutableInlines.h */; };
    17771778                E34E657520668EAA00FB81AC /* ParseHash.h in Headers */ = {isa = PBXBuildFile; fileRef = E34E657320668E8D00FB81AC /* ParseHash.h */; settings = {ATTRIBUTES = (Private, ); }; };
    17781779                E34EDBF71DB5FFC900DC87A5 /* FrameTracers.h in Headers */ = {isa = PBXBuildFile; fileRef = E34EDBF61DB5FFC100DC87A5 /* FrameTracers.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    17931794                E39006212208BFC4001019CF /* SubspaceAccess.h in Headers */ = {isa = PBXBuildFile; fileRef = E39006202208BFC3001019CF /* SubspaceAccess.h */; settings = {ATTRIBUTES = (Private, ); }; };
    17941795                E393ADD81FE702D00022D681 /* WeakMapImplInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E393ADD71FE702CC0022D681 /* WeakMapImplInlines.h */; };
     1796                E39BF39922A2288B00BD183E /* SymbolTableInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E39BF39822A2288B00BD183E /* SymbolTableInlines.h */; };
    17951797                E39D45F51D39005600B3B377 /* InterpreterInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E39D9D841D39000600667282 /* InterpreterInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
    17961798                E39DA4A71B7E8B7C0084F33A /* JSModuleRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    31343136                0FF729A1166AD347000F5BA3 /* ProfilerOriginStack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProfilerOriginStack.cpp; path = profiler/ProfilerOriginStack.cpp; sourceTree = "<group>"; };
    31353137                0FF729A2166AD347000F5BA3 /* ProfilerOriginStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerOriginStack.h; path = profiler/ProfilerOriginStack.h; sourceTree = "<group>"; };
    3136                 0FF8BDE81AD4CF7100DFE884 /* InferredValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InferredValue.cpp; sourceTree = "<group>"; };
    31373138                0FF8BDE91AD4CF7100DFE884 /* InferredValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InferredValue.h; sourceTree = "<group>"; };
    31383139                0FF922CF14F46B130041A24E /* JSCLLIntOffsetsExtractor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = JSCLLIntOffsetsExtractor; sourceTree = BUILT_PRODUCTS_DIR; };
     
    47734774                E33F50861B8449EF00413856 /* JSInternalPromiseConstructor.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSInternalPromiseConstructor.lut.h; sourceTree = "<group>"; };
    47744775                E33F50881B844A1A00413856 /* InternalPromiseConstructor.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = InternalPromiseConstructor.js; sourceTree = "<group>"; };
     4776                E3400EC022A1CC78009DED54 /* FunctionExecutableInlines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FunctionExecutableInlines.h; sourceTree = "<group>"; };
    47754777                E34E657320668E8D00FB81AC /* ParseHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParseHash.h; sourceTree = "<group>"; };
    47764778                E34E657420668E8E00FB81AC /* ParseHash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParseHash.cpp; sourceTree = "<group>"; };
     
    48054807                E393ADD71FE702CC0022D681 /* WeakMapImplInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakMapImplInlines.h; sourceTree = "<group>"; };
    48064808                E3963CEC1B73F75000EB4CE5 /* NodesAnalyzeModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NodesAnalyzeModule.cpp; sourceTree = "<group>"; };
     4809                E39BF39822A2288B00BD183E /* SymbolTableInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolTableInlines.h; sourceTree = "<group>"; };
    48074810                E39D9D841D39000600667282 /* InterpreterInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InterpreterInlines.h; sourceTree = "<group>"; };
    48084811                E39DA4A41B7E8B7C0084F33A /* JSModuleRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleRecord.cpp; sourceTree = "<group>"; };
     
    68736876                                0FB4B52116B6278D003F696B /* FunctionExecutableDump.cpp */,
    68746877                                0FB4B52216B6278D003F696B /* FunctionExecutableDump.h */,
     6878                                E3400EC022A1CC78009DED54 /* FunctionExecutableInlines.h */,
    68756879                                52B310FC1974AE870080857C /* FunctionHasExecutedCache.cpp */,
    68766880                                52B310FA1974AE610080857C /* FunctionHasExecutedCache.h */,
     
    69106914                                14386A761DD6989C008652C4 /* IndirectEvalExecutable.cpp */,
    69116915                                14386A771DD6989C008652C4 /* IndirectEvalExecutable.h */,
    6912                                 0FF8BDE81AD4CF7100DFE884 /* InferredValue.cpp */,
    69136916                                0FF8BDE91AD4CF7100DFE884 /* InferredValue.h */,
    69146917                                0F4AE0421FE0D25400E20839 /* InferredValueInlines.h */,
     
    73187321                                0F919D2715856770004A4E7D /* SymbolTable.cpp */,
    73197322                                14A396A60CD2933100B5B4FF /* SymbolTable.h */,
     7323                                E39BF39822A2288B00BD183E /* SymbolTableInlines.h */,
    73207324                                E31179A92288385D00514B2C /* SymbolTableOrScopeDepth.h */,
    73217325                                BDB4B5E099CD4C1BB3C1CF05 /* TemplateObjectDescriptor.cpp */,
     
    91859189                                147341D81DC02F9900AA29BA /* FunctionExecutable.h in Headers */,
    91869190                                0FF0F1A016B72A1A005DF95B /* FunctionExecutableDump.h in Headers */,
     9191                                E3400EC122A1CC7B009DED54 /* FunctionExecutableInlines.h in Headers */,
    91879192                                52B310FB1974AE610080857C /* FunctionHasExecutedCache.h in Headers */,
    91889193                                FE4BFF2C1AD476E700088F87 /* FunctionOverrides.h in Headers */,
     
    98819886                                996B73281BDA08EF00331B84 /* SymbolPrototype.lut.h in Headers */,
    98829887                                BC18C46B0E16F5CD00B34460 /* SymbolTable.h in Headers */,
     9888                                E39BF39922A2288B00BD183E /* SymbolTableInlines.h in Headers */,
    98839889                                E31179AA2288386100514B2C /* SymbolTableOrScopeDepth.h in Headers */,
    98849890                                0FD79A2D1EBBBDBB00DA88D3 /* Synchronousness.h in Headers */,
  • trunk/Source/JavaScriptCore/Sources.txt

    r246060 r246073  
    785785runtime/IndexingType.cpp
    786786runtime/IndirectEvalExecutable.cpp
    787 runtime/InferredValue.cpp
    788787runtime/InitializeThreading.cpp
    789788runtime/InspectorInstrumentationObject.cpp
  • trunk/Source/JavaScriptCore/bytecode/ObjectAllocationProfileInlines.h

    r245658 r246073  
    6464            isPolyProto = true;
    6565        else
    66             isPolyProto = executable->ensurePolyProtoWatchpoint().hasBeenInvalidated() && executable->singletonFunctionHasBeenInvalidated();
     66            isPolyProto = executable->ensurePolyProtoWatchpoint().hasBeenInvalidated() && executable->singleton().hasBeenInvalidated();
    6767    }
    6868
  • trunk/Source/JavaScriptCore/bytecode/Watchpoint.h

    r245214 r246073  
    162162};
    163163
    164 enum WatchpointState {
    165     ClearWatchpoint,
    166     IsWatched,
    167     IsInvalidated
     164// Make sure that the state can be represented in 2 bits.
     165enum WatchpointState : uint8_t {
     166    ClearWatchpoint = 0,
     167    IsWatched = 1,
     168    IsInvalidated = 2
    168169};
    169170
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r246041 r246073  
    27632763    case GetCallee:
    27642764        if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(m_vm, m_codeBlock->ownerExecutable())) {
    2765             InferredValue* singleton = executable->singletonFunction();
    2766             if (JSValue value = singleton->inferredValue()) {
    2767                 m_graph.watchpoints().addLazily(singleton);
    2768                 JSFunction* function = jsCast<JSFunction*>(value);
     2765            if (JSFunction* function = executable->singleton().inferredValue()) {
     2766                m_graph.watchpoints().addLazily(executable);
    27692767                setConstant(node, *m_graph.freeze(function));
    27702768                break;
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r246041 r246073  
    322322            // case if the function is a singleton then we already know it.
    323323            if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(*m_vm, m_codeBlock->ownerExecutable())) {
    324                 InferredValue* singleton = executable->singletonFunction();
    325                 if (JSValue value = singleton->inferredValue()) {
    326                     m_graph.watchpoints().addLazily(singleton);
    327                     JSFunction* function = jsCast<JSFunction*>(value);
     324                if (JSFunction* function = executable->singleton().inferredValue()) {
     325                    m_graph.watchpoints().addLazily(executable);
    328326                    return weakJSConstant(function);
    329327                }
     
    62776275                // We have various forms of constant folding here. This is necessary to avoid
    62786276                // spurious recompiles in dead-but-foldable code.
     6277
    62796278                if (symbolTable) {
    6280                     InferredValue* singleton = symbolTable->singletonScope();
    6281                     if (JSValue value = singleton->inferredValue()) {
    6282                         m_graph.watchpoints().addLazily(singleton);
    6283                         set(bytecode.m_dst, weakJSConstant(value));
     6279                    if (JSScope* scope = symbolTable->singleton().inferredValue()) {
     6280                        m_graph.watchpoints().addLazily(symbolTable);
     6281                        set(bytecode.m_dst, weakJSConstant(scope));
    62846282                        break;
    62856283                    }
     
    63126310            auto bytecode = currentInstruction->as<OpResolveScopeForHoistingFuncDeclInEval>();
    63136311            unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[bytecode.m_property];
    6314 
    63156312            set(bytecode.m_dst, addToGraph(ResolveScopeForHoistingFuncDeclInEval, OpInfo(identifierNumber), get(bytecode.m_scope)));
    63166313
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r246041 r246073  
    515515    case CreateActivation: {
    516516        SymbolTable* table = node->castOperand<SymbolTable*>();
    517         if (table->singletonScope()->isStillValid())
     517        if (table->singleton().isStillValid())
    518518            write(Watchpoint_fire);
    519519        read(HeapObjectCount);
     
    15691569    case NewAsyncGeneratorFunction:
    15701570    case NewAsyncFunction:
    1571         if (node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid())
     1571        if (node->castOperand<FunctionExecutable*>()->singleton().isStillValid())
    15721572            write(Watchpoint_fire);
    15731573        read(HeapObjectCount);
  • trunk/Source/JavaScriptCore/dfg/DFGClobbersExitState.cpp

    r239142 r246073  
    8888    case CreateActivation:
    8989        // Like above, but with the activation allocation caveat.
    90         return node->castOperand<SymbolTable*>()->singletonScope()->isStillValid();
     90        return node->castOperand<SymbolTable*>()->singleton().isStillValid();
    9191
    9292    case NewFunction:
     
    9595    case NewAsyncFunction:
    9696        // Like above, but with the JSFunction allocation caveat.
    97         return node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid();
     97        return node->castOperand<FunctionExecutable*>()->singleton().isStillValid();
    9898
    9999    default:
  • trunk/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp

    r243560 r246073  
    4949}
    5050
    51 void InferredValueAdaptor::add(
    52     CodeBlock* codeBlock, InferredValue* inferredValue, CommonData& common)
     51void SymbolTableAdaptor::add(
     52    CodeBlock* codeBlock, SymbolTable* symbolTable, CommonData& common)
    5353{
    54     codeBlock->addConstant(inferredValue); // For common users, it doesn't really matter if it's weak or not. If references to it go away, we go away, too.
    55     inferredValue->add(common.watchpoints.add(codeBlock));
     54    codeBlock->addConstant(symbolTable); // For common users, it doesn't really matter if it's weak or not. If references to it go away, we go away, too.
     55    symbolTable->singleton().add(common.watchpoints.add(codeBlock));
     56}
     57
     58void FunctionExecutableAdaptor::add(
     59    CodeBlock* codeBlock, FunctionExecutable* executable, CommonData& common)
     60{
     61    codeBlock->addConstant(executable); // For common users, it doesn't really matter if it's weak or not. If references to it go away, we go away, too.
     62    executable->singleton().add(common.watchpoints.add(codeBlock));
    5663}
    5764
     
    8390}
    8491
    85 void DesiredWatchpoints::addLazily(InferredValue* inferredValue)
     92void DesiredWatchpoints::addLazily(SymbolTable* symbolTable)
    8693{
    87     m_inferredValues.addLazily(inferredValue);
     94    m_symbolTables.addLazily(symbolTable);
     95}
     96
     97void DesiredWatchpoints::addLazily(FunctionExecutable* executable)
     98{
     99    m_functionExecutables.addLazily(executable);
    88100}
    89101
     
    110122    m_sets.reallyAdd(codeBlock, commonData);
    111123    m_inlineSets.reallyAdd(codeBlock, commonData);
    112     m_inferredValues.reallyAdd(codeBlock, commonData);
     124    m_symbolTables.reallyAdd(codeBlock, commonData);
     125    m_functionExecutables.reallyAdd(codeBlock, commonData);
    113126    m_bufferViews.reallyAdd(codeBlock, commonData);
    114127    m_adaptiveStructureSets.reallyAdd(codeBlock, commonData);
     
    119132    return m_sets.areStillValid()
    120133        && m_inlineSets.areStillValid()
    121         && m_inferredValues.areStillValid()
     134        && m_symbolTables.areStillValid()
     135        && m_functionExecutables.areStillValid()
    122136        && m_bufferViews.areStillValid()
    123137        && m_adaptiveStructureSets.areStillValid();
     
    129143    out.print("    Watchpoint sets: ", inContext(m_sets, context), "\n");
    130144    out.print("    Inline watchpoint sets: ", inContext(m_inlineSets, context), "\n");
    131     out.print("    Inferred values: ", inContext(m_inferredValues, context), "\n");
     145    out.print("    SymbolTables: ", inContext(m_symbolTables, context), "\n");
     146    out.print("    FunctionExecutables: ", inContext(m_functionExecutables, context), "\n");
    132147    out.print("    Buffer views: ", inContext(m_bufferViews, context), "\n");
    133148    out.print("    Object property conditions: ", inContext(m_adaptiveStructureSets, context), "\n");
  • trunk/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h

    r240023 r246073  
    2929
    3030#include "DFGCommonData.h"
    31 #include "InferredValue.h"
     31#include "FunctionExecutable.h"
    3232#include "JSArrayBufferView.h"
    3333#include "ObjectPropertyCondition.h"
     34#include "SymbolTable.h"
    3435#include "Watchpoint.h"
    3536#include <wtf/CommaPrinter.h>
     
    5657};
    5758
    58 struct InferredValueAdaptor {
    59     static void add(CodeBlock*, InferredValue*, CommonData&);
    60     static bool hasBeenInvalidated(InferredValue* inferredValue)
    61     {
    62         return inferredValue->hasBeenInvalidated();
    63     }
    64     static void dumpInContext(PrintStream& out, InferredValue* inferredValue, DumpContext*)
    65     {
    66         out.print(RawPointer(inferredValue));
     59struct SymbolTableAdaptor {
     60    static void add(CodeBlock*, SymbolTable*, CommonData&);
     61    static bool hasBeenInvalidated(SymbolTable* symbolTable)
     62    {
     63        return symbolTable->singleton().hasBeenInvalidated();
     64    }
     65    static void dumpInContext(PrintStream& out, SymbolTable* symbolTable, DumpContext*)
     66    {
     67        out.print(RawPointer(symbolTable));
     68    }
     69};
     70
     71struct FunctionExecutableAdaptor {
     72    static void add(CodeBlock*, FunctionExecutable*, CommonData&);
     73    static bool hasBeenInvalidated(FunctionExecutable* executable)
     74    {
     75        return executable->singleton().hasBeenInvalidated();
     76    }
     77    static void dumpInContext(PrintStream& out, FunctionExecutable* executable, DumpContext*)
     78    {
     79        out.print(RawPointer(executable));
    6780    }
    6881};
     
    155168    void addLazily(WatchpointSet*);
    156169    void addLazily(InlineWatchpointSet&);
    157     void addLazily(InferredValue*);
     170    void addLazily(SymbolTable*);
     171    void addLazily(FunctionExecutable*);
    158172    void addLazily(JSArrayBufferView*);
    159173   
     
    176190        return m_inlineSets.isWatched(&set);
    177191    }
    178     bool isWatched(InferredValue* inferredValue)
    179     {
    180         return m_inferredValues.isWatched(inferredValue);
     192    bool isWatched(SymbolTable* symbolTable)
     193    {
     194        return m_symbolTables.isWatched(symbolTable);
     195    }
     196    bool isWatched(FunctionExecutable* executable)
     197    {
     198        return m_functionExecutables.isWatched(executable);
    181199    }
    182200    bool isWatched(JSArrayBufferView* view)
     
    194212    GenericDesiredWatchpoints<WatchpointSet*> m_sets;
    195213    GenericDesiredWatchpoints<InlineWatchpointSet*> m_inlineSets;
    196     GenericDesiredWatchpoints<InferredValue*, InferredValueAdaptor> m_inferredValues;
     214    GenericDesiredWatchpoints<SymbolTable*, SymbolTableAdaptor> m_symbolTables;
     215    GenericDesiredWatchpoints<FunctionExecutable*, FunctionExecutableAdaptor> m_functionExecutables;
    197216    GenericDesiredWatchpoints<JSArrayBufferView*, ArrayBufferViewWatchpointAdaptor> m_bufferViews;
    198217    GenericDesiredWatchpoints<ObjectPropertyCondition, AdaptiveStructureWatchpointAdaptor> m_adaptiveStructureSets;
  • trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp

    r243232 r246073  
    841841        case NewAsyncGeneratorFunction:
    842842        case NewAsyncFunction: {
    843             if (isStillValid(node->castOperand<FunctionExecutable*>()->singletonFunction())) {
     843            if (isStillValid(node->castOperand<FunctionExecutable*>())) {
    844844                m_heap.escape(node->child1().node());
    845845                break;
     
    869869
    870870        case CreateActivation: {
    871             if (isStillValid(node->castOperand<SymbolTable*>()->singletonScope())) {
     871            if (isStillValid(node->castOperand<SymbolTable*>())) {
    872872                m_heap.escape(node->child1().node());
    873873                break;
     
    23832383    // returns but breaks badly if this changes its mind for any particular InferredValue. This
    23842384    // method protects us from that.
    2385     bool isStillValid(InferredValue* value)
    2386     {
    2387         return m_validInferredValues.add(value, value->isStillValid()).iterator->value;
    2388     }
     2385    bool isStillValid(SymbolTable* value)
     2386    {
     2387        return m_validInferredValues.add(value, value->singleton().isStillValid()).iterator->value;
     2388    }
     2389
     2390    bool isStillValid(FunctionExecutable* value)
     2391    {
     2392        return m_validInferredValues.add(value, value->singleton().isStillValid()).iterator->value;
     2393    }
     2394
    23892395
    23902396    SSACalculator m_pointerSSA;
     
    23982404    CombinedLiveness m_combinedLiveness;
    23992405
    2400     HashMap<InferredValue*, bool> m_validInferredValues;
     2406    HashMap<JSCell*, bool> m_validInferredValues;
    24012407
    24022408    HashMap<Node*, Node*> m_materializationToEscapee;
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r246041 r246073  
    71947194    FunctionExecutable* executable = node->castOperand<FunctionExecutable*>();
    71957195
    7196     if (executable->singletonFunction()->isStillValid()) {
     7196    if (executable->singleton().isStillValid()) {
    71977197        GPRFlushedCallResult result(this);
    71987198        GPRReg resultGPR = result.gpr();
     
    74117411    ASSERT(initializationValue == jsUndefined() || initializationValue == jsTDZValue());
    74127412   
    7413     if (table->singletonScope()->isStillValid()) {
     7413    if (table->singleton().isStillValid()) {
    74147414        GPRFlushedCallResult result(this);
    74157415        GPRReg resultGPR = result.gpr();
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r246071 r246073  
    54425442        JSValue initializationValue = m_node->initializationValueForActivation();
    54435443        ASSERT(initializationValue.isUndefined() || initializationValue == jsTDZValue());
    5444         if (table->singletonScope()->isStillValid()) {
     5444        if (table->singleton().isStillValid()) {
    54455445            LValue callResult = vmCall(
    54465446                Int64,
     
    55035503       
    55045504        FunctionExecutable* executable = m_node->castOperand<FunctionExecutable*>();
    5505         if (executable->singletonFunction()->isStillValid()) {
     5505        if (executable->singleton().isStillValid()) {
    55065506            LValue callResult =
    55075507                isGeneratorFunction ? vmCall(Int64, m_out.operation(operationNewGeneratorFunction), m_callFrame, scope, weakPointer(executable)) :
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r245808 r246073  
    3232#include "Exception.h"
    3333#include "FullGCActivityCallback.h"
     34#include "FunctionExecutableInlines.h"
    3435#include "GCActivityCallback.h"
    3536#include "GCIncomingRefCountedSetInlines.h"
     
    6869#include "SuperSampler.h"
    6970#include "SweepingScope.h"
     71#include "SymbolTableInlines.h"
    7072#include "SynchronousStopTheWorldMutatorScheduler.h"
    7173#include "TypeProfiler.h"
     
    597599{
    598600    vm()->builtinExecutables()->finalizeUnconditionally();
    599     if (vm()->m_inferredValueSpace)
    600         finalizeMarkedUnconditionalFinalizers<InferredValue>(vm()->m_inferredValueSpace->space);
     601    finalizeMarkedUnconditionalFinalizers<FunctionExecutable>(vm()->functionExecutableSpace.space);
     602    finalizeMarkedUnconditionalFinalizers<SymbolTable>(vm()->symbolTableSpace);
    601603    vm()->forEachCodeBlockSpace(
    602604        [&] (auto& space) {
  • trunk/Source/JavaScriptCore/runtime/FunctionExecutable.cpp

    r245040 r246073  
    4949    RELEASE_ASSERT(!source.isNull());
    5050    ASSERT(source.length());
    51     if (VM::canUseJIT())
    52         new (&m_singletonFunction) WriteBarrier<InferredValue>();
    53     else
    54         m_singletonFunctionState = ClearWatchpoint;
    5551}
    5652
     
    5955    Base::finishCreation(vm);
    6056    m_topLevelExecutable.set(vm, this, topLevelExecutable ? topLevelExecutable : this);
    61     if (VM::canUseJIT())
    62         m_singletonFunction.set(vm, this, InferredValue::create(vm));
    6357}
    6458
     
    9185    visitor.append(thisObject->m_codeBlockForConstruct);
    9286    visitor.append(thisObject->m_unlinkedExecutable);
    93     if (VM::canUseJIT())
    94         visitor.append(thisObject->m_singletonFunction);
    9587    if (RareData* rareData = thisObject->m_rareData.get()) {
    9688        visitor.append(rareData->m_cachedPolyProtoStructure);
  • trunk/Source/JavaScriptCore/runtime/FunctionExecutable.h

    r245288 r246073  
    249249    DECLARE_INFO;
    250250
    251     InferredValue* singletonFunction()
    252     {
    253         if (VM::canUseJIT())
    254             return m_singletonFunction.get();
    255         return nullptr;
    256     }
    257 
    258     void notifyCreation(VM& vm, JSValue value, const char* reason)
    259     {
    260         if (VM::canUseJIT()) {
    261             singletonFunction()->notifyWrite(vm, value, reason);
    262             return;
    263         }
    264         switch (m_singletonFunctionState) {
    265         case ClearWatchpoint:
    266             m_singletonFunctionState = IsWatched;
    267             return;
    268         case IsWatched:
    269             m_singletonFunctionState = IsInvalidated;
    270             return;
    271         case IsInvalidated:
    272             return;
    273         }
    274     }
    275 
    276     bool singletonFunctionHasBeenInvalidated()
    277     {
    278         if (VM::canUseJIT())
    279             return singletonFunction()->hasBeenInvalidated();
    280         return m_singletonFunctionState == IsInvalidated;
     251    InferredValue<JSFunction>& singleton()
     252    {
     253        return m_singleton;
     254    }
     255
     256    void notifyCreation(VM& vm, JSFunction* function, const char* reason)
     257    {
     258        m_singleton.notifyWrite(vm, this, function, reason);
    281259    }
    282260
     
    305283
    306284    TemplateObjectMap& ensureTemplateObjectMap(VM&);
     285
     286    void finalizeUnconditionally(VM&);
    307287
    308288private:
     
    343323    WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForCall;
    344324    WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForConstruct;
    345     union {
    346         WriteBarrier<InferredValue> m_singletonFunction;
    347         WatchpointState m_singletonFunctionState;
    348     };
     325    InferredValue<JSFunction> m_singleton;
    349326    Box<InlineWatchpointSet> m_polyProtoWatchpoint;
    350327};
  • trunk/Source/JavaScriptCore/runtime/FunctionExecutableInlines.h

    r246072 r246073  
    11/*
    2  * Copyright (C) 2017 Apple Inc. All rights reserved.
     2 * Copyright (C) 2019 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2121 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    2222 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2424 */
    2525
    2626#pragma once
    2727
    28 #include "InferredValue.h"
     28#include "FunctionExecutable.h"
     29#include "InferredValueInlines.h"
    2930
    3031namespace JSC {
    3132
    32 void InferredValue::finalizeUnconditionally(VM& vm)
     33inline void FunctionExecutable::finalizeUnconditionally(VM& vm)
    3334{
    34     JSValue value = m_value.get();
    35    
    36     if (value && value.isCell()) {
    37         if (vm.heap.isMarked(value.asCell()))
    38             return;
    39        
    40         invalidate(vm, StringFireDetail("InferredValue clean-up during GC"));
    41     }
    42    
    43     VM::SpaceAndSet::setFor(*subspace()).remove(this);
     35    m_singleton.finalizeUnconditionally(vm);
    4436}
    4537
  • trunk/Source/JavaScriptCore/runtime/InferredValue.h

    r240965 r246073  
    11/*
    2  * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
     2 * Copyright (C) 2015-2019 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2626#pragma once
    2727
    28 #include "IsoSubspace.h"
    2928#include "JSCast.h"
    3029#include "VM.h"
    3130#include "Watchpoint.h"
    3231#include "WriteBarrier.h"
     32#include <wtf/Nonmovable.h>
    3333
    3434namespace JSC {
    3535
    36 // Allocate one of these if you'd like to infer a constant value. Writes to the value should use
    37 // notifyWrite(). So long as exactly one value had ever been written and invalidate() has never been
    38 // called, and you register a watchpoint, you can rely on the inferredValue() being the one true
    39 // value.
    40 //
    41 // Commonly used for inferring singletons - in that case each allocation does notifyWrite(). But you
    42 // can use it for other things as well.
    43 
    44 class InferredValue final : public JSCell {
     36template<typename JSCellType>
     37class InferredValue {
     38    WTF_MAKE_NONCOPYABLE(InferredValue);
     39    WTF_MAKE_NONMOVABLE(InferredValue);
    4540public:
    46     typedef JSCell Base;
    47    
    48     template<typename CellType, SubspaceAccess mode>
    49     static IsoSubspace* subspaceFor(VM& vm)
    50     {
    51         return vm.inferredValueSpace<mode>();
    52     }
    53 
    54     static InferredValue* create(VM&);
    55    
    56     static const bool needsDestruction = true;
    57     static void destroy(JSCell*);
    58    
    59     static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
    60    
    61     static void visitChildren(JSCell*, SlotVisitor&);
    62    
    63     DECLARE_INFO;
    64    
    6541    // For the purpose of deciding whether or not to watch this variable, you only need
    6642    // to inspect inferredValue(). If this returns something other than the empty
     
    7450    //        either notice that it's invalidated and not install the watchpoint, or
    7551    //        you will have been notified that the watchpoint was fired.
    76     JSValue inferredValue() { return m_value.get(); }
    77 
    78     // Forwards some WatchpointSet methods.
    79     WatchpointState state() const { return m_set.state(); }
    80     bool isStillValid() const { return m_set.isStillValid(); }
    81     bool hasBeenInvalidated() const { return m_set.hasBeenInvalidated(); }
    82     void add(Watchpoint* watchpoint) { m_set.add(watchpoint); }
    83    
    84     void notifyWrite(VM& vm, JSValue value, const FireDetail& detail)
    85     {
    86         if (LIKELY(m_set.stateOnJSThread() == IsInvalidated))
    87             return;
    88         notifyWriteSlow(vm, value, detail);
    89     }
    90    
    91     void notifyWrite(VM& vm, JSValue value, const char* reason)
    92     {
    93         if (LIKELY(m_set.stateOnJSThread() == IsInvalidated))
    94             return;
    95         notifyWriteSlow(vm, value, reason);
    96     }
     52    JSCellType* inferredValue()
     53    {
     54        uintptr_t data = m_data;
     55        if (isFat(data))
     56            return fat(data)->inferredValue();
     57        return bitwise_cast<JSCellType*>(data & ValueMask);
     58    }
     59
     60    explicit InferredValue()
     61        : m_data(encodeState(ClearWatchpoint))
     62    {
     63        ASSERT(inferredValue() == nullptr);
     64    }
     65
     66    ~InferredValue()
     67    {
     68        if (isThin())
     69            return;
     70        freeFat();
     71    }
     72
     73    // Fast way of getting the state, which only works from the main thread.
     74    WatchpointState stateOnJSThread() const
     75    {
     76        uintptr_t data = m_data;
     77        if (isFat(data))
     78            return fat(data)->stateOnJSThread();
     79        return decodeState(data);
     80    }
     81
     82    // It is safe to call this from another thread. It may return a prior state,
     83    // but that should be fine since you should only perform actions based on the
     84    // state if you also add a watchpoint.
     85    WatchpointState state() const
     86    {
     87        WTF::loadLoadFence();
     88        uintptr_t data = m_data;
     89        WTF::loadLoadFence();
     90        if (isFat(data))
     91            return fat(data)->state();
     92        return decodeState(data);
     93    }
     94
     95    // It is safe to call this from another thread. It may return false
     96    // even if the set actually had been invalidated, but that ought to happen
     97    // only in the case of races, and should be rare.
     98    bool hasBeenInvalidated() const
     99    {
     100        return state() == IsInvalidated;
     101    }
     102   
     103    // Like hasBeenInvalidated(), may be called from another thread.
     104    bool isStillValid() const
     105    {
     106        return !hasBeenInvalidated();
     107    }
     108   
     109    void add(Watchpoint*);
    97110   
    98111    void invalidate(VM& vm, const FireDetail& detail)
    99112    {
    100         m_value.clear();
    101         m_set.invalidate(vm, detail);
    102     }
    103    
    104     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
     113        if (isFat())
     114            fat()->invalidate(vm, detail);
     115        else
     116            m_data = encodeState(IsInvalidated);
     117    }
     118   
     119    bool isBeingWatched() const
     120    {
     121        if (isFat())
     122            return fat()->isBeingWatched();
     123        return false;
     124    }
     125
     126    void notifyWrite(VM& vm, JSCell* owner, JSCellType* value, const FireDetail& detail)
     127    {
     128        if (LIKELY(stateOnJSThread() == IsInvalidated))
     129            return;
     130        notifyWriteSlow(vm, owner, value, detail);
     131    }
     132   
     133    void notifyWrite(VM& vm, JSCell* owner, JSCellType* value, const char* reason)
     134    {
     135        if (LIKELY(stateOnJSThread() == IsInvalidated))
     136            return;
     137        notifyWriteSlow(vm, owner, value, reason);
     138    }
    105139   
    106140    void finalizeUnconditionally(VM&);
    107    
     141
    108142private:
    109     InferredValue(VM&);
    110     ~InferredValue();
    111    
    112     JS_EXPORT_PRIVATE void notifyWriteSlow(VM&, JSValue, const FireDetail&);
    113     JS_EXPORT_PRIVATE void notifyWriteSlow(VM&, JSValue, const char* reason);
    114    
    115     InlineWatchpointSet m_set;
    116     WriteBarrier<Unknown> m_value;
     143    class InferredValueWatchpointSet final : public WatchpointSet {
     144    public:
     145        InferredValueWatchpointSet(WatchpointState state, JSCellType* value)
     146            : WatchpointSet(state)
     147            , m_value(value)
     148        {
     149        }
     150
     151        JSCellType* inferredValue() const { return m_value; }
     152
     153        void invalidate(VM& vm, const FireDetail& detail)
     154        {
     155            m_value = nullptr;
     156            WatchpointSet::invalidate(vm, detail);
     157        }
     158
     159        void notifyWriteSlow(VM&, JSCell* owner, JSCellType*, const FireDetail&);
     160
     161    private:
     162        JSCellType* m_value;
     163    };
     164
     165    static constexpr uintptr_t IsThinFlag        = 1;
     166    static constexpr uintptr_t StateMask         = 6;
     167    static constexpr uintptr_t StateShift        = 1;
     168    static constexpr uintptr_t ValueMask         = ~static_cast<uintptr_t>(IsThinFlag | StateMask);
     169   
     170    static bool isThin(uintptr_t data) { return data & IsThinFlag; }
     171    static bool isFat(uintptr_t data) { return !isThin(data); }
     172   
     173    static WatchpointState decodeState(uintptr_t data)
     174    {
     175        ASSERT(isThin(data));
     176        return static_cast<WatchpointState>((data & StateMask) >> StateShift);
     177    }
     178   
     179    static uintptr_t encodeState(WatchpointState state)
     180    {
     181        return (static_cast<uintptr_t>(state) << StateShift) | IsThinFlag;
     182    }
     183   
     184    bool isThin() const { return isThin(m_data); }
     185    bool isFat() const { return isFat(m_data); };
     186   
     187    static InferredValueWatchpointSet* fat(uintptr_t data)
     188    {
     189        return bitwise_cast<InferredValueWatchpointSet*>(data);
     190    }
     191   
     192    InferredValueWatchpointSet* fat()
     193    {
     194        ASSERT(isFat());
     195        return fat(m_data);
     196    }
     197   
     198    const InferredValueWatchpointSet* fat() const
     199    {
     200        ASSERT(isFat());
     201        return fat(m_data);
     202    }
     203   
     204    InferredValueWatchpointSet* inflate()
     205    {
     206        if (LIKELY(isFat()))
     207            return fat();
     208        return inflateSlow();
     209    }
     210
     211    InferredValueWatchpointSet* inflateSlow();
     212    void freeFat();
     213
     214    void notifyWriteSlow(VM&, JSCell* owner, JSCellType*, const FireDetail&);
     215    void notifyWriteSlow(VM&, JSCell* owner, JSCellType*, const char* reason);
     216   
     217    uintptr_t m_data;
    117218};
    118219
    119 // FIXME: We could have an InlineInferredValue, which only allocates the InferredValue object when
    120 // a notifyWrite() transitions us towards watching, and then clears the reference (allowing the object
    121 // to die) when we get invalidated.
     220template<typename JSCellType>
     221void InferredValue<JSCellType>::InferredValueWatchpointSet::notifyWriteSlow(VM& vm, JSCell* owner, JSCellType* value, const FireDetail& detail)
     222{
     223    switch (state()) {
     224    case ClearWatchpoint:
     225        m_value = value;
     226        vm.heap.writeBarrier(owner, value);
     227        startWatching();
     228        return;
     229
     230    case IsWatched:
     231        ASSERT(!!m_value);
     232        if (m_value == value)
     233            return;
     234        invalidate(vm, detail);
     235        return;
     236
     237    case IsInvalidated:
     238        ASSERT_NOT_REACHED();
     239        return;
     240    }
     241
     242    ASSERT_NOT_REACHED();
     243}
     244
     245template<typename JSCellType>
     246void InferredValue<JSCellType>::notifyWriteSlow(VM& vm, JSCell* owner, JSCellType* value, const FireDetail& detail)
     247{
     248    uintptr_t data = m_data;
     249    if (isFat(data)) {
     250        fat(data)->notifyWriteSlow(vm, owner, value, detail);
     251        return;
     252    }
     253
     254    switch (state()) {
     255    case ClearWatchpoint:
     256        ASSERT(decodeState(m_data) != IsInvalidated);
     257        m_data = (bitwise_cast<uintptr_t>(value) & ValueMask) | encodeState(IsWatched);
     258        vm.heap.writeBarrier(owner, value);
     259        return;
     260
     261    case IsWatched:
     262        ASSERT(!!inferredValue());
     263        if (inferredValue() == value)
     264            return;
     265        invalidate(vm, detail);
     266        return;
     267
     268    case IsInvalidated:
     269        ASSERT_NOT_REACHED();
     270        return;
     271    }
     272
     273    ASSERT_NOT_REACHED();
     274}
     275
     276template<typename JSCellType>
     277void InferredValue<JSCellType>::notifyWriteSlow(VM& vm, JSCell* owner, JSCellType* value, const char* reason)
     278{
     279    notifyWriteSlow(vm, owner, value, StringFireDetail(reason));
     280}
     281
     282template<typename JSCellType>
     283void InferredValue<JSCellType>::add(Watchpoint* watchpoint)
     284{
     285    inflate()->add(watchpoint);
     286}
     287
     288template<typename JSCellType>
     289auto InferredValue<JSCellType>::inflateSlow() -> InferredValueWatchpointSet*
     290{
     291    ASSERT(isThin());
     292    ASSERT(!isCompilationThread());
     293    uintptr_t data = m_data;
     294    InferredValueWatchpointSet* fat = adoptRef(new InferredValueWatchpointSet(decodeState(m_data), bitwise_cast<JSCellType*>(data & ValueMask))).leakRef();
     295    WTF::storeStoreFence();
     296    m_data = bitwise_cast<uintptr_t>(fat);
     297    return fat;
     298}
     299
     300template<typename JSCellType>
     301void InferredValue<JSCellType>::freeFat()
     302{
     303    ASSERT(isFat());
     304    fat()->deref();
     305}
    122306
    123307} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/InferredValueInlines.h

    r243467 r246073  
    2121 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    2222 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2424 */
    2525
     
    3030namespace JSC {
    3131
    32 void InferredValue::finalizeUnconditionally(VM& vm)
     32template<typename JSCellType>
     33void InferredValue<JSCellType>::finalizeUnconditionally(VM& vm)
    3334{
    34     JSValue value = m_value.get();
    35    
    36     if (value && value.isCell()) {
    37         if (vm.heap.isMarked(value.asCell()))
     35    JSCellType* value = inferredValue();
     36
     37    if (value) {
     38        if (vm.heap.isMarked(value))
    3839            return;
    39        
     40
    4041        invalidate(vm, StringFireDetail("InferredValue clean-up during GC"));
    4142    }
    42    
    43     VM::SpaceAndSet::setFor(*subspace()).remove(this);
    4443}
    4544
    4645} // namespace JSC
    47 
  • trunk/Source/JavaScriptCore/runtime/JSFunctionInlines.h

    r240796 r246073  
    3535    VM& vm, FunctionExecutable* executable, JSScope* scope)
    3636{
    37     ASSERT(executable->singletonFunctionHasBeenInvalidated());
     37    ASSERT(executable->singleton().hasBeenInvalidated());
    3838    return createImpl(vm, executable, scope, selectStructureForNewFuncExp(scope->globalObject(vm), executable));
    3939}
  • trunk/Source/JavaScriptCore/runtime/JSSymbolTableObject.h

    r240796 r246073  
    6767    {
    6868        ASSERT(!m_symbolTable);
    69         if (auto* singletonScope = symbolTable->singletonScope())
    70             singletonScope->notifyWrite(vm, this, "Allocated a scope");
     69        symbolTable->notifyCreation(vm, this, "Allocated a scope");
    7170        m_symbolTable.set(vm, this, symbolTable);
    7271    }
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.cpp

    r241862 r246073  
    9191{
    9292    Base::finishCreation(vm);
    93     if (VM::canUseJIT())
    94         m_singletonScope.set(vm, this, InferredValue::create(vm));
    9593}
    9694
     
    10199
    102100    visitor.append(thisSymbolTable->m_arguments);
    103     visitor.append(thisSymbolTable->m_singletonScope);
    104101   
    105102    if (thisSymbolTable->m_rareData)
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.h

    r245064 r246073  
    346346   
    347347    SymbolTableEntry& copySlow(const SymbolTableEntry&);
    348     JS_EXPORT_PRIVATE void notifyWriteSlow(VM&, JSValue, const FireDetail&);
    349348   
    350349    bool isFat() const
     
    451450    typedef Vector<SymbolTableEntry*> LocalToEntryVec;
    452451
     452    template<typename CellType, SubspaceAccess>
     453    static IsoSubspace* subspaceFor(VM& vm)
     454    {
     455        return &vm.symbolTableSpace;
     456    }
     457
    453458    static SymbolTable* create(VM& vm)
    454459    {
     
    688693    void setRareDataCodeBlock(CodeBlock*);
    689694   
    690     InferredValue* singletonScope() { return m_singletonScope.get(); }
     695    InferredValue<JSScope>& singleton() { return m_singleton; }
     696
     697    void notifyCreation(VM& vm, JSScope* scope, const char* reason)
     698    {
     699        m_singleton.notifyWrite(vm, this, scope, reason);
     700    }
    691701
    692702    static void visitChildren(JSCell*, SlotVisitor&);
    693703
    694704    DECLARE_EXPORT_INFO;
     705
     706    void finalizeUnconditionally(VM&);
    695707
    696708private:
     
    718730
    719731    WriteBarrier<ScopedArgumentsTable> m_arguments;
    720     WriteBarrier<InferredValue> m_singletonScope;
     732    InferredValue<JSScope> m_singleton;
    721733   
    722734    std::unique_ptr<LocalToEntryVec> m_localToEntry;
  • trunk/Source/JavaScriptCore/runtime/SymbolTableInlines.h

    r246072 r246073  
    11/*
    2  * Copyright (C) 2017 Apple Inc. All rights reserved.
     2 * Copyright (C) 2019 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2121 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    2222 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2424 */
    2525
    2626#pragma once
    2727
    28 #include "InferredValue.h"
     28#include "InferredValueInlines.h"
     29#include "SymbolTable.h"
    2930
    3031namespace JSC {
    3132
    32 void InferredValue::finalizeUnconditionally(VM& vm)
     33inline void SymbolTable::finalizeUnconditionally(VM& vm)
    3334{
    34     JSValue value = m_value.get();
    35    
    36     if (value && value.isCell()) {
    37         if (vm.heap.isMarked(value.asCell()))
    38             return;
    39        
    40         invalidate(vm, StringFireDetail("InferredValue clean-up during GC"));
    41     }
    42    
    43     VM::SpaceAndSet::setFor(*subspace()).remove(this);
     35    m_singleton.finalizeUnconditionally(vm);
    4436}
    4537
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r245646 r246073  
    6565#include "IncrementalSweeper.h"
    6666#include "IndirectEvalExecutable.h"
    67 #include "InferredValue.h"
    6867#include "Interpreter.h"
    6968#include "IntlCollatorConstructor.h"
     
    287286    , structureRareDataSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), StructureRareData)
    288287    , structureSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), Structure)
     288    , symbolTableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), SymbolTable)
    289289    , executableToCodeBlockEdgesWithConstraints(executableToCodeBlockEdgeSpace)
    290290    , executableToCodeBlockEdgesWithFinalizers(executableToCodeBlockEdgeSpace)
     
    379379    unlinkedModuleProgramCodeBlockStructure.set(*this, UnlinkedModuleProgramCodeBlock::createStructure(*this, 0, jsNull()));
    380380    propertyTableStructure.set(*this, PropertyTable::createStructure(*this, 0, jsNull()));
    381     if (VM::canUseJIT())
    382         inferredValueStructure.set(*this, InferredValue::createStructure(*this, 0, jsNull()));
    383381    functionRareDataStructure.set(*this, FunctionRareData::createStructure(*this, 0, jsNull()));
    384382    exceptionStructure.set(*this, Exception::createStructure(*this, 0, jsNull()));
     
    12781276    }
    12791277
    1280 DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER_SLOW(inferredValueSpace, destructibleCellHeapCellType.get(), InferredValue)
    12811278DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER_SLOW(evalExecutableSpace, destructibleCellHeapCellType.get(), EvalExecutable)
    12821279DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER_SLOW(moduleProgramExecutableSpace, destructibleCellHeapCellType.get(), ModuleProgramExecutable)
  • trunk/Source/JavaScriptCore/runtime/VM.h

    r245765 r246073  
    381381    IsoSubspace structureRareDataSpace;
    382382    IsoSubspace structureSpace;
     383    IsoSubspace symbolTableSpace;
    383384
    384385#define DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(name) \
     
    452453   
    453454    SpaceAndSet codeBlockSpace;
    454     DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(inferredValueSpace)
    455455
    456456    template<typename Func>
     
    528528    Strong<Structure> unlinkedModuleProgramCodeBlockStructure;
    529529    Strong<Structure> propertyTableStructure;
    530     Strong<Structure> inferredValueStructure;
    531530    Strong<Structure> functionRareDataStructure;
    532531    Strong<Structure> exceptionStructure;
Note: See TracChangeset for help on using the changeset viewer.