Changeset 159798 in webkit


Ignore:
Timestamp:
Nov 26, 2013 6:47:43 PM (10 years ago)
Author:
fpizlo@apple.com
Message:

Restructure global variable constant inference so that it could work for any kind of symbol table variable
https://bugs.webkit.org/show_bug.cgi?id=124760

Reviewed by Oliver Hunt.

This changes the way global variable constant inference works so that it can be reused
for closure variable constant inference. Some of the premises that originally motivated
this patch are somewhat wrong, but it led to some simplifications anyway and I suspect
that we'll be able to fix those premises in the future. The main point of this patch is
to make it easy to reuse global variable constant inference for closure variable
constant inference, and this will be possible provided we can also either (a) infer
one-shot closures (easy) or (b) infer closure variables that are always assigned prior
to first use.

One of the things that this patch is meant to enable is constant inference for closure
variables that may be part of a multi-shot closure. Closure variables may be
instantiated multiple times, like:

function foo() {

var WIDTH = 45;
function bar() {

... use WIDTH ...

}
...

}


Even if foo() is called many times and WIDTH is assigned to multiple times, that
doesn't change the fact that it's a constant. The goal of closure variable constant
inference is to catch any case where a closure variable has been assigned at least once
and its value has never changed. This patch doesn't implement that, but it does change
global variable constant inference to have most of the powers needed to do that. Note
that most likely we will use this functionality only to implement constant inference
for one-shot closures, but the resulting machinery is still simpler than what we had
before.

This involves three changes:

  • The watchpoint object now contains the inferred value. This involves creating a new kind of watchpoint set, the VariableWatchpointSet. We will reuse this object for closure variables.


  • Writing to a variable that is watchpointed still involves these three states that we proceed through monotonically (Uninitialized->Initialized->Invalidated) but now, the Initialized->Invalidated state transition only happens if we change the variable's value, rather than store to the variable. Repeatedly storing the same value won't change the variable's state.


  • On 64-bit systems (the only systems on which we do concurrent JIT), you no longer need fancy fencing to get a consistent view of the watchpoint in the JIT. The state of the VariableWatchpointSet for the purposes of constant folding is entirely encapsulated in the VariableWatchpointSet::m_inferredValue. If that is JSValue() then you cannot fold (either because the set is uninitialized or because it's invalidated - doesn't matter which); on the other hand if the value is anything other than JSValue() then you can fold, and that's the value you fold to. Simple!


This also changes the way that DFG IR deals with variable watchpoints. It's now
oblivious to global variables. You install a watchpoint using VariableWatchpoint and
you notify write using NotifyWrite. Easy!

Note that this will requires some more tweaks because of the fact that op_enter will
store Undefined into every captured variable. Hence it won't even work for one-shot
closures. One-shot closures are easily fixed by introducing another state (so we'll
have Uninitialized->Undefined->Initialized->Invalidated). Multi-shot closures will
require static analysis. One-shot closures are clearly a higher priority.

  • GNUmakefile.list.am:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/Instruction.h:
  • bytecode/VariableWatchpointSet.h: Added.

(JSC::VariableWatchpointSet::VariableWatchpointSet):
(JSC::VariableWatchpointSet::~VariableWatchpointSet):
(JSC::VariableWatchpointSet::inferredValue):
(JSC::VariableWatchpointSet::notifyWrite):
(JSC::VariableWatchpointSet::invalidate):
(JSC::VariableWatchpointSet::finalizeUnconditionally):
(JSC::VariableWatchpointSet::addressOfInferredValue):

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

(JSC::DFG::::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

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

  • dfg/DFGCSEPhase.cpp:

(JSC::DFG::CSEPhase::performNodeCSE):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasRegisterPointer):
(JSC::DFG::Node::hasVariableWatchpointSet):
(JSC::DFG::Node::variableWatchpointSet):

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileArithMod):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGWatchpointCollectionPhase.cpp:

(JSC::DFG::WatchpointCollectionPhase::handle):

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileNotifyWrite):

  • jit/JIT.h:
  • jit/JITOperations.h:
  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emitNotifyWrite):
(JSC::JIT::emitPutGlobalVar):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emitNotifyWrite):
(JSC::JIT::emitPutGlobalVar):

  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::addGlobalVar):
(JSC::JSGlobalObject::addFunction):

  • runtime/JSGlobalObject.h:
  • runtime/JSScope.h:

(JSC::ResolveOp::ResolveOp):

  • runtime/JSSymbolTableObject.h:

(JSC::symbolTablePut):
(JSC::symbolTablePutWithAttributes):

  • runtime/SymbolTable.cpp:

(JSC::SymbolTableEntry::inferredValue):
(JSC::SymbolTableEntry::prepareToWatch):
(JSC::SymbolTableEntry::addWatchpoint):
(JSC::SymbolTableEntry::notifyWriteSlow):
(JSC::SymbolTable::visitChildren):
(JSC::SymbolTable::WatchpointCleanup::WatchpointCleanup):
(JSC::SymbolTable::WatchpointCleanup::~WatchpointCleanup):
(JSC::SymbolTable::WatchpointCleanup::finalizeUnconditionally):

  • runtime/SymbolTable.h:

(JSC::SymbolTableEntry::watchpointSet):
(JSC::SymbolTableEntry::notifyWrite):

Location:
trunk/Source/JavaScriptCore
Files:
1 added
37 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r159795 r159798  
     12013-11-26  Filip Pizlo  <fpizlo@apple.com>
     2
     3        Restructure global variable constant inference so that it could work for any kind of symbol table variable
     4        https://bugs.webkit.org/show_bug.cgi?id=124760
     5
     6        Reviewed by Oliver Hunt.
     7       
     8        This changes the way global variable constant inference works so that it can be reused
     9        for closure variable constant inference. Some of the premises that originally motivated
     10        this patch are somewhat wrong, but it led to some simplifications anyway and I suspect
     11        that we'll be able to fix those premises in the future. The main point of this patch is
     12        to make it easy to reuse global variable constant inference for closure variable
     13        constant inference, and this will be possible provided we can also either (a) infer
     14        one-shot closures (easy) or (b) infer closure variables that are always assigned prior
     15        to first use.
     16       
     17        One of the things that this patch is meant to enable is constant inference for closure
     18        variables that may be part of a multi-shot closure. Closure variables may be
     19        instantiated multiple times, like:
     20       
     21            function foo() {
     22                var WIDTH = 45;
     23                function bar() {
     24                    ... use WIDTH ...
     25                }
     26                ...
     27            }
     28       
     29        Even if foo() is called many times and WIDTH is assigned to multiple times, that
     30        doesn't change the fact that it's a constant. The goal of closure variable constant
     31        inference is to catch any case where a closure variable has been assigned at least once
     32        and its value has never changed. This patch doesn't implement that, but it does change
     33        global variable constant inference to have most of the powers needed to do that. Note
     34        that most likely we will use this functionality only to implement constant inference
     35        for one-shot closures, but the resulting machinery is still simpler than what we had
     36        before.
     37       
     38        This involves three changes:
     39       
     40            - The watchpoint object now contains the inferred value. This involves creating a
     41              new kind of watchpoint set, the VariableWatchpointSet. We will reuse this object
     42              for closure variables.
     43       
     44            - Writing to a variable that is watchpointed still involves these three states that
     45              we proceed through monotonically (Uninitialized->Initialized->Invalidated) but
     46              now, the Initialized->Invalidated state transition only happens if we change the
     47              variable's value, rather than store to the variable. Repeatedly storing the same
     48              value won't change the variable's state.
     49       
     50            - On 64-bit systems (the only systems on which we do concurrent JIT), you no longer
     51              need fancy fencing to get a consistent view of the watchpoint in the JIT. The
     52              state of the VariableWatchpointSet for the purposes of constant folding is
     53              entirely encapsulated in the VariableWatchpointSet::m_inferredValue. If that is
     54              JSValue() then you cannot fold (either because the set is uninitialized or
     55              because it's invalidated - doesn't matter which); on the other hand if the value
     56              is anything other than JSValue() then you can fold, and that's the value you fold
     57              to. Simple!
     58       
     59        This also changes the way that DFG IR deals with variable watchpoints. It's now
     60        oblivious to global variables. You install a watchpoint using VariableWatchpoint and
     61        you notify write using NotifyWrite. Easy!
     62       
     63        Note that this will requires some more tweaks because of the fact that op_enter will
     64        store Undefined into every captured variable. Hence it won't even work for one-shot
     65        closures. One-shot closures are easily fixed by introducing another state (so we'll
     66        have Uninitialized->Undefined->Initialized->Invalidated). Multi-shot closures will
     67        require static analysis. One-shot closures are clearly a higher priority.
     68
     69        * GNUmakefile.list.am:
     70        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
     71        * JavaScriptCore.xcodeproj/project.pbxproj:
     72        * bytecode/Instruction.h:
     73        * bytecode/VariableWatchpointSet.h: Added.
     74        (JSC::VariableWatchpointSet::VariableWatchpointSet):
     75        (JSC::VariableWatchpointSet::~VariableWatchpointSet):
     76        (JSC::VariableWatchpointSet::inferredValue):
     77        (JSC::VariableWatchpointSet::notifyWrite):
     78        (JSC::VariableWatchpointSet::invalidate):
     79        (JSC::VariableWatchpointSet::finalizeUnconditionally):
     80        (JSC::VariableWatchpointSet::addressOfInferredValue):
     81        * bytecode/Watchpoint.h:
     82        * dfg/DFGAbstractInterpreterInlines.h:
     83        (JSC::DFG::::executeEffects):
     84        * dfg/DFGByteCodeParser.cpp:
     85        (JSC::DFG::ByteCodeParser::parseBlock):
     86        * dfg/DFGCSEPhase.cpp:
     87        (JSC::DFG::CSEPhase::performNodeCSE):
     88        * dfg/DFGClobberize.h:
     89        (JSC::DFG::clobberize):
     90        * dfg/DFGFixupPhase.cpp:
     91        (JSC::DFG::FixupPhase::fixupNode):
     92        * dfg/DFGNode.h:
     93        (JSC::DFG::Node::hasRegisterPointer):
     94        (JSC::DFG::Node::hasVariableWatchpointSet):
     95        (JSC::DFG::Node::variableWatchpointSet):
     96        * dfg/DFGNodeType.h:
     97        * dfg/DFGOperations.cpp:
     98        * dfg/DFGOperations.h:
     99        * dfg/DFGPredictionPropagationPhase.cpp:
     100        (JSC::DFG::PredictionPropagationPhase::propagate):
     101        * dfg/DFGSafeToExecute.h:
     102        (JSC::DFG::safeToExecute):
     103        * dfg/DFGSpeculativeJIT.cpp:
     104        (JSC::DFG::SpeculativeJIT::compileArithMod):
     105        * dfg/DFGSpeculativeJIT.h:
     106        (JSC::DFG::SpeculativeJIT::callOperation):
     107        * dfg/DFGSpeculativeJIT32_64.cpp:
     108        (JSC::DFG::SpeculativeJIT::compile):
     109        * dfg/DFGSpeculativeJIT64.cpp:
     110        (JSC::DFG::SpeculativeJIT::compile):
     111        * dfg/DFGWatchpointCollectionPhase.cpp:
     112        (JSC::DFG::WatchpointCollectionPhase::handle):
     113        * ftl/FTLCapabilities.cpp:
     114        (JSC::FTL::canCompile):
     115        * ftl/FTLLowerDFGToLLVM.cpp:
     116        (JSC::FTL::LowerDFGToLLVM::compileNode):
     117        (JSC::FTL::LowerDFGToLLVM::compileNotifyWrite):
     118        * jit/JIT.h:
     119        * jit/JITOperations.h:
     120        * jit/JITPropertyAccess.cpp:
     121        (JSC::JIT::emitNotifyWrite):
     122        (JSC::JIT::emitPutGlobalVar):
     123        * jit/JITPropertyAccess32_64.cpp:
     124        (JSC::JIT::emitNotifyWrite):
     125        (JSC::JIT::emitPutGlobalVar):
     126        * llint/LowLevelInterpreter32_64.asm:
     127        * llint/LowLevelInterpreter64.asm:
     128        * runtime/JSGlobalObject.cpp:
     129        (JSC::JSGlobalObject::addGlobalVar):
     130        (JSC::JSGlobalObject::addFunction):
     131        * runtime/JSGlobalObject.h:
     132        * runtime/JSScope.h:
     133        (JSC::ResolveOp::ResolveOp):
     134        * runtime/JSSymbolTableObject.h:
     135        (JSC::symbolTablePut):
     136        (JSC::symbolTablePutWithAttributes):
     137        * runtime/SymbolTable.cpp:
     138        (JSC::SymbolTableEntry::inferredValue):
     139        (JSC::SymbolTableEntry::prepareToWatch):
     140        (JSC::SymbolTableEntry::addWatchpoint):
     141        (JSC::SymbolTableEntry::notifyWriteSlow):
     142        (JSC::SymbolTable::visitChildren):
     143        (JSC::SymbolTable::WatchpointCleanup::WatchpointCleanup):
     144        (JSC::SymbolTable::WatchpointCleanup::~WatchpointCleanup):
     145        (JSC::SymbolTable::WatchpointCleanup::finalizeUnconditionally):
     146        * runtime/SymbolTable.h:
     147        (JSC::SymbolTableEntry::watchpointSet):
     148        (JSC::SymbolTableEntry::notifyWrite):
     149
    11502013-11-24  Filip Pizlo  <fpizlo@apple.com>
    2151
  • trunk/Source/JavaScriptCore/GNUmakefile.list.am

    r159642 r159798  
    182182        Source/JavaScriptCore/bytecode/ValueRecovery.cpp \
    183183        Source/JavaScriptCore/bytecode/ValueRecovery.h \
     184        Source/JavaScriptCore/bytecode/VariableWatchpointSet.h \
    184185        Source/JavaScriptCore/bytecode/VirtualRegister.h \
    185186        Source/JavaScriptCore/bytecode/Watchpoint.cpp \
  • trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj

    r159642 r159798  
    796796    <ClInclude Include="..\bytecode\ValueProfile.h" />
    797797    <ClInclude Include="..\bytecode\ValueRecovery.h" />
     798    <ClInclude Include="..\bytecode\VariableWatchpointSet.h" />
    798799    <ClInclude Include="..\bytecode\VirtualRegister.h" />
    799800    <ClInclude Include="..\bytecode\Watchpoint.h" />
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r159642 r159798  
    301301                0F8F94441667635400D61971 /* JITCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F94431667635200D61971 /* JITCode.cpp */; };
    302302                0F8F9446166764F100D61971 /* CodeOrigin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F9445166764EE00D61971 /* CodeOrigin.cpp */; };
     303                0F9181C718415CA50057B669 /* VariableWatchpointSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F9181C618415CA50057B669 /* VariableWatchpointSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
    303304                0F919D0C157EE09F004A4E7D /* JSSymbolTableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */; };
    304305                0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    15941595                0F8F94431667635200D61971 /* JITCode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITCode.cpp; sourceTree = "<group>"; };
    15951596                0F8F9445166764EE00D61971 /* CodeOrigin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeOrigin.cpp; sourceTree = "<group>"; };
     1597                0F9181C618415CA50057B669 /* VariableWatchpointSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VariableWatchpointSet.h; sourceTree = "<group>"; };
    15961598                0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSymbolTableObject.cpp; sourceTree = "<group>"; };
    15971599                0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSymbolTableObject.h; sourceTree = "<group>"; };
     
    41334135                                0F24E55717F74EDB00ABB217 /* ValueRecovery.cpp */,
    41344136                                0F426A451460CBAB00131F8F /* ValueRecovery.h */,
     4137                                0F9181C618415CA50057B669 /* VariableWatchpointSet.h */,
    41354138                                0F426A461460CBAB00131F8F /* VirtualRegister.h */,
    41364139                                0F919D2215853CDE004A4E7D /* Watchpoint.cpp */,
     
    43764379                                0FD8A32817D51F5700CA2C40 /* DFGTierUpCheckInjectionPhase.h in Headers */,
    43774380                                0FD8A32A17D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.h in Headers */,
     4381                                0F9181C718415CA50057B669 /* VariableWatchpointSet.h in Headers */,
    43784382                                0FD8A32C17D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.h in Headers */,
    43794383                                0F63943F15C75F19006A597C /* DFGTypeCheckHoistingPhase.h in Headers */,
  • trunk/Source/JavaScriptCore/bytecode/Instruction.h

    r159462 r159798  
    4444class ArrayProfile;
    4545class ObjectAllocationProfile;
     46class VariableWatchpointSet;
    4647struct LLIntCallLinkInfo;
    4748struct ValueProfile;
     
    116117        ArrayAllocationProfile* arrayAllocationProfile;
    117118        ObjectAllocationProfile* objectAllocationProfile;
    118         WatchpointSet* watchpointSet;
     119        VariableWatchpointSet* watchpointSet;
    119120        void* pointer;
    120121        bool* predicatePointer;
  • trunk/Source/JavaScriptCore/bytecode/Watchpoint.h

    r159545 r159798  
    109109    }
    110110   
    111     void notifyWrite()
    112     {
    113         if (state() == ClearWatchpoint)
    114             startWatching();
    115         else
    116             fireAll();
    117     }
    118    
    119111    int8_t* addressOfState() { return &m_state; }
    120112    int8_t* addressOfSetIsNotEmpty() { return &m_setIsNotEmpty; }
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r159545 r159798  
    15061506        break;
    15071507       
    1508     case GlobalVarWatchpoint:
     1508    case VariableWatchpoint:
    15091509    case VarInjectionWatchpoint:
    15101510        node->setCanExit(true);
     
    15121512           
    15131513    case PutGlobalVar:
    1514     case NotifyPutGlobalVar:
     1514    case NotifyWrite:
    15151515        break;
    15161516           
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r159545 r159798  
    30953095                addToGraph(Phantom, get(VirtualRegister(scope)));
    30963096                SymbolTableEntry entry = globalObject->symbolTable()->get(uid);
    3097                 if (!entry.couldBeWatched() || !m_graph.watchpoints().isStillValid(entry.watchpointSet())) {
     3097                VariableWatchpointSet* watchpointSet = entry.watchpointSet();
     3098                JSValue specificValue =
     3099                    watchpointSet ? watchpointSet->inferredValue() : JSValue();
     3100                if (!specificValue) {
    30983101                    set(VirtualRegister(dst), addToGraph(GetGlobalVar, OpInfo(operand), OpInfo(prediction)));
    30993102                    break;
    31003103                }
    31013104
    3102                 addToGraph(GlobalVarWatchpoint, OpInfo(operand), OpInfo(identifierNumber));
    3103                 JSValue specificValue = globalObject->registerAt(entry.getIndex()).get();
     3105                addToGraph(VariableWatchpoint, OpInfo(watchpointSet));
    31043106                if (specificValue.isCell())
    31053107                    set(VirtualRegister(dst), cellConstant(specificValue.asCell()));
     
    31293131
    31303132            Structure* structure = 0;
    3131             WatchpointSet* watchpoints = 0;
     3133            VariableWatchpointSet* watchpoints = 0;
    31323134            uintptr_t operand;
    31333135            {
     
    31613163                SymbolTableEntry entry = globalObject->symbolTable()->get(uid);
    31623164                ASSERT(watchpoints == entry.watchpointSet());
    3163                 addToGraph(PutGlobalVar, OpInfo(operand), get(VirtualRegister(value)));
     3165                Node* valueNode = get(VirtualRegister(value));
     3166                addToGraph(PutGlobalVar, OpInfo(operand), valueNode);
    31643167                if (watchpoints->state() != IsInvalidated)
    3165                     addToGraph(NotifyPutGlobalVar, OpInfo(operand), OpInfo(identifierNumber));
     3168                    addToGraph(NotifyWrite, OpInfo(watchpoints), valueNode);
    31663169                // Keep scope alive until after put.
    31673170                addToGraph(Phantom, get(VirtualRegister(scope)));
  • trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp

    r158384 r159798  
    261261    }
    262262   
    263     bool globalVarWatchpointElimination(WriteBarrier<Unknown>* registerPointer)
    264     {
    265         for (unsigned i = m_indexInBlock; i--;) {
    266             Node* node = m_currentBlock->at(i);
    267             switch (node->op()) {
    268             case GlobalVarWatchpoint:
    269                 if (node->registerPointer() == registerPointer)
    270                     return true;
    271                 break;
    272             case PutGlobalVar:
    273                 if (node->registerPointer() == registerPointer)
    274                     return false;
    275                 break;
    276             default:
    277                 break;
    278             }
    279             if (m_graph.clobbersWorld(node))
    280                 break;
    281         }
    282         return false;
    283     }
    284 
    285263    bool varInjectionWatchpointElimination()
    286264    {
     
    12301208        }
    12311209
    1232         case GlobalVarWatchpoint:
    1233             if (cseMode == StoreElimination)
    1234                 break;
    1235             if (globalVarWatchpointElimination(node->registerPointer()))
    1236                 eliminate();
    1237             break;
    1238            
    12391210        case VarInjectionWatchpoint:
    12401211            if (cseMode == StoreElimination)
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r159545 r159798  
    144144        return;
    145145       
    146     case NotifyPutGlobalVar:
     146    case VariableWatchpoint:
     147        read(Watchpoint_fire);
     148        return;
     149       
     150    case NotifyWrite:
    147151        write(Watchpoint_fire);
     152        write(SideState);
    148153        return;
    149154
     
    521526       
    522527    case GetGlobalVar:
    523     case GlobalVarWatchpoint:
    524528        read(AbstractHeap(Absolute, node->registerPointer()));
    525529        return;
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r159783 r159798  
    919919        case GetGlobalVar:
    920920        case PutGlobalVar:
    921         case NotifyPutGlobalVar:
    922         case GlobalVarWatchpoint:
     921        case NotifyWrite:
     922        case VariableWatchpoint:
    923923        case VarInjectionWatchpoint:
    924924        case AllocationProfileWatchpoint:
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r159545 r159798  
    749749    }
    750750   
    751     bool hasIdentifierNumberForCheck()
    752     {
    753         return op() == GlobalVarWatchpoint || op() == NotifyPutGlobalVar;
    754     }
    755    
    756     unsigned identifierNumberForCheck()
    757     {
    758         ASSERT(hasIdentifierNumberForCheck());
    759         return m_opInfo2;
    760     }
    761    
    762751    bool hasRegisterPointer()
    763752    {
    764         return op() == GetGlobalVar || op() == PutGlobalVar || op() == GlobalVarWatchpoint || op() == NotifyPutGlobalVar;
     753        return op() == GetGlobalVar || op() == PutGlobalVar;
    765754    }
    766755   
     
    974963        return jsCast<ExecutableBase*>(reinterpret_cast<JSCell*>(m_opInfo));
    975964    }
     965   
     966    bool hasVariableWatchpointSet()
     967    {
     968        return op() == NotifyWrite || op() == VariableWatchpoint;
     969    }
     970   
     971    VariableWatchpointSet* variableWatchpointSet()
     972    {
     973        return reinterpret_cast<VariableWatchpointSet*>(m_opInfo);
     974    }
    976975
    977976    bool hasStructureTransitionData()
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r159545 r159798  
    185185    macro(GetGlobalVar, NodeResultJS) \
    186186    macro(PutGlobalVar, NodeMustGenerate) \
    187     macro(NotifyPutGlobalVar, NodeMustGenerate) \
    188     macro(GlobalVarWatchpoint, NodeMustGenerate) \
     187    macro(NotifyWrite, NodeMustGenerate) \
     188    macro(VariableWatchpoint, NodeMustGenerate) \
    189189    macro(VarInjectionWatchpoint, NodeMustGenerate) \
    190190    macro(CheckFunction, NodeMustGenerate) \
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r159545 r159798  
    999999}
    10001000
    1001 void JIT_OPERATION operationNotifyWrite(ExecState* exec, WatchpointSet* set)
    1002 {
    1003     VM& vm = exec->vm();
    1004     NativeCallFrameTracer tracer(&vm, exec);
    1005 
    1006     set->notifyWrite();
     1001void JIT_OPERATION operationInvalidate(ExecState* exec, VariableWatchpointSet* set)
     1002{
     1003    VM& vm = exec->vm();
     1004    NativeCallFrameTracer tracer(&vm, exec);
     1005
     1006    set->invalidate();
    10071007}
    10081008
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r159545 r159798  
    126126char* JIT_OPERATION operationFindSwitchImmTargetForDouble(ExecState*, EncodedJSValue, size_t tableIndex);
    127127char* JIT_OPERATION operationSwitchString(ExecState*, size_t tableIndex, JSString*);
    128 void JIT_OPERATION operationNotifyWrite(ExecState*, WatchpointSet*);
     128void JIT_OPERATION operationInvalidate(ExecState*, VariableWatchpointSet*);
    129129
    130130#if ENABLE(FTL_JIT)
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r159545 r159798  
    575575        case TearOffArguments:
    576576        case CheckArgumentsNotCreated:
    577         case GlobalVarWatchpoint:
     577        case VariableWatchpoint:
    578578        case VarInjectionWatchpoint:
    579579        case AllocationProfileWatchpoint:
     
    583583        case Unreachable:
    584584        case LoopHint:
    585         case NotifyPutGlobalVar:
     585        case NotifyWrite:
    586586            break;
    587587           
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r159545 r159798  
    173173    case GetGlobalVar:
    174174    case PutGlobalVar:
    175     case GlobalVarWatchpoint:
     175    case VariableWatchpoint:
    176176    case VarInjectionWatchpoint:
    177177    case CheckFunction:
     
    243243    case Int52ToValue:
    244244    case InvalidationPoint:
    245     case NotifyPutGlobalVar:
     245    case NotifyWrite:
    246246        return true;
    247247       
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r159736 r159798  
    56015601}
    56025602
    5603 void SpeculativeJIT::compileNotifyPutGlobalVar(Node* node)
    5604 {
    5605     WatchpointSet* set = m_jit.globalObjectFor(node->codeOrigin)->symbolTable()->get(
    5606         m_jit.graph().identifiers()[node->identifierNumberForCheck()]).watchpointSet();
    5607    
    5608     GPRTemporary temp(this);
    5609     GPRReg tempGPR = temp.gpr();
    5610    
    5611     m_jit.load8(set->addressOfState(), tempGPR);
    5612    
    5613     JITCompiler::JumpList ready;
    5614    
    5615     ready.append(m_jit.branch32(JITCompiler::Equal, tempGPR, TrustedImm32(IsInvalidated)));
    5616    
    5617     m_jit.memoryFence();
    5618 
    5619     if (set->state() == ClearWatchpoint) {
    5620         JITCompiler::Jump isWatched =
    5621             m_jit.branch32(JITCompiler::NotEqual, tempGPR, TrustedImm32(ClearWatchpoint));
    5622        
    5623         m_jit.store8(TrustedImm32(IsWatched), set->addressOfState());
    5624         ready.append(m_jit.jump());
    5625        
    5626         isWatched.link(&m_jit);
    5627     }
    5628    
    5629     JITCompiler::Jump slowCase = m_jit.branchTest8(
    5630         JITCompiler::NonZero, JITCompiler::AbsoluteAddress(set->addressOfSetIsNotEmpty()));
    5631     m_jit.store8(TrustedImm32(IsInvalidated), set->addressOfState());
    5632 
    5633     ready.link(&m_jit);
    5634    
    5635     addSlowPathGenerator(
    5636         slowPathCall(slowCase, this, operationNotifyWrite, NoResult, set));
    5637    
    5638     noResult(node);
    5639 }
    5640 
    56415603void SpeculativeJIT::addBranch(const MacroAssembler::JumpList& jump, BasicBlock* destination)
    56425604{
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r159545 r159798  
    10851085    }
    10861086
    1087     JITCompiler::Call callOperation(V_JITOperation_EW operation, WatchpointSet* watchpointSet)
     1087    JITCompiler::Call callOperation(V_JITOperation_EVws operation, VariableWatchpointSet* watchpointSet)
    10881088    {
    10891089        m_jit.setupArgumentsWithExecState(TrustedImmPtr(watchpointSet));
     
    20452045    void compileNewFunctionExpression(Node*);
    20462046    bool compileRegExpExec(Node*);
    2047    
    2048     void compileNotifyPutGlobalVar(Node*);
    20492047   
    20502048    // size can be an immediate or a register, and must be in bytes. If size is a register,
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r159713 r159798  
    40724072    }
    40734073
    4074     case GlobalVarWatchpoint: {
    4075 #if DFG_ENABLE(JIT_ASSERT)
    4076         GPRTemporary scratch(this);
    4077         GPRReg scratchGPR = scratch.gpr();
    4078         m_jit.load32(node->registerPointer()->tagPointer(), scratchGPR);
    4079         JITCompiler::Jump notOK = m_jit.branch32(
    4080             JITCompiler::NotEqual, scratchGPR,
    4081             TrustedImm32(node->registerPointer()->get().tag()));
    4082         m_jit.load32(node->registerPointer()->payloadPointer(), scratchGPR);
    4083         JITCompiler::Jump ok = m_jit.branch32(
    4084             JITCompiler::Equal, scratchGPR,
    4085             TrustedImm32(node->registerPointer()->get().payload()));
    4086         notOK.link(&m_jit);
    4087         m_jit.breakpoint();
    4088         ok.link(&m_jit);
    4089 #endif
    4090        
     4074    case NotifyWrite: {
     4075        VariableWatchpointSet* set = node->variableWatchpointSet();
     4076   
     4077        JSValueOperand value(this, node->child1());
     4078        GPRReg valueTagGPR = value.tagGPR();
     4079        GPRReg valuePayloadGPR = value.payloadGPR();
     4080   
     4081        GPRTemporary temp(this);
     4082        GPRReg tempGPR = temp.gpr();
     4083   
     4084        m_jit.load8(set->addressOfState(), tempGPR);
     4085   
     4086        JITCompiler::JumpList ready;
     4087   
     4088        ready.append(m_jit.branch32(JITCompiler::Equal, tempGPR, TrustedImm32(IsInvalidated)));
     4089   
     4090        if (set->state() == ClearWatchpoint) {
     4091            JITCompiler::Jump isWatched =
     4092                m_jit.branch32(JITCompiler::NotEqual, tempGPR, TrustedImm32(ClearWatchpoint));
     4093       
     4094            m_jit.store32(valueTagGPR, &set->addressOfInferredValue()->u.asBits.tag);
     4095            m_jit.store32(valuePayloadGPR, &set->addressOfInferredValue()->u.asBits.payload);
     4096            m_jit.store8(TrustedImm32(IsWatched), set->addressOfState());
     4097            ready.append(m_jit.jump());
     4098       
     4099            isWatched.link(&m_jit);
     4100        }
     4101
     4102        JITCompiler::Jump definitelyNotEqual = m_jit.branch32(
     4103            JITCompiler::NotEqual,
     4104            JITCompiler::AbsoluteAddress(&set->addressOfInferredValue()->u.asBits.payload),
     4105            valuePayloadGPR);
     4106        ready.append(m_jit.branch32(
     4107            JITCompiler::Equal,
     4108            JITCompiler::AbsoluteAddress(&set->addressOfInferredValue()->u.asBits.tag),
     4109            valueTagGPR));
     4110        definitelyNotEqual.link(&m_jit);
     4111   
     4112        JITCompiler::Jump slowCase = m_jit.branchTest8(
     4113            JITCompiler::NonZero, JITCompiler::AbsoluteAddress(set->addressOfSetIsNotEmpty()));
     4114        m_jit.store8(TrustedImm32(IsInvalidated), set->addressOfState());
     4115        m_jit.store32(
     4116            TrustedImm32(JSValue::EmptyValueTag),
     4117            &set->addressOfInferredValue()->u.asBits.tag);
     4118        m_jit.store32(
     4119            TrustedImm32(0), &set->addressOfInferredValue()->u.asBits.payload);
     4120
     4121        ready.link(&m_jit);
     4122   
     4123        addSlowPathGenerator(
     4124            slowPathCall(slowCase, this, operationInvalidate, NoResult, set));
     4125   
    40914126        noResult(node);
    40924127        break;
    40934128    }
    40944129
    4095     case NotifyPutGlobalVar: {
    4096         compileNotifyPutGlobalVar(node);
    4097         break;
    4098     }
    4099 
    4100     case VarInjectionWatchpoint: {
     4130    case VarInjectionWatchpoint:
     4131    case VariableWatchpoint: {
    41014132        noResult(node);
    41024133        break;
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r159713 r159798  
    43544354    }
    43554355
    4356     case GlobalVarWatchpoint: {
    4357 #if DFG_ENABLE(JIT_ASSERT)
    4358         GPRTemporary scratch(this);
    4359         GPRReg scratchGPR = scratch.gpr();
    4360         m_jit.load64(node->registerPointer(), scratchGPR);
    4361         JITCompiler::Jump ok = m_jit.branch64(
    4362             JITCompiler::Equal, scratchGPR,
    4363             TrustedImm64(JSValue::encode(node->registerPointer()->get())));
    4364         m_jit.breakpoint();
    4365         ok.link(&m_jit);
    4366 #endif
    4367        
     4356    case NotifyWrite: {
     4357        VariableWatchpointSet* set = node->variableWatchpointSet();
     4358   
     4359        JSValueOperand value(this, node->child1());
     4360        GPRReg valueGPR = value.gpr();
     4361   
     4362        GPRTemporary temp(this);
     4363        GPRReg tempGPR = temp.gpr();
     4364   
     4365        m_jit.load8(set->addressOfState(), tempGPR);
     4366   
     4367        JITCompiler::JumpList ready;
     4368   
     4369        ready.append(m_jit.branch32(JITCompiler::Equal, tempGPR, TrustedImm32(IsInvalidated)));
     4370   
     4371        if (set->state() == ClearWatchpoint) {
     4372            JITCompiler::Jump isWatched =
     4373                m_jit.branch32(JITCompiler::NotEqual, tempGPR, TrustedImm32(ClearWatchpoint));
     4374       
     4375            m_jit.store64(valueGPR, set->addressOfInferredValue());
     4376            m_jit.store8(TrustedImm32(IsWatched), set->addressOfState());
     4377            ready.append(m_jit.jump());
     4378       
     4379            isWatched.link(&m_jit);
     4380        }
     4381   
     4382        ready.append(m_jit.branch64(
     4383            JITCompiler::Equal,
     4384            JITCompiler::AbsoluteAddress(set->addressOfInferredValue()), valueGPR));
     4385   
     4386        JITCompiler::Jump slowCase = m_jit.branchTest8(
     4387            JITCompiler::NonZero, JITCompiler::AbsoluteAddress(set->addressOfSetIsNotEmpty()));
     4388        m_jit.store8(TrustedImm32(IsInvalidated), set->addressOfState());
     4389        m_jit.move(TrustedImm64(JSValue::encode(JSValue())), tempGPR);
     4390        m_jit.store64(tempGPR, set->addressOfInferredValue());
     4391
     4392        ready.link(&m_jit);
     4393   
     4394        addSlowPathGenerator(
     4395            slowPathCall(slowCase, this, operationInvalidate, NoResult, set));
     4396   
    43684397        noResult(node);
    43694398        break;
    43704399    }
    4371        
    4372     case NotifyPutGlobalVar: {
    4373         compileNotifyPutGlobalVar(node);
    4374         break;
    4375     }
    4376 
    4377     case VarInjectionWatchpoint: {
     4400
     4401    case VarInjectionWatchpoint:
     4402    case VariableWatchpoint: {
    43784403        noResult(node);
    43794404        break;
  • trunk/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp

    r158304 r159798  
    119119            break;
    120120           
    121         case GlobalVarWatchpoint:
    122             addLazily(
    123                 globalObject()->symbolTable()->get(
    124                     m_graph.identifiers()[m_node->identifierNumberForCheck()]).watchpointSet());
     121        case VariableWatchpoint:
     122            addLazily(m_node->variableWatchpointSet());
    125123            break;
    126124           
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r159545 r159798  
    7070    case GetGlobalVar:
    7171    case PutGlobalVar:
    72     case NotifyPutGlobalVar:
    7372    case ValueAdd:
    7473    case ArithAdd:
     
    9392    case Call:
    9493    case Construct:
    95     case GlobalVarWatchpoint:
    9694    case GetMyScope:
    9795    case SkipScope:
     
    105103    case StringCharCodeAt:
    106104    case AllocatePropertyStorage:
     105    case VariableWatchpoint:
     106    case NotifyWrite:
    107107        // These are OK.
    108108        break;
  • trunk/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h

    r159545 r159798  
    6666    macro(V_JITOperation_EOZD, functionType(voidType, intPtr, intPtr, int32, doubleType)) \
    6767    macro(V_JITOperation_EOZJ, functionType(voidType, intPtr, intPtr, int32, int64)) \
    68     macro(V_JITOperation_EW, functionType(voidType, intPtr, intPtr)) \
     68    macro(V_JITOperation_EVws, functionType(voidType, intPtr, intPtr)) \
    6969    macro(Z_JITOperation_D, functionType(int32, doubleType))
    7070
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp

    r159721 r159798  
    395395            compilePutGlobalVar();
    396396            break;
    397         case NotifyPutGlobalVar:
    398             compileNotifyPutGlobalVar();
    399             break;
    400         case GlobalVarWatchpoint:
    401             compileGlobalVarWatchpoint();
     397        case NotifyWrite:
     398            compileNotifyWrite();
     399            break;
     400        case VariableWatchpoint:
    402401            break;
    403402        case GetMyScope:
     
    21182117    }
    21192118   
    2120     void compileNotifyPutGlobalVar()
    2121     {
    2122         WatchpointSet* set = m_graph.globalObjectFor(m_node->codeOrigin)->symbolTable()->get(
    2123             m_graph.identifiers()[m_node->identifierNumberForCheck()]).watchpointSet();
    2124        
    2125         LBasicBlock isNotInvalidated = FTL_NEW_BLOCK(m_out, ("NotifyPutGlobalVar not invalidated case"));
    2126         LBasicBlock isClear = FTL_NEW_BLOCK(m_out, ("NotifyPutGlobalVar clear case"));
    2127         LBasicBlock isWatched = FTL_NEW_BLOCK(m_out, ("NotifyPutGlobalVar watched case"));
    2128         LBasicBlock isWatchedFast = FTL_NEW_BLOCK(m_out, ("NotifyPutGlobalVar watched fast case"));
    2129         LBasicBlock isWatchedSlow = FTL_NEW_BLOCK(m_out, ("NotifyPutGlobalVar watched slow case"));
    2130         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NotifyPutGlobalVar continuation"));
     2119    void compileNotifyWrite()
     2120    {
     2121        VariableWatchpointSet* set = m_node->variableWatchpointSet();
     2122       
     2123        LValue value = lowJSValue(m_node->child1());
     2124       
     2125        LBasicBlock isNotInvalidated = FTL_NEW_BLOCK(m_out, ("NotifyWrite not invalidated case"));
     2126        LBasicBlock isClear = FTL_NEW_BLOCK(m_out, ("NotifyWrite clear case"));
     2127        LBasicBlock isWatched = FTL_NEW_BLOCK(m_out, ("NotifyWrite watched case"));
     2128        LBasicBlock invalidate = FTL_NEW_BLOCK(m_out, ("NotifyWrite invalidate case"));
     2129        LBasicBlock invalidateFast = FTL_NEW_BLOCK(m_out, ("NotifyWrite invalidate fast case"));
     2130        LBasicBlock invalidateSlow = FTL_NEW_BLOCK(m_out, ("NotifyWrite invalidate slow case"));
     2131        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NotifyWrite continuation"));
    21312132       
    21322133        LValue state = m_out.load8(m_out.absolute(set->addressOfState()));
     
    21382139        LBasicBlock lastNext = m_out.appendTo(isNotInvalidated, isClear);
    21392140
    2140         m_out.fenceAcqRel();
    2141        
    21422141        LValue isClearValue;
    21432142        if (set->state() == ClearWatchpoint)
     
    21492148        m_out.appendTo(isClear, isWatched);
    21502149       
     2150        m_out.store64(value, m_out.absolute(set->addressOfInferredValue()));
    21512151        m_out.store8(m_out.constInt8(IsWatched), m_out.absolute(set->addressOfState()));
    21522152        m_out.jump(continuation);
    21532153       
    2154         m_out.appendTo(isWatched, isWatchedFast);
     2154        m_out.appendTo(isWatched, invalidate);
     2155       
     2156        m_out.branch(
     2157            m_out.equal(value, m_out.load64(m_out.absolute(set->addressOfInferredValue()))),
     2158            continuation, invalidate);
     2159       
     2160        m_out.appendTo(invalidate, invalidateFast);
    21552161       
    21562162        m_out.branch(
    21572163            m_out.notZero8(m_out.load8(m_out.absolute(set->addressOfSetIsNotEmpty()))),
    2158             isWatchedSlow, isWatchedFast);
    2159        
    2160         m_out.appendTo(isWatchedFast, isWatchedSlow);
    2161        
     2164            invalidateSlow, invalidateFast);
     2165       
     2166        m_out.appendTo(invalidateFast, invalidateSlow);
     2167       
     2168        m_out.store64(
     2169            m_out.constInt64(JSValue::encode(JSValue())),
     2170            m_out.absolute(set->addressOfInferredValue()));
    21622171        m_out.store8(m_out.constInt8(IsInvalidated), m_out.absolute(set->addressOfState()));
    21632172        m_out.jump(continuation);
    21642173       
    2165         m_out.appendTo(isWatchedSlow, continuation);
    2166        
    2167         vmCall(m_out.operation(operationNotifyWrite), m_callFrame, m_out.constIntPtr(set));
     2174        m_out.appendTo(invalidateSlow, continuation);
     2175       
     2176        vmCall(m_out.operation(operationInvalidate), m_callFrame, m_out.constIntPtr(set));
    21682177        m_out.jump(continuation);
    21692178       
    21702179        m_out.appendTo(continuation, lastNext);
    2171     }
    2172    
    2173     void compileGlobalVarWatchpoint()
    2174     {
    2175         // FIXME: In debug mode we could emit some assertion code here.
    2176         // https://bugs.webkit.org/show_bug.cgi?id=123471
    21772180    }
    21782181   
  • trunk/Source/JavaScriptCore/jit/JIT.h

    r159721 r159798  
    619619        void emitGetClosureVar(int scope, uintptr_t operand);
    620620        void emitPutGlobalProperty(uintptr_t* operandSlot, int value);
    621         void emitPutGlobalVar(uintptr_t operand, int value, WatchpointSet*);
     621#if USE(JSVALUE64)
     622        void emitNotifyWrite(RegisterID value, RegisterID scratch, VariableWatchpointSet*);
     623#else
     624        void emitNotifyWrite(RegisterID tag, RegisterID payload, RegisterID scratch, VariableWatchpointSet*);
     625#endif
     626        void emitPutGlobalVar(uintptr_t operand, int value, VariableWatchpointSet*);
    622627        void emitPutClosureVar(int scope, uintptr_t operand, int value);
    623628
  • trunk/Source/JavaScriptCore/jit/JITOperations.h

    r159545 r159798  
    3636#include "PutKind.h"
    3737#include "StructureStubInfo.h"
    38 #include "Watchpoint.h"
     38#include "VariableWatchpointSet.h"
    3939
    4040namespace JSC {
     
    7777    V: void
    7878    Vm: VM*
    79     W: WatchpointSet*
     79    Vws: VariableWatchpointSet*
    8080    Z: int32_t
    8181*/
     
    155155typedef void JIT_OPERATION (*V_JITOperation_EPZJ)(ExecState*, void*, int32_t, EncodedJSValue);
    156156typedef void JIT_OPERATION (*V_JITOperation_ESsiJJI)(ExecState*, StructureStubInfo*, EncodedJSValue, EncodedJSValue, StringImpl*);
    157 typedef void JIT_OPERATION (*V_JITOperation_EW)(ExecState*, WatchpointSet*);
     157typedef void JIT_OPERATION (*V_JITOperation_EVws)(ExecState*, VariableWatchpointSet*);
    158158typedef void JIT_OPERATION (*V_JITOperation_EZ)(ExecState*, int32_t);
    159159typedef void JIT_OPERATION (*V_JITOperation_EVm)(ExecState*, VM*);
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp

    r159545 r159798  
    772772}
    773773
    774 void JIT::emitPutGlobalVar(uintptr_t operand, int value, WatchpointSet* set)
    775 {
    776     if (set && set->state() != IsInvalidated) {
    777         load8(set->addressOfState(), regT1);
     774void JIT::emitNotifyWrite(RegisterID value, RegisterID scratch, VariableWatchpointSet* set)
     775{
     776    if (!set || set->state() == IsInvalidated)
     777        return;
     778   
     779    load8(set->addressOfState(), scratch);
     780   
     781    JumpList ready;
     782   
     783    ready.append(branch32(Equal, scratch, TrustedImm32(IsInvalidated)));
     784   
     785    if (set->state() == ClearWatchpoint) {
     786        Jump isWatched = branch32(NotEqual, scratch, TrustedImm32(ClearWatchpoint));
    778787       
    779         JumpList ready;
     788        store64(value, set->addressOfInferredValue());
     789        store8(TrustedImm32(IsWatched), set->addressOfState());
     790        ready.append(jump());
    780791       
    781         ready.append(branch32(Equal, regT1, TrustedImm32(IsInvalidated)));
    782        
    783         if (set->state() == ClearWatchpoint) {
    784             Jump isWatched = branch32(NotEqual, regT1, TrustedImm32(ClearWatchpoint));
    785            
    786             move(TrustedImm32(IsWatched), regT1);
    787             ready.append(jump());
    788            
    789             isWatched.link(this);
    790         }
    791        
    792         addSlowCase(branchTest8(NonZero, AbsoluteAddress(set->addressOfSetIsNotEmpty())));
    793         move(TrustedImm32(IsInvalidated), regT1);
    794         ready.link(this);
    795     }
    796    
     792        isWatched.link(this);
     793    }
     794   
     795    ready.append(branch64(Equal, AbsoluteAddress(set->addressOfInferredValue()), value));
     796    addSlowCase(branchTest8(NonZero, AbsoluteAddress(set->addressOfSetIsNotEmpty())));
     797    store8(TrustedImm32(IsInvalidated), set->addressOfState());
     798    move(TrustedImm64(JSValue::encode(JSValue())), scratch);
     799    store64(scratch, set->addressOfInferredValue());
     800   
     801    ready.link(this);
     802}
     803
     804void JIT::emitPutGlobalVar(uintptr_t operand, int value, VariableWatchpointSet* set)
     805{
    797806    emitGetVirtualRegister(value, regT0);
     807    emitNotifyWrite(regT0, regT1, set);
    798808    storePtr(regT0, reinterpret_cast<void*>(operand));
    799    
    800     if (set && set->state() != IsInvalidated) {
    801         memoryFence();
    802         store8(regT1, set->addressOfState());
    803     }
    804809}
    805810
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp

    r159545 r159798  
    808808}
    809809
    810 void JIT::emitPutGlobalVar(uintptr_t operand, int value, WatchpointSet* set)
    811 {
    812     if (set && set->state() != IsInvalidated) {
    813         load8(set->addressOfState(), regT2);
     810void JIT::emitNotifyWrite(RegisterID tag, RegisterID payload, RegisterID scratch, VariableWatchpointSet* set)
     811{
     812    if (!set || set->state() == IsInvalidated)
     813        return;
     814   
     815    load8(set->addressOfState(), scratch);
     816   
     817    JumpList ready;
     818   
     819    ready.append(branch32(Equal, scratch, TrustedImm32(IsInvalidated)));
     820   
     821    if (set->state() == ClearWatchpoint) {
     822        Jump isWatched = branch32(NotEqual, scratch, TrustedImm32(ClearWatchpoint));
    814823       
    815         JumpList ready;
     824        store32(tag, &set->addressOfInferredValue()->u.asBits.tag);
     825        store32(payload, &set->addressOfInferredValue()->u.asBits.payload);
     826        store8(TrustedImm32(IsWatched), set->addressOfState());
     827        ready.append(jump());
    816828       
    817         ready.append(branch32(Equal, regT2, TrustedImm32(IsInvalidated)));
    818        
    819         if (set->state() == ClearWatchpoint) {
    820             Jump isWatched = branch32(NotEqual, regT2, TrustedImm32(ClearWatchpoint));
    821            
    822             move(TrustedImm32(IsWatched), regT2);
    823             ready.append(jump());
    824            
    825             isWatched.link(this);
    826         }
    827        
    828         addSlowCase(branchTest8(NonZero, AbsoluteAddress(set->addressOfSetIsNotEmpty())));
    829         move(TrustedImm32(IsInvalidated), regT2);
    830         ready.link(this);
    831     }
    832    
     829        isWatched.link(this);
     830    }
     831
     832    Jump definitelyNotEqual = branch32(
     833        NotEqual, AbsoluteAddress(&set->addressOfInferredValue()->u.asBits.payload), payload);
     834    ready.append(branch32(
     835        Equal, AbsoluteAddress(&set->addressOfInferredValue()->u.asBits.tag), tag));
     836    definitelyNotEqual.link(this);
     837    addSlowCase(branchTest8(NonZero, AbsoluteAddress(set->addressOfSetIsNotEmpty())));
     838    store8(TrustedImm32(IsInvalidated), set->addressOfState());
     839    store32(
     840        TrustedImm32(JSValue::EmptyValueTag), &set->addressOfInferredValue()->u.asBits.tag);
     841    store32(TrustedImm32(0), &set->addressOfInferredValue()->u.asBits.payload);
     842   
     843    ready.link(this);
     844}
     845
     846void JIT::emitPutGlobalVar(uintptr_t operand, int value, VariableWatchpointSet* set)
     847{
    833848    emitLoad(value, regT1, regT0);
     849    emitNotifyWrite(regT1, regT0, regT2, set);
    834850    store32(regT1, reinterpret_cast<char*>(operand) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
    835851    store32(regT0, reinterpret_cast<char*>(operand) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
    836    
    837     if (set && set->state() != IsInvalidated) {
    838         memoryFence();
    839         store8(regT1, set->addressOfState());
    840     }
    841852}
    842853
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm

    r159545 r159798  
    21332133end
    21342134
     2135macro notifyWrite(set, valueTag, valuePayload, scratch, slow)
     2136    loadb VariableWatchpointSet::m_state[set], scratch
     2137    bieq scratch, IsInvalidated, .done
     2138    bineq scratch, ClearWatchpoint, .overwrite
     2139    storei valueTag, VariableWatchpointSet::m_inferredValue + TagOffset[set]
     2140    storei valuePayload, VariableWatchpointSet::m_inferredValue + PayloadOffset[set]
     2141    storeb IsWatched, VariableWatchpointSet::m_state[set]
     2142    jmp .done
     2143
     2144.overwrite:
     2145    bineq valuePayload, VariableWatchpointSet::m_inferredValue + PayloadOffset[set], .definitelyDifferent
     2146    bieq valueTag, VariableWatchpointSet::m_inferredValue + TagOffset[set], .done
     2147.definitelyDifferent:
     2148    btbnz VariableWatchpointSet::m_setIsNotEmpty[set], slow
     2149    storei EmptyValueTag, VariableWatchpointSet::m_inferredValue + TagOffset[set]
     2150    storei 0, VariableWatchpointSet::m_inferredValue + PayloadOffset[set]
     2151    storeb IsInvalidated, VariableWatchpointSet::m_state[set]
     2152
     2153.done:
     2154end
     2155
    21352156macro putGlobalVar()
    2136     loadpFromInstruction(5, t2)
    2137     loadb WatchpointSet::m_state[t2], t3
    2138     bieq t3, IsInvalidated, .ready
    2139     bineq t3, ClearWatchpoint, .needToInvalidate
    2140     move IsWatched, t3
    2141     jmp .ready
    2142 .needToInvalidate:
    2143     btbnz WatchpointSet::m_setIsNotEmpty[t2], .pDynamic
    2144     move IsInvalidated, t3
    2145 .ready:
    21462157    loadisFromInstruction(3, t0)
    21472158    loadConstantOrVariable(t0, t1, t2)
     2159    loadpFromInstruction(5, t3)
     2160    notifyWrite(t3, t1, t2, t0, .pDynamic)
    21482161    loadpFromInstruction(6, t0)
    21492162    storei t1, TagOffset[t0]
    21502163    storei t2, PayloadOffset[t0]
    2151     memfence
    2152     loadpFromInstruction(5, t2)
    2153     storeb t3, WatchpointSet::m_state[t2]
    21542164end
    21552165
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r159655 r159798  
    19531953end
    19541954
     1955macro notifyWrite(set, value, scratch, slow)
     1956    loadb VariableWatchpointSet::m_state[set], scratch
     1957    bieq scratch, IsInvalidated, .done
     1958    bineq scratch, ClearWatchpoint, .overwrite
     1959    storeq value, VariableWatchpointSet::m_inferredValue[set]
     1960    storeb IsWatched, VariableWatchpointSet::m_state[set]
     1961    jmp .done
     1962
     1963.overwrite:
     1964    bqeq value, VariableWatchpointSet::m_inferredValue[set], .done
     1965    btbnz VariableWatchpointSet::m_setIsNotEmpty[set], slow
     1966    storeq 0, VariableWatchpointSet::m_inferredValue[set]
     1967    storeb IsInvalidated, VariableWatchpointSet::m_state[set]
     1968
     1969.done:   
     1970end
     1971
    19551972macro putGlobalVar()
    1956     loadpFromInstruction(5, t2)
    1957     loadb WatchpointSet::m_state[t2], t3
    1958     bieq t3, IsInvalidated, .ready
    1959     bineq t3, ClearWatchpoint, .needToInvalidate
    1960     move IsWatched, t3
    1961     jmp .ready
    1962 .needToInvalidate:
    1963     btbnz WatchpointSet::m_setIsNotEmpty[t2], .pDynamic
    1964     move IsInvalidated, t3
    1965 .ready:
    19661973    loadisFromInstruction(3, t0)
    19671974    loadConstantOrVariable(t0, t1)
     1975    loadpFromInstruction(5, t2)
     1976    notifyWrite(t2, t1, t0, .pDynamic)
    19681977    loadpFromInstruction(6, t0)
    19691978    storeq t1, [t0]
    1970     memfence
    1971     storeb t3, WatchpointSet::m_state[t2]
    19721979end
    19731980
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r159605 r159798  
    217217    SymbolTableEntry newEntry(index, (constantMode == IsConstant) ? ReadOnly : 0);
    218218    if (constantMode == IsVariable)
    219         newEntry.prepareToWatch(SymbolTableEntry::NotInitialized);
     219        newEntry.prepareToWatch();
    220220    SymbolTable::Map::AddResult result = symbolTable()->add(locker, ident.impl(), newEntry);
    221221    if (result.isNewEntry)
     
    235235    registerAt(var.registerNumber).set(exec->vm(), this, value);
    236236    if (var.set)
    237         var.set->notifyWrite();
     237        var.set->notifyWrite(value);
    238238}
    239239
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h

    r159605 r159798  
    292292    struct NewGlobalVar {
    293293        int registerNumber;
    294         WatchpointSet* set;
     294        VariableWatchpointSet* set;
    295295    };
    296296    NewGlobalVar addGlobalVar(const Identifier&, ConstantMode);
  • trunk/Source/JavaScriptCore/runtime/JSScope.h

    r159462 r159798  
    3232
    3333class ScopeChainIterator;
    34 class WatchpointSet;
     34class VariableWatchpointSet;
    3535
    3636enum ResolveMode {
     
    9797
    9898struct ResolveOp {
    99     ResolveOp(ResolveType type, size_t depth, Structure* structure, WatchpointSet* watchpointSet, uintptr_t operand)
     99    ResolveOp(ResolveType type, size_t depth, Structure* structure, VariableWatchpointSet* watchpointSet, uintptr_t operand)
    100100        : type(type)
    101101        , depth(depth)
     
    109109    size_t depth;
    110110    Structure* structure;
    111     WatchpointSet* watchpointSet;
     111    VariableWatchpointSet* watchpointSet;
    112112    uintptr_t operand;
    113113};
  • trunk/Source/JavaScriptCore/runtime/JSSymbolTableObject.h

    r159713 r159798  
    124124   
    125125    WriteBarrierBase<Unknown>* reg;
    126     WatchpointSet* set = 0;
    127126    {
    128127        SymbolTable& symbolTable = *object->symbolTable();
     
    139138            return true;
    140139        }
    141         set = iter->value.watchpointSet();
     140        if (VariableWatchpointSet* set = iter->value.watchpointSet())
     141            set->notifyWrite(value);
    142142        reg = &object->registerAt(fastEntry.getIndex());
    143143    }
     
    146146    // locks while GC'ing.
    147147    reg->set(vm, object, value);
    148     if (set)
    149         set->notifyWrite();
    150148    return true;
    151149}
     
    159157
    160158    WriteBarrierBase<Unknown>* reg;
    161     WatchpointSet* set = 0;
    162159    {
    163160        SymbolTable& symbolTable = *object->symbolTable();
     
    168165        SymbolTableEntry& entry = iter->value;
    169166        ASSERT(!entry.isNull());
    170         set = entry.watchpointSet();
     167        if (VariableWatchpointSet* set = entry.watchpointSet())
     168            set->notifyWrite(value);
    171169        entry.setAttributes(attributes);
    172170        reg = &object->registerAt(entry.getIndex());
    173171    }
    174172    reg->set(vm, object, value);
    175     if (set)
    176         set->notifyWrite();
    177173    return true;
    178174}
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.cpp

    r159795 r159798  
    5959}
    6060
    61 bool SymbolTableEntry::couldBeWatched()
     61JSValue SymbolTableEntry::inferredValue()
    6262{
    6363    if (!isFat())
    64         return false;
    65     WatchpointSet* watchpoints = fatEntry()->m_watchpoints.get();
    66     if (!watchpoints)
    67         return false;
    68     return watchpoints->state() == IsWatched;
     64        return JSValue();
     65    return fatEntry()->m_watchpoints->inferredValue();
    6966}
    7067
    71 void SymbolTableEntry::prepareToWatch(WatchState state)
     68void SymbolTableEntry::prepareToWatch()
    7269{
    7370    FatEntry* entry = inflate();
    7471    ASSERT(!entry->m_watchpoints);
    75     entry->m_watchpoints = adoptRef(
    76         new WatchpointSet(state == AlreadyInitialized ? IsWatched : ClearWatchpoint));
     72    entry->m_watchpoints = adoptRef(new VariableWatchpointSet());
    7773}
    7874
    7975void SymbolTableEntry::addWatchpoint(Watchpoint* watchpoint)
    8076{
    81     ASSERT(couldBeWatched());
    8277    fatEntry()->m_watchpoints->add(watchpoint);
    8378}
    8479
    85 void SymbolTableEntry::notifyWriteSlow()
     80void SymbolTableEntry::notifyWriteSlow(JSValue value)
    8681{
    87     WatchpointSet* watchpoints = fatEntry()->m_watchpoints.get();
     82    VariableWatchpointSet* watchpoints = fatEntry()->m_watchpoints.get();
    8883    if (!watchpoints)
    8984        return;
    9085   
    91     watchpoints->notifyWrite();
     86    watchpoints->notifyWrite(value);
    9287}
    9388
     
    109104
    110105SymbolTable::~SymbolTable() { }
     106
     107void SymbolTable::visitChildren(JSCell* thisCell, SlotVisitor& visitor)
     108{
     109    SymbolTable* thisSymbolTable = jsCast<SymbolTable*>(thisCell);
     110    if (!thisSymbolTable->m_watchpointCleanup) {
     111        thisSymbolTable->m_watchpointCleanup =
     112            std::make_unique<WatchpointCleanup>(thisSymbolTable);
     113    }
     114   
     115    visitor.addUnconditionalFinalizer(thisSymbolTable->m_watchpointCleanup.get());
     116}
     117
     118SymbolTable::WatchpointCleanup::WatchpointCleanup(SymbolTable* symbolTable)
     119    : m_symbolTable(symbolTable)
     120{
     121}
     122
     123SymbolTable::WatchpointCleanup::~WatchpointCleanup() { }
     124
     125void SymbolTable::WatchpointCleanup::finalizeUnconditionally()
     126{
     127    Map::iterator iter = m_symbolTable->m_map.begin();
     128    Map::iterator end = m_symbolTable->m_map.end();
     129    for (; iter != end; ++iter) {
     130        if (VariableWatchpointSet* set = iter->value.watchpointSet())
     131            set->finalizeUnconditionally();
     132    }
     133}
    111134
    112135SymbolTable* SymbolTable::clone(VM& vm)
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.h

    r159795 r159798  
    3232#include "ConcurrentJITLock.h"
    3333#include "JSObject.h"
    34 #include "Watchpoint.h"
     34#include "VariableWatchpointSet.h"
    3535#include <memory>
    3636#include <wtf/HashTraits.h>
     
    3838
    3939namespace JSC {
    40 
    41 class Watchpoint;
    42 class WatchpointSet;
    4340
    4441struct SlowArgument {
     
    8077// WatchpointSet will manifest in all copies. Here's a picture:
    8178//
    82 // SymbolTableEntry --> FatEntry --> WatchpointSet
     79// SymbolTableEntry --> FatEntry --> VariableWatchpointSet
    8380//
    8481// If you make a copy of a SymbolTableEntry, you will have:
    8582//
    86 // original: SymbolTableEntry --> FatEntry --> WatchpointSet
     83// original: SymbolTableEntry --> FatEntry --> VariableWatchpointSet
    8784// copy:     SymbolTableEntry --> FatEntry -----^
    8885
     
    219216    }
    220217   
    221     bool couldBeWatched();
    222    
    223     enum WatchState { NotInitialized, AlreadyInitialized };
    224     void prepareToWatch(WatchState);
     218    JSValue inferredValue();
     219   
     220    void prepareToWatch();
    225221   
    226222    void addWatchpoint(Watchpoint*);
    227223   
    228     WatchpointSet* watchpointSet()
     224    VariableWatchpointSet* watchpointSet()
    229225    {
    230226        if (!isFat())
     
    233229    }
    234230   
    235     ALWAYS_INLINE void notifyWrite()
     231    ALWAYS_INLINE void notifyWrite(JSValue value)
    236232    {
    237233        if (LIKELY(!isFat()))
    238234            return;
    239         notifyWriteSlow();
     235        notifyWriteSlow(value);
    240236    }
    241237   
     
    257253        intptr_t m_bits; // always has FatFlag set and exactly matches what the bits would have been if this wasn't fat.
    258254       
    259         RefPtr<WatchpointSet> m_watchpoints;
     255        RefPtr<VariableWatchpointSet> m_watchpoints;
    260256    };
    261257   
    262258    SymbolTableEntry& copySlow(const SymbolTableEntry&);
    263     JS_EXPORT_PRIVATE void notifyWriteSlow();
     259    JS_EXPORT_PRIVATE void notifyWriteSlow(JSValue);
    264260   
    265261    bool isFat() const
     
    469465    SymbolTable* clone(VM&);
    470466
     467    static void visitChildren(JSCell*, SlotVisitor&);
     468
    471469    DECLARE_EXPORT_INFO;
    472470
    473471private:
     472    class WatchpointCleanup : public UnconditionalFinalizer {
     473    public:
     474        WatchpointCleanup(SymbolTable*);
     475        virtual ~WatchpointCleanup();
     476       
     477    protected:
     478        virtual void finalizeUnconditionally() OVERRIDE;
     479
     480    private:
     481        SymbolTable* m_symbolTable;
     482    };
     483   
    474484    JS_EXPORT_PRIVATE SymbolTable(VM&);
    475485    ~SymbolTable();
     
    484494
    485495    std::unique_ptr<SlowArgument[]> m_slowArguments;
     496   
     497    std::unique_ptr<WatchpointCleanup> m_watchpointCleanup;
    486498
    487499public:
Note: See TracChangeset for help on using the changeset viewer.