Changeset 120172 in webkit


Ignore:
Timestamp:
Jun 13, 2012, 1:20:39 AM (13 years ago)
Author:
[email protected]
Message:

DFG should be able to set watchpoints on global variables
https://bugs.webkit.org/show_bug.cgi?id=88692

Source/JavaScriptCore:

Reviewed by Geoffrey Garen.

This implements global variable constant folding by allowing the optimizing
compiler to set a "watchpoint" on globals that it wishes to constant fold.
If the watchpoint fires, then an OSR exit is forced by overwriting the
machine code that the optimizing compiler generated with a jump.

As such, this patch is adding quite a bit of stuff:

  • Jump replacement on those hardware targets supported by the optimizing JIT. It is now possible to patch in a jump instruction over any recorded watchpoint label. The jump must be "local" in the sense that it must be within the range of the largest jump distance supported by a one instruction jump.


  • WatchpointSets and Watchpoints. A Watchpoint is a doubly-linked list node that records the location where a jump must be inserted and the destination to which it should jump. Watchpoints can be added to a WatchpointSet. The WatchpointSet can be fired all at once, which plants all jumps. WatchpointSet also remembers if it had ever been invalidated, which allows for monotonicity: we typically don't want to optimize using watchpoints on something for which watchpoints had previously fired. The act of notifying a WatchpointSet has a trivial fast path in case no Watchpoints are registered (one-byte load+branch).


  • SpeculativeJIT::speculationWatchpoint(). It's like speculationCheck(), except that you don't have to emit branches. But, you need to know what WatchpointSet to add the resulting Watchpoint to. Not everything that you could write a speculationCheck() for will have a WatchpointSet that would get notified if the condition you were speculating against became invalid.


  • SymbolTableEntry now has the ability to refer to a WatchpointSet. It can do so without incurring any space overhead for those entries that don't have WatchpointSets.


  • The bytecode generator infers all global function variables to be watchable, and makes all stores perform the WatchpointSet's write check, and marks all loads as being potentially watchable (i.e. you can compile them to a watchpoint and a constant).


Put together, this allows for fully sleazy inlining of calls to globally
declared functions. The inline prologue will no longer contain the load of
the function, or any checks of the function you're calling. I.e. it's
pretty much like the kind of inlining you would see in Java or C++.
Furthermore, the watchpointing functionality is built to be fairly general,
and should allow setting watchpoints on all sorts of interesting things
in the future.

The sleazy inlining means that we will now sometimes inline in code paths
that have never executed. Previously, to inline we would have either had
to have executed the call (to read the call's inline cache) or have
executed the method check (to read the method check's inline cache). Now,
we might inline when the callee is a watched global variable. This
revealed some humorous bugs. First, constant folding disagreed with CFA
over what kinds of operations can clobber (example: code path A is dead
but stores a String into variable X, all other code paths store 0 into
X, and then you do CompareEq(X, 0) - CFA will say that this is a non-
clobbering constant, but constant folding thought it was clobbering
because it saw the String prediction). Second, inlining would crash if
the inline callee had not been compiled. This patch fixes both bugs,
since otherwise run-javascriptcore-tests would report regressions.

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Target.pri:
  • assembler/ARMv7Assembler.h:

(ARMv7Assembler):
(JSC::ARMv7Assembler::ARMv7Assembler):
(JSC::ARMv7Assembler::labelForWatchpoint):
(JSC::ARMv7Assembler::label):
(JSC::ARMv7Assembler::replaceWithJump):
(JSC::ARMv7Assembler::maxJumpReplacementSize):

  • assembler/AbstractMacroAssembler.h:

(JSC):
(AbstractMacroAssembler):
(Label):
(JSC::AbstractMacroAssembler::watchpointLabel):

  • assembler/AssemblerBuffer.h:
  • assembler/MacroAssemblerARM.h:

(JSC::MacroAssemblerARM::replaceWithJump):
(MacroAssemblerARM):
(JSC::MacroAssemblerARM::maxJumpReplacementSize):

  • assembler/MacroAssemblerARMv7.h:

(MacroAssemblerARMv7):
(JSC::MacroAssemblerARMv7::replaceWithJump):
(JSC::MacroAssemblerARMv7::maxJumpReplacementSize):
(JSC::MacroAssemblerARMv7::branchTest8):
(JSC::MacroAssemblerARMv7::jump):
(JSC::MacroAssemblerARMv7::makeBranch):

  • assembler/MacroAssemblerMIPS.h:

(JSC::MacroAssemblerMIPS::replaceWithJump):
(MacroAssemblerMIPS):
(JSC::MacroAssemblerMIPS::maxJumpReplacementSize):

  • assembler/MacroAssemblerSH4.h:

(JSC::MacroAssemblerSH4::replaceWithJump):
(MacroAssemblerSH4):
(JSC::MacroAssemblerSH4::maxJumpReplacementSize):

  • assembler/MacroAssemblerX86.h:

(MacroAssemblerX86):
(JSC::MacroAssemblerX86::branchTest8):

  • assembler/MacroAssemblerX86Common.h:

(JSC::MacroAssemblerX86Common::replaceWithJump):
(MacroAssemblerX86Common):
(JSC::MacroAssemblerX86Common::maxJumpReplacementSize):

  • assembler/MacroAssemblerX86_64.h:

(MacroAssemblerX86_64):
(JSC::MacroAssemblerX86_64::branchTest8):

  • assembler/X86Assembler.h:

(JSC::X86Assembler::X86Assembler):
(X86Assembler):
(JSC::X86Assembler::cmpb_im):
(JSC::X86Assembler::testb_im):
(JSC::X86Assembler::labelForWatchpoint):
(JSC::X86Assembler::label):
(JSC::X86Assembler::replaceWithJump):
(JSC::X86Assembler::maxJumpReplacementSize):
(JSC::X86Assembler::X86InstructionFormatter::memoryModRM):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dump):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::appendOSRExit):
(JSC::CodeBlock::appendSpeculationRecovery):
(CodeBlock):
(JSC::CodeBlock::appendWatchpoint):
(JSC::CodeBlock::numberOfWatchpoints):
(JSC::CodeBlock::watchpoint):
(DFGData):

  • bytecode/DFGExitProfile.h:

(JSC::DFG::exitKindToString):
(JSC::DFG::exitKindIsCountable):

  • bytecode/Instruction.h:

(Instruction):
(JSC::Instruction::Instruction):

  • bytecode/Opcode.h:

(JSC):
(JSC::padOpcodeName):

  • bytecode/Watchpoint.cpp: Added.

(JSC):
(JSC::Watchpoint::~Watchpoint):
(JSC::Watchpoint::correctLabels):
(JSC::Watchpoint::fire):
(JSC::WatchpointSet::WatchpointSet):
(JSC::WatchpointSet::~WatchpointSet):
(JSC::WatchpointSet::add):
(JSC::WatchpointSet::notifyWriteSlow):
(JSC::WatchpointSet::fireAllWatchpoints):

  • bytecode/Watchpoint.h: Added.

(JSC):
(Watchpoint):
(JSC::Watchpoint::Watchpoint):
(JSC::Watchpoint::setDestination):
(WatchpointSet):
(JSC::WatchpointSet::isStillValid):
(JSC::WatchpointSet::hasBeenInvalidated):
(JSC::WatchpointSet::startWatching):
(JSC::WatchpointSet::notifyWrite):
(JSC::WatchpointSet::addressOfIsWatched):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::ResolveResult::checkValidity):
(JSC::BytecodeGenerator::addGlobalVar):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::resolve):
(JSC::BytecodeGenerator::emitResolve):
(JSC::BytecodeGenerator::emitResolveWithBase):
(JSC::BytecodeGenerator::emitResolveWithThis):
(JSC::BytecodeGenerator::emitGetStaticVar):
(JSC::BytecodeGenerator::emitPutStaticVar):

  • bytecompiler/BytecodeGenerator.h:

(BytecodeGenerator):

  • bytecompiler/NodesCodegen.cpp:

(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::PostfixResolveNode::emitBytecode):
(JSC::PrefixResolveNode::emitBytecode):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::ConstDeclNode::emitCodeSingle):

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::execute):
(JSC::DFG::AbstractState::clobberStructures):

  • dfg/DFGAbstractState.h:

(AbstractState):
(JSC::DFG::AbstractState::didClobber):

  • dfg/DFGByteCodeParser.cpp:

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

  • dfg/DFGCCallHelpers.h:

(CCallHelpers):
(JSC::DFG::CCallHelpers::setupArguments):

  • dfg/DFGCSEPhase.cpp:

(JSC::DFG::CSEPhase::globalVarWatchpointElimination):
(CSEPhase):
(JSC::DFG::CSEPhase::globalVarStoreElimination):
(JSC::DFG::CSEPhase::performNodeCSE):

  • dfg/DFGCapabilities.h:

(JSC::DFG::canCompileOpcode):

  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::ConstantFoldingPhase::run):

  • dfg/DFGCorrectableJumpPoint.h:

(JSC::DFG::CorrectableJumpPoint::isSet):
(CorrectableJumpPoint):

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::linkOSRExits):
(JSC::DFG::JITCompiler::link):

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasIdentifierNumberForCheck):
(Node):
(JSC::DFG::Node::identifierNumberForCheck):
(JSC::DFG::Node::hasRegisterPointer):

  • dfg/DFGNodeType.h:

(DFG):

  • dfg/DFGOSRExit.cpp:

(JSC::DFG::OSRExit::OSRExit):

  • dfg/DFGOSRExit.h:

(OSRExit):

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

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

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):
(JSC::DFG::SpeculativeJIT::appendCall):
(SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::speculationWatchpoint):

  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):

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

(JSC::JIT::emit_op_put_global_var_check):
(JSC):
(JSC::JIT::emitSlow_op_put_global_var_check):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emit_op_put_global_var_check):
(JSC):
(JSC::JIT::emitSlow_op_put_global_var_check):

  • jit/JITStubs.cpp:

(JSC::JITThunks::JITThunks):
(JSC::DEFINE_STUB_FUNCTION):
(JSC):

  • jit/JITStubs.h:
  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):
(LLInt):

  • llint/LLIntSlowPaths.h:

(LLInt):

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

(JSC::JSObject::removeDirect):

  • runtime/JSObject.h:

(JSObject):

  • runtime/JSSymbolTableObject.h:

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

  • runtime/SymbolTable.cpp: Added.

(JSC):
(JSC::SymbolTableEntry::copySlow):
(JSC::SymbolTableEntry::freeFatEntrySlow):
(JSC::SymbolTableEntry::couldBeWatched):
(JSC::SymbolTableEntry::attemptToWatch):
(JSC::SymbolTableEntry::addressOfIsWatched):
(JSC::SymbolTableEntry::addWatchpoint):
(JSC::SymbolTableEntry::notifyWriteSlow):
(JSC::SymbolTableEntry::inflateSlow):

  • runtime/SymbolTable.h:

(JSC):
(SymbolTableEntry):
(Fast):
(JSC::SymbolTableEntry::Fast::Fast):
(JSC::SymbolTableEntry::Fast::isNull):
(JSC::SymbolTableEntry::Fast::getIndex):
(JSC::SymbolTableEntry::Fast::isReadOnly):
(JSC::SymbolTableEntry::Fast::getAttributes):
(JSC::SymbolTableEntry::Fast::isFat):
(JSC::SymbolTableEntry::SymbolTableEntry):
(JSC::SymbolTableEntry::~SymbolTableEntry):
(JSC::SymbolTableEntry::operator=):
(JSC::SymbolTableEntry::isNull):
(JSC::SymbolTableEntry::getIndex):
(JSC::SymbolTableEntry::getFast):
(JSC::SymbolTableEntry::getAttributes):
(JSC::SymbolTableEntry::isReadOnly):
(JSC::SymbolTableEntry::watchpointSet):
(JSC::SymbolTableEntry::notifyWrite):
(FatEntry):
(JSC::SymbolTableEntry::FatEntry::FatEntry):
(JSC::SymbolTableEntry::isFat):
(JSC::SymbolTableEntry::fatEntry):
(JSC::SymbolTableEntry::inflate):
(JSC::SymbolTableEntry::bits):
(JSC::SymbolTableEntry::freeFatEntry):
(JSC::SymbolTableEntry::pack):
(JSC::SymbolTableEntry::isValidIndex):

Source/WTF:

Reviewed by Geoffrey Garen.

Added ability to set the inline capacity of segmented vectors.

  • wtf/SegmentedVector.h:

(WTF):
(SegmentedVectorIterator):
(WTF::SegmentedVectorIterator::operator=):
(WTF::SegmentedVectorIterator::SegmentedVectorIterator):
(SegmentedVector):

LayoutTests:

Rubber stamped by Geoffrey Garen.

Added a test for watchpoints. Also updated the jsc-test-list to include the latest
tests.

  • fast/js/dfg-call-function-hit-watchpoint-expected.txt: Added.
  • fast/js/dfg-call-function-hit-watchpoint.html: Added.
  • fast/js/jsc-test-list:
  • fast/js/script-tests/dfg-call-function-hit-watchpoint.js: Added.

(foo):
(bar):
(.foo):

Location:
trunk
Files:
6 added
63 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r120170 r120172  
     12012-06-12  Filip Pizlo  <[email protected]>
     2
     3        DFG should be able to set watchpoints on global variables
     4        https://bugs.webkit.org/show_bug.cgi?id=88692
     5
     6        Rubber stamped by Geoffrey Garen.
     7       
     8        Added a test for watchpoints. Also updated the jsc-test-list to include the latest
     9        tests.
     10
     11        * fast/js/dfg-call-function-hit-watchpoint-expected.txt: Added.
     12        * fast/js/dfg-call-function-hit-watchpoint.html: Added.
     13        * fast/js/jsc-test-list:
     14        * fast/js/script-tests/dfg-call-function-hit-watchpoint.js: Added.
     15        (foo):
     16        (bar):
     17        (.foo):
     18
    1192012-06-13  Kristóf Kosztyó  <[email protected]>
    220
  • trunk/LayoutTests/fast/js/jsc-test-list

    r118323 r120172  
    6565fast/js/delete-getters-setters
    6666fast/js/delete-then-put
     67fast/js/dfg-add-not-number
     68fast/js/dfg-arguments-alias-escape
     69fast/js/dfg-arguments-alias-one-block-osr-exit
     70fast/js/dfg-arguments-alias-one-block-overwrite-arguments
     71fast/js/dfg-arguments-alias-one-block-overwrite
     72fast/js/dfg-arguments-alias-one-block
     73fast/js/dfg-arguments-alias
     74fast/js/dfg-arguments-cross-code-origin
     75fast/js/dfg-arguments-mixed-alias
    6776fast/js/dfg-arguments-osr-exit
    68 fast/js/dfg-arguments-mixed-alias
    69 fast/js/dfg-arguments-cross-code-origin
     77fast/js/dfg-arguments-out-of-bounds
    7078fast/js/dfg-arguments-unexpected-escape
    71 fast/js/dfg-arguments-alias
    72 fast/js/dfg-arguments-alias-escape
    7379fast/js/dfg-array-length-dead
     80fast/js/dfg-branch-not-fail
     81fast/js/dfg-check-two-structures
     82fast/js/dfg-constant-fold-first-local-read-after-block-merge
    7483fast/js/dfg-convert-this-dom-window
     84fast/js/dfg-cse-cfa-discrepancy
     85fast/js/dfg-dead-min-one-arg
     86fast/js/dfg-dead-min-two-args
     87fast/js/dfg-dead-speculation
     88fast/js/dfg-dead-variable-on-exit
     89fast/js/dfg-double-use-of-post-simplification-double-prediction
    7590fast/js/dfg-double-vote-fuzz
    7691fast/js/dfg-exception
    7792fast/js/dfg-float32array
    7893fast/js/dfg-float64array
     94fast/js/dfg-flush-get-local
    7995fast/js/dfg-get-by-val-clobber
    8096fast/js/dfg-get-by-val-getter-cse
    8197fast/js/dfg-getter-throw
    8298fast/js/dfg-getter
     99fast/js/dfg-inline-arguments-become-double
     100fast/js/dfg-inline-arguments-become-int32
    83101fast/js/dfg-inline-arguments-int32
     102fast/js/dfg-inline-arguments-osr-exit-and-capture
     103fast/js/dfg-inline-arguments-out-of-bounds
     104fast/js/dfg-inline-arguments-reset-changetype
     105fast/js/dfg-inline-arguments-reset
    84106fast/js/dfg-inline-arguments-simple
    85107fast/js/dfg-inline-arguments-use-directly-from-inlined-code
     
    97119fast/js/dfg-inlining-reg-alloc
    98120fast/js/dfg-int16array
     121fast/js/dfg-int32-to-double-on-known-number
    99122fast/js/dfg-int32array-overflow-values
    100123fast/js/dfg-int32array
     
    106129fast/js/dfg-min-max
    107130fast/js/dfg-multiply
     131fast/js/dfg-negative-array-index
     132fast/js/dfg-obvious-constant-cfa
    108133fast/js/dfg-other-branch
    109134fast/js/dfg-poison-fuzz
     135fast/js/dfg-proto-access-inline-osr-exit
     136fast/js/dfg-put-by-id-prototype-check
     137fast/js/dfg-putbyval-cfa-clobber
    110138fast/js/dfg-string-stricteq
     139fast/js/dfg-tear-off-arguments-not-activation
    111140fast/js/dfg-uint16array
     141fast/js/dfg-uint32-to-number-on-captured-variable
     142fast/js/dfg-uint32-to-number
     143fast/js/dfg-uint32array-overflow-constant
    112144fast/js/dfg-uint32array-overflow-values
    113 fast/js/dfg-uint32-to-number
    114 fast/js/dfg-uint32-to-number-on-captured-variable
     145fast/js/dfg-uint32array
    115146fast/js/dfg-uint8array
    116147fast/js/dfg-uint8clampedarray
     148fast/js/dfg-weak-js-constant-silent-fill
    117149fast/js/dictionary-no-cache
    118150fast/js/dictionary-prototype-caching
     
    127159fast/js/exception-for-nonobject
    128160fast/js/exception-linenums
     161fast/js/exception-propagate-from-dfg-to-llint
    129162fast/js/exception-properties
    130163fast/js/exception-try-finally-scope-error
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r119660 r120172  
    5454    bytecode/SamplingTool.cpp
    5555    bytecode/StructureStubInfo.cpp
     56    bytecode/Watchpoint.cpp
    5657
    5758    bytecompiler/BytecodeGenerator.cpp
     
    232233    runtime/Structure.cpp
    233234    runtime/StructureChain.cpp
     235    runtime/SymbolTable.cpp
    234236    runtime/TimeoutChecker.cpp
    235237    runtime/UString.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r120159 r120172  
     12012-06-12  Filip Pizlo  <[email protected]>
     2
     3        DFG should be able to set watchpoints on global variables
     4        https://bugs.webkit.org/show_bug.cgi?id=88692
     5
     6        Reviewed by Geoffrey Garen.
     7       
     8        This implements global variable constant folding by allowing the optimizing
     9        compiler to set a "watchpoint" on globals that it wishes to constant fold.
     10        If the watchpoint fires, then an OSR exit is forced by overwriting the
     11        machine code that the optimizing compiler generated with a jump.
     12       
     13        As such, this patch is adding quite a bit of stuff:
     14       
     15        - Jump replacement on those hardware targets supported by the optimizing
     16          JIT. It is now possible to patch in a jump instruction over any recorded
     17          watchpoint label. The jump must be "local" in the sense that it must be
     18          within the range of the largest jump distance supported by a one
     19          instruction jump.
     20         
     21        - WatchpointSets and Watchpoints. A Watchpoint is a doubly-linked list node
     22          that records the location where a jump must be inserted and the
     23          destination to which it should jump. Watchpoints can be added to a
     24          WatchpointSet. The WatchpointSet can be fired all at once, which plants
     25          all jumps. WatchpointSet also remembers if it had ever been invalidated,
     26          which allows for monotonicity: we typically don't want to optimize using
     27          watchpoints on something for which watchpoints had previously fired. The
     28          act of notifying a WatchpointSet has a trivial fast path in case no
     29          Watchpoints are registered (one-byte load+branch).
     30       
     31        - SpeculativeJIT::speculationWatchpoint(). It's like speculationCheck(),
     32          except that you don't have to emit branches. But, you need to know what
     33          WatchpointSet to add the resulting Watchpoint to. Not everything that
     34          you could write a speculationCheck() for will have a WatchpointSet that
     35          would get notified if the condition you were speculating against became
     36          invalid.
     37         
     38        - SymbolTableEntry now has the ability to refer to a WatchpointSet. It can
     39          do so without incurring any space overhead for those entries that don't
     40          have WatchpointSets.
     41         
     42        - The bytecode generator infers all global function variables to be
     43          watchable, and makes all stores perform the WatchpointSet's write check,
     44          and marks all loads as being potentially watchable (i.e. you can compile
     45          them to a watchpoint and a constant).
     46       
     47        Put together, this allows for fully sleazy inlining of calls to globally
     48        declared functions. The inline prologue will no longer contain the load of
     49        the function, or any checks of the function you're calling. I.e. it's
     50        pretty much like the kind of inlining you would see in Java or C++.
     51        Furthermore, the watchpointing functionality is built to be fairly general,
     52        and should allow setting watchpoints on all sorts of interesting things
     53        in the future.
     54       
     55        The sleazy inlining means that we will now sometimes inline in code paths
     56        that have never executed. Previously, to inline we would have either had
     57        to have executed the call (to read the call's inline cache) or have
     58        executed the method check (to read the method check's inline cache). Now,
     59        we might inline when the callee is a watched global variable. This
     60        revealed some humorous bugs. First, constant folding disagreed with CFA
     61        over what kinds of operations can clobber (example: code path A is dead
     62        but stores a String into variable X, all other code paths store 0 into
     63        X, and then you do CompareEq(X, 0) - CFA will say that this is a non-
     64        clobbering constant, but constant folding thought it was clobbering
     65        because it saw the String prediction). Second, inlining would crash if
     66        the inline callee had not been compiled. This patch fixes both bugs,
     67        since otherwise run-javascriptcore-tests would report regressions.
     68
     69        * CMakeLists.txt:
     70        * GNUmakefile.list.am:
     71        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
     72        * JavaScriptCore.xcodeproj/project.pbxproj:
     73        * Target.pri:
     74        * assembler/ARMv7Assembler.h:
     75        (ARMv7Assembler):
     76        (JSC::ARMv7Assembler::ARMv7Assembler):
     77        (JSC::ARMv7Assembler::labelForWatchpoint):
     78        (JSC::ARMv7Assembler::label):
     79        (JSC::ARMv7Assembler::replaceWithJump):
     80        (JSC::ARMv7Assembler::maxJumpReplacementSize):
     81        * assembler/AbstractMacroAssembler.h:
     82        (JSC):
     83        (AbstractMacroAssembler):
     84        (Label):
     85        (JSC::AbstractMacroAssembler::watchpointLabel):
     86        * assembler/AssemblerBuffer.h:
     87        * assembler/MacroAssemblerARM.h:
     88        (JSC::MacroAssemblerARM::replaceWithJump):
     89        (MacroAssemblerARM):
     90        (JSC::MacroAssemblerARM::maxJumpReplacementSize):
     91        * assembler/MacroAssemblerARMv7.h:
     92        (MacroAssemblerARMv7):
     93        (JSC::MacroAssemblerARMv7::replaceWithJump):
     94        (JSC::MacroAssemblerARMv7::maxJumpReplacementSize):
     95        (JSC::MacroAssemblerARMv7::branchTest8):
     96        (JSC::MacroAssemblerARMv7::jump):
     97        (JSC::MacroAssemblerARMv7::makeBranch):
     98        * assembler/MacroAssemblerMIPS.h:
     99        (JSC::MacroAssemblerMIPS::replaceWithJump):
     100        (MacroAssemblerMIPS):
     101        (JSC::MacroAssemblerMIPS::maxJumpReplacementSize):
     102        * assembler/MacroAssemblerSH4.h:
     103        (JSC::MacroAssemblerSH4::replaceWithJump):
     104        (MacroAssemblerSH4):
     105        (JSC::MacroAssemblerSH4::maxJumpReplacementSize):
     106        * assembler/MacroAssemblerX86.h:
     107        (MacroAssemblerX86):
     108        (JSC::MacroAssemblerX86::branchTest8):
     109        * assembler/MacroAssemblerX86Common.h:
     110        (JSC::MacroAssemblerX86Common::replaceWithJump):
     111        (MacroAssemblerX86Common):
     112        (JSC::MacroAssemblerX86Common::maxJumpReplacementSize):
     113        * assembler/MacroAssemblerX86_64.h:
     114        (MacroAssemblerX86_64):
     115        (JSC::MacroAssemblerX86_64::branchTest8):
     116        * assembler/X86Assembler.h:
     117        (JSC::X86Assembler::X86Assembler):
     118        (X86Assembler):
     119        (JSC::X86Assembler::cmpb_im):
     120        (JSC::X86Assembler::testb_im):
     121        (JSC::X86Assembler::labelForWatchpoint):
     122        (JSC::X86Assembler::label):
     123        (JSC::X86Assembler::replaceWithJump):
     124        (JSC::X86Assembler::maxJumpReplacementSize):
     125        (JSC::X86Assembler::X86InstructionFormatter::memoryModRM):
     126        * bytecode/CodeBlock.cpp:
     127        (JSC::CodeBlock::dump):
     128        * bytecode/CodeBlock.h:
     129        (JSC::CodeBlock::appendOSRExit):
     130        (JSC::CodeBlock::appendSpeculationRecovery):
     131        (CodeBlock):
     132        (JSC::CodeBlock::appendWatchpoint):
     133        (JSC::CodeBlock::numberOfWatchpoints):
     134        (JSC::CodeBlock::watchpoint):
     135        (DFGData):
     136        * bytecode/DFGExitProfile.h:
     137        (JSC::DFG::exitKindToString):
     138        (JSC::DFG::exitKindIsCountable):
     139        * bytecode/Instruction.h:
     140        (Instruction):
     141        (JSC::Instruction::Instruction):
     142        * bytecode/Opcode.h:
     143        (JSC):
     144        (JSC::padOpcodeName):
     145        * bytecode/Watchpoint.cpp: Added.
     146        (JSC):
     147        (JSC::Watchpoint::~Watchpoint):
     148        (JSC::Watchpoint::correctLabels):
     149        (JSC::Watchpoint::fire):
     150        (JSC::WatchpointSet::WatchpointSet):
     151        (JSC::WatchpointSet::~WatchpointSet):
     152        (JSC::WatchpointSet::add):
     153        (JSC::WatchpointSet::notifyWriteSlow):
     154        (JSC::WatchpointSet::fireAllWatchpoints):
     155        * bytecode/Watchpoint.h: Added.
     156        (JSC):
     157        (Watchpoint):
     158        (JSC::Watchpoint::Watchpoint):
     159        (JSC::Watchpoint::setDestination):
     160        (WatchpointSet):
     161        (JSC::WatchpointSet::isStillValid):
     162        (JSC::WatchpointSet::hasBeenInvalidated):
     163        (JSC::WatchpointSet::startWatching):
     164        (JSC::WatchpointSet::notifyWrite):
     165        (JSC::WatchpointSet::addressOfIsWatched):
     166        * bytecompiler/BytecodeGenerator.cpp:
     167        (JSC::ResolveResult::checkValidity):
     168        (JSC::BytecodeGenerator::addGlobalVar):
     169        (JSC::BytecodeGenerator::BytecodeGenerator):
     170        (JSC::BytecodeGenerator::resolve):
     171        (JSC::BytecodeGenerator::emitResolve):
     172        (JSC::BytecodeGenerator::emitResolveWithBase):
     173        (JSC::BytecodeGenerator::emitResolveWithThis):
     174        (JSC::BytecodeGenerator::emitGetStaticVar):
     175        (JSC::BytecodeGenerator::emitPutStaticVar):
     176        * bytecompiler/BytecodeGenerator.h:
     177        (BytecodeGenerator):
     178        * bytecompiler/NodesCodegen.cpp:
     179        (JSC::FunctionCallResolveNode::emitBytecode):
     180        (JSC::PostfixResolveNode::emitBytecode):
     181        (JSC::PrefixResolveNode::emitBytecode):
     182        (JSC::ReadModifyResolveNode::emitBytecode):
     183        (JSC::AssignResolveNode::emitBytecode):
     184        (JSC::ConstDeclNode::emitCodeSingle):
     185        * dfg/DFGAbstractState.cpp:
     186        (JSC::DFG::AbstractState::execute):
     187        (JSC::DFG::AbstractState::clobberStructures):
     188        * dfg/DFGAbstractState.h:
     189        (AbstractState):
     190        (JSC::DFG::AbstractState::didClobber):
     191        * dfg/DFGByteCodeParser.cpp:
     192        (JSC::DFG::ByteCodeParser::handleInlining):
     193        (JSC::DFG::ByteCodeParser::parseBlock):
     194        * dfg/DFGCCallHelpers.h:
     195        (CCallHelpers):
     196        (JSC::DFG::CCallHelpers::setupArguments):
     197        * dfg/DFGCSEPhase.cpp:
     198        (JSC::DFG::CSEPhase::globalVarWatchpointElimination):
     199        (CSEPhase):
     200        (JSC::DFG::CSEPhase::globalVarStoreElimination):
     201        (JSC::DFG::CSEPhase::performNodeCSE):
     202        * dfg/DFGCapabilities.h:
     203        (JSC::DFG::canCompileOpcode):
     204        * dfg/DFGConstantFoldingPhase.cpp:
     205        (JSC::DFG::ConstantFoldingPhase::run):
     206        * dfg/DFGCorrectableJumpPoint.h:
     207        (JSC::DFG::CorrectableJumpPoint::isSet):
     208        (CorrectableJumpPoint):
     209        * dfg/DFGJITCompiler.cpp:
     210        (JSC::DFG::JITCompiler::linkOSRExits):
     211        (JSC::DFG::JITCompiler::link):
     212        * dfg/DFGNode.h:
     213        (JSC::DFG::Node::hasIdentifierNumberForCheck):
     214        (Node):
     215        (JSC::DFG::Node::identifierNumberForCheck):
     216        (JSC::DFG::Node::hasRegisterPointer):
     217        * dfg/DFGNodeType.h:
     218        (DFG):
     219        * dfg/DFGOSRExit.cpp:
     220        (JSC::DFG::OSRExit::OSRExit):
     221        * dfg/DFGOSRExit.h:
     222        (OSRExit):
     223        * dfg/DFGOperations.cpp:
     224        * dfg/DFGOperations.h:
     225        * dfg/DFGPredictionPropagationPhase.cpp:
     226        (JSC::DFG::PredictionPropagationPhase::propagate):
     227        * dfg/DFGSpeculativeJIT.h:
     228        (JSC::DFG::SpeculativeJIT::callOperation):
     229        (JSC::DFG::SpeculativeJIT::appendCall):
     230        (SpeculativeJIT):
     231        (JSC::DFG::SpeculativeJIT::speculationWatchpoint):
     232        * dfg/DFGSpeculativeJIT32_64.cpp:
     233        (JSC::DFG::SpeculativeJIT::compile):
     234        * dfg/DFGSpeculativeJIT64.cpp:
     235        (JSC::DFG::SpeculativeJIT::compile):
     236        * jit/JIT.cpp:
     237        (JSC::JIT::privateCompileMainPass):
     238        (JSC::JIT::privateCompileSlowCases):
     239        * jit/JIT.h:
     240        * jit/JITPropertyAccess.cpp:
     241        (JSC::JIT::emit_op_put_global_var_check):
     242        (JSC):
     243        (JSC::JIT::emitSlow_op_put_global_var_check):
     244        * jit/JITPropertyAccess32_64.cpp:
     245        (JSC::JIT::emit_op_put_global_var_check):
     246        (JSC):
     247        (JSC::JIT::emitSlow_op_put_global_var_check):
     248        * jit/JITStubs.cpp:
     249        (JSC::JITThunks::JITThunks):
     250        (JSC::DEFINE_STUB_FUNCTION):
     251        (JSC):
     252        * jit/JITStubs.h:
     253        * llint/LLIntSlowPaths.cpp:
     254        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
     255        (LLInt):
     256        * llint/LLIntSlowPaths.h:
     257        (LLInt):
     258        * llint/LowLevelInterpreter32_64.asm:
     259        * llint/LowLevelInterpreter64.asm:
     260        * runtime/JSObject.cpp:
     261        (JSC::JSObject::removeDirect):
     262        * runtime/JSObject.h:
     263        (JSObject):
     264        * runtime/JSSymbolTableObject.h:
     265        (JSC::symbolTableGet):
     266        (JSC::symbolTablePut):
     267        (JSC::symbolTablePutWithAttributes):
     268        * runtime/SymbolTable.cpp: Added.
     269        (JSC):
     270        (JSC::SymbolTableEntry::copySlow):
     271        (JSC::SymbolTableEntry::freeFatEntrySlow):
     272        (JSC::SymbolTableEntry::couldBeWatched):
     273        (JSC::SymbolTableEntry::attemptToWatch):
     274        (JSC::SymbolTableEntry::addressOfIsWatched):
     275        (JSC::SymbolTableEntry::addWatchpoint):
     276        (JSC::SymbolTableEntry::notifyWriteSlow):
     277        (JSC::SymbolTableEntry::inflateSlow):
     278        * runtime/SymbolTable.h:
     279        (JSC):
     280        (SymbolTableEntry):
     281        (Fast):
     282        (JSC::SymbolTableEntry::Fast::Fast):
     283        (JSC::SymbolTableEntry::Fast::isNull):
     284        (JSC::SymbolTableEntry::Fast::getIndex):
     285        (JSC::SymbolTableEntry::Fast::isReadOnly):
     286        (JSC::SymbolTableEntry::Fast::getAttributes):
     287        (JSC::SymbolTableEntry::Fast::isFat):
     288        (JSC::SymbolTableEntry::SymbolTableEntry):
     289        (JSC::SymbolTableEntry::~SymbolTableEntry):
     290        (JSC::SymbolTableEntry::operator=):
     291        (JSC::SymbolTableEntry::isNull):
     292        (JSC::SymbolTableEntry::getIndex):
     293        (JSC::SymbolTableEntry::getFast):
     294        (JSC::SymbolTableEntry::getAttributes):
     295        (JSC::SymbolTableEntry::isReadOnly):
     296        (JSC::SymbolTableEntry::watchpointSet):
     297        (JSC::SymbolTableEntry::notifyWrite):
     298        (FatEntry):
     299        (JSC::SymbolTableEntry::FatEntry::FatEntry):
     300        (JSC::SymbolTableEntry::isFat):
     301        (JSC::SymbolTableEntry::fatEntry):
     302        (JSC::SymbolTableEntry::inflate):
     303        (JSC::SymbolTableEntry::bits):
     304        (JSC::SymbolTableEntry::freeFatEntry):
     305        (JSC::SymbolTableEntry::pack):
     306        (JSC::SymbolTableEntry::isValidIndex):
     307
    13082012-06-12  Filip Pizlo  <[email protected]>
    2309
  • trunk/Source/JavaScriptCore/GNUmakefile.list.am

    r119981 r120172  
    134134        Source/JavaScriptCore/bytecode/ValueRecovery.h \
    135135        Source/JavaScriptCore/bytecode/VirtualRegister.h \
     136        Source/JavaScriptCore/bytecode/Watchpoint.cpp \
     137        Source/JavaScriptCore/bytecode/Watchpoint.h \
    136138        Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp \
    137139        Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h \
     
    604606        Source/JavaScriptCore/runtime/Structure.h \
    605607        Source/JavaScriptCore/runtime/StructureTransitionTable.h \
     608        Source/JavaScriptCore/runtime/SymbolTable.cpp \
    606609        Source/JavaScriptCore/runtime/SymbolTable.h \
    607610        Source/JavaScriptCore/runtime/Terminator.h \
  • trunk/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def

    r119844 r120172  
    247247    ?neuter@ArrayBufferView@WTF@@MAEXXZ
    248248    ?newUninitialized@CString@WTF@@SA?AV12@IAAPAD@Z
     249    ?notifyWriteSlow@SymbolTableEntry@JSC@@AAEXXZ
    249250    ?nullptr@@3Vnullptr_t@std@@A
    250251    ?number@String@WTF@@SA?AV12@NII@Z
  • trunk/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj

    r119660 r120172  
    12551255                        </File>
    12561256                        <File
     1257                                RelativePath="..\..\runtime\SymbolTable.cpp"
     1258                                >
     1259                        </File>
     1260                        <File
    12571261                                RelativePath="..\..\runtime\SymbolTable.h"
    12581262                                >
     
    16801684                        <File
    16811685                                RelativePath="..\..\bytecode\ValueProfile.h"
     1686                                >
     1687                        </File>
     1688                        <File
     1689                                RelativePath="..\..\bytecode\Watchpoint.cpp"
     1690                                >
     1691                        </File>
     1692                        <File
     1693                                RelativePath="..\..\bytecode\Watchpoint.h"
    16821694                                >
    16831695                        </File>
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r119660 r120172  
    140140                0F919D10157F3329004A4E7D /* JSSegmentedVariableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D0E157F3327004A4E7D /* JSSegmentedVariableObject.cpp */; };
    141141                0F919D11157F332C004A4E7D /* JSSegmentedVariableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F919D0F157F3327004A4E7D /* JSSegmentedVariableObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
     142                0F919D2515853CE0004A4E7D /* Watchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D2215853CDE004A4E7D /* Watchpoint.cpp */; };
     143                0F919D2615853CE3004A4E7D /* Watchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F919D2315853CDE004A4E7D /* Watchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
     144                0F919D2815856773004A4E7D /* SymbolTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D2715856770004A4E7D /* SymbolTable.cpp */; };
    142145                0F93329D14CA7DC30085F3C6 /* CallLinkStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */; };
    143146                0F93329E14CA7DC50085F3C6 /* CallLinkStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    371374                7EFF00640EC05A9A00AA7C93 /* NodeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 7EFF00630EC05A9A00AA7C93 /* NodeInfo.h */; };
    372375                840480131021A1D9008E7F01 /* JSAPIValueWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = BC0894D60FAFBA2D00001865 /* JSAPIValueWrapper.h */; settings = {ATTRIBUTES = (Private, ); }; };
    373                 860161E30F3A83C100F84710 /* AbstractMacroAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161DF0F3A83C100F84710 /* AbstractMacroAssembler.h */; };
    374                 860161E40F3A83C100F84710 /* MacroAssemblerX86.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161E00F3A83C100F84710 /* MacroAssemblerX86.h */; };
    375                 860161E50F3A83C100F84710 /* MacroAssemblerX86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161E10F3A83C100F84710 /* MacroAssemblerX86_64.h */; };
    376                 860161E60F3A83C100F84710 /* MacroAssemblerX86Common.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161E20F3A83C100F84710 /* MacroAssemblerX86Common.h */; };
     376                860161E30F3A83C100F84710 /* AbstractMacroAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161DF0F3A83C100F84710 /* AbstractMacroAssembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
     377                860161E40F3A83C100F84710 /* MacroAssemblerX86.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161E00F3A83C100F84710 /* MacroAssemblerX86.h */; settings = {ATTRIBUTES = (Private, ); }; };
     378                860161E50F3A83C100F84710 /* MacroAssemblerX86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161E10F3A83C100F84710 /* MacroAssemblerX86_64.h */; settings = {ATTRIBUTES = (Private, ); }; };
     379                860161E60F3A83C100F84710 /* MacroAssemblerX86Common.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161E20F3A83C100F84710 /* MacroAssemblerX86Common.h */; settings = {ATTRIBUTES = (Private, ); }; };
    377380                8604F505143CE1C200B295F5 /* JSGlobalThis.h in Headers */ = {isa = PBXBuildFile; fileRef = 8604F503143CE1C100B295F5 /* JSGlobalThis.h */; settings = {ATTRIBUTES = (Private, ); }; };
    378381                860BD801148EA6F200112B2F /* Intrinsic.h in Headers */ = {isa = PBXBuildFile; fileRef = 86BF642A148DB2B5004DE36A /* Intrinsic.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    402405                869EBCB70E8C6D4A008722CC /* ResultType.h in Headers */ = {isa = PBXBuildFile; fileRef = 869EBCB60E8C6D4A008722CC /* ResultType.h */; settings = {ATTRIBUTES = (Private, ); }; };
    403406                86A90ED00EE7D51F00AB350D /* JITArithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86A90ECF0EE7D51F00AB350D /* JITArithmetic.cpp */; };
    404                 86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */; };
    405                 86ADD1460FDDEA980006EEC2 /* MacroAssemblerARMv7.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1440FDDEA980006EEC2 /* MacroAssemblerARMv7.h */; };
     407                86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
     408                86ADD1460FDDEA980006EEC2 /* MacroAssemblerARMv7.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1440FDDEA980006EEC2 /* MacroAssemblerARMv7.h */; settings = {ATTRIBUTES = (Private, ); }; };
    406409                86AE64A8135E5E1C00963012 /* MacroAssemblerSH4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86AE64A5135E5E1C00963012 /* MacroAssemblerSH4.cpp */; };
    407                 86AE64A9135E5E1C00963012 /* MacroAssemblerSH4.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE64A6135E5E1C00963012 /* MacroAssemblerSH4.h */; };
    408                 86AE64AA135E5E1C00963012 /* SH4Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE64A7135E5E1C00963012 /* SH4Assembler.h */; };
     410                86AE64A9135E5E1C00963012 /* MacroAssemblerSH4.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE64A6135E5E1C00963012 /* MacroAssemblerSH4.h */; settings = {ATTRIBUTES = (Private, ); }; };
     411                86AE64AA135E5E1C00963012 /* SH4Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE64A7135E5E1C00963012 /* SH4Assembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
    409412                86AE6C4D136A11E400963012 /* DFGFPRInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE6C4B136A11E400963012 /* DFGFPRInfo.h */; };
    410413                86AE6C4E136A11E400963012 /* DFGGPRInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE6C4C136A11E400963012 /* DFGGPRInfo.h */; };
     
    415418                86C36EEA0EE1289D00B3DF59 /* MacroAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C36EE90EE1289D00B3DF59 /* MacroAssembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
    416419                86C568E011A213EE0007F7F0 /* MacroAssemblerARM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86C568DD11A213EE0007F7F0 /* MacroAssemblerARM.cpp */; };
    417                 86C568E111A213EE0007F7F0 /* MacroAssemblerMIPS.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C568DE11A213EE0007F7F0 /* MacroAssemblerMIPS.h */; };
    418                 86C568E211A213EE0007F7F0 /* MIPSAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C568DF11A213EE0007F7F0 /* MIPSAssembler.h */; };
     420                86C568E111A213EE0007F7F0 /* MacroAssemblerMIPS.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C568DE11A213EE0007F7F0 /* MacroAssemblerMIPS.h */; settings = {ATTRIBUTES = (Private, ); }; };
     421                86C568E211A213EE0007F7F0 /* MIPSAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C568DF11A213EE0007F7F0 /* MIPSAssembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
    419422                86CA032E1038E8440028A609 /* Executable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CA032D1038E8440028A609 /* Executable.cpp */; };
    420423                86CAFEE31035DDE60028A609 /* Executable.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CAFEE21035DDE60028A609 /* Executable.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    424427                86CCEFDE0F413F8900FD7F9E /* JITCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CCEFDD0F413F8900FD7F9E /* JITCode.h */; settings = {ATTRIBUTES = (Private, ); }; };
    425428                86D3B2C310156BDE002865E7 /* ARMAssembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86D3B2BF10156BDE002865E7 /* ARMAssembler.cpp */; };
    426                 86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B2C010156BDE002865E7 /* ARMAssembler.h */; };
    427                 86D3B2C510156BDE002865E7 /* AssemblerBufferWithConstantPool.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B2C110156BDE002865E7 /* AssemblerBufferWithConstantPool.h */; };
    428                 86D3B2C610156BDE002865E7 /* MacroAssemblerARM.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B2C210156BDE002865E7 /* MacroAssemblerARM.h */; };
    429                 86D3B3C310159D7F002865E7 /* LinkBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B3C110159D7F002865E7 /* LinkBuffer.h */; };
    430                 86D3B3C410159D7F002865E7 /* RepatchBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B3C210159D7F002865E7 /* RepatchBuffer.h */; };
     429                86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B2C010156BDE002865E7 /* ARMAssembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
     430                86D3B2C510156BDE002865E7 /* AssemblerBufferWithConstantPool.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B2C110156BDE002865E7 /* AssemblerBufferWithConstantPool.h */; settings = {ATTRIBUTES = (Private, ); }; };
     431                86D3B2C610156BDE002865E7 /* MacroAssemblerARM.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B2C210156BDE002865E7 /* MacroAssemblerARM.h */; settings = {ATTRIBUTES = (Private, ); }; };
     432                86D3B3C310159D7F002865E7 /* LinkBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B3C110159D7F002865E7 /* LinkBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; };
     433                86D3B3C410159D7F002865E7 /* RepatchBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B3C210159D7F002865E7 /* RepatchBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; };
    431434                86DB64640F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86DB64630F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp */; };
    432                 86E116B10FE75AC800B512BC /* CodeLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 86E116B00FE75AC800B512BC /* CodeLocation.h */; };
     435                86E116B10FE75AC800B512BC /* CodeLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 86E116B00FE75AC800B512BC /* CodeLocation.h */; settings = {ATTRIBUTES = (Private, ); }; };
    433436                86E85539111B9968001AF51E /* JSStringBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 86E85538111B9968001AF51E /* JSStringBuilder.h */; };
    434437                86EBF2FF1560F06A008E9222 /* NameConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86EBF2F91560F036008E9222 /* NameConstructor.cpp */; };
     
    476479                960097A60EBABB58007A7297 /* LabelScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 960097A50EBABB58007A7297 /* LabelScope.h */; };
    477480                960626960FB8EC02009798AB /* JITStubCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 960626950FB8EC02009798AB /* JITStubCall.h */; };
    478                 9688CB150ED12B4E001D649F /* AssemblerBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 9688CB130ED12B4E001D649F /* AssemblerBuffer.h */; };
    479                 9688CB160ED12B4E001D649F /* X86Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 9688CB140ED12B4E001D649F /* X86Assembler.h */; };
     481                9688CB150ED12B4E001D649F /* AssemblerBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 9688CB130ED12B4E001D649F /* AssemblerBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; };
     482                9688CB160ED12B4E001D649F /* X86Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 9688CB140ED12B4E001D649F /* X86Assembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
    480483                969A07230ED1CE3300F1F681 /* BytecodeGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 969A07210ED1CE3300F1F681 /* BytecodeGenerator.h */; };
    481484                969A072A0ED1CE6900F1F681 /* Label.h in Headers */ = {isa = PBXBuildFile; fileRef = 969A07270ED1CE6900F1F681 /* Label.h */; };
     
    837840                0F919D0E157F3327004A4E7D /* JSSegmentedVariableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSegmentedVariableObject.cpp; sourceTree = "<group>"; };
    838841                0F919D0F157F3327004A4E7D /* JSSegmentedVariableObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSegmentedVariableObject.h; sourceTree = "<group>"; };
     842                0F919D2215853CDE004A4E7D /* Watchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Watchpoint.cpp; sourceTree = "<group>"; };
     843                0F919D2315853CDE004A4E7D /* Watchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Watchpoint.h; sourceTree = "<group>"; };
     844                0F919D2715856770004A4E7D /* SymbolTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolTable.cpp; sourceTree = "<group>"; };
    839845                0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallLinkStatus.cpp; sourceTree = "<group>"; };
    840846                0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallLinkStatus.h; sourceTree = "<group>"; };
     
    20462052                                7E4EE7080EBB7963005934AA /* StructureChain.h */,
    20472053                                BC9041470EB9250900FE26FA /* StructureTransitionTable.h */,
     2054                                0F919D2715856770004A4E7D /* SymbolTable.cpp */,
    20482055                                14A396A60CD2933100B5B4FF /* SymbolTable.h */,
    20492056                                97F6903A1169DF7F00A6BB46 /* Terminator.h */,
     
    22972304                                0F426A451460CBAB00131F8F /* ValueRecovery.h */,
    22982305                                0F426A461460CBAB00131F8F /* VirtualRegister.h */,
     2306                                0F919D2215853CDE004A4E7D /* Watchpoint.cpp */,
     2307                                0F919D2315853CDE004A4E7D /* Watchpoint.h */,
    22992308                        );
    23002309                        path = bytecode;
     
    26722681                                0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */,
    26732682                                0F919D11157F332C004A4E7D /* JSSegmentedVariableObject.h in Headers */,
     2683                                0F919D2615853CE3004A4E7D /* Watchpoint.h in Headers */,
    26742684                        );
    26752685                        runOnlyForDeploymentPostprocessing = 0;
     
    32463256                                0F919D0C157EE09F004A4E7D /* JSSymbolTableObject.cpp in Sources */,
    32473257                                0F919D10157F3329004A4E7D /* JSSegmentedVariableObject.cpp in Sources */,
     3258                                0F919D2515853CE0004A4E7D /* Watchpoint.cpp in Sources */,
     3259                                0F919D2815856773004A4E7D /* SymbolTable.cpp in Sources */,
    32483260                        );
    32493261                        runOnlyForDeploymentPostprocessing = 0;
  • trunk/Source/JavaScriptCore/Target.pri

    r119660 r120172  
    6363    bytecode/Opcode.cpp \
    6464    bytecode/PolymorphicPutByIdList.cpp \
    65     bytecode/SpeculatedType.cpp \
    6665    bytecode/PutByIdStatus.cpp \
    6766    bytecode/SamplingTool.cpp \
     67    bytecode/SpeculatedType.cpp \
    6868    bytecode/StructureStubInfo.cpp \
     69    bytecode/Watchpoint.cpp \
    6970    bytecompiler/BytecodeGenerator.cpp \
    7071    bytecompiler/NodesCodegen.cpp \
     
    237238    runtime/StructureChain.cpp \
    238239    runtime/Structure.cpp \
     240    runtime/SymbolTable.cpp \
    239241    runtime/TimeoutChecker.cpp \
    240242    runtime/UString.cpp \
  • trunk/Source/JavaScriptCore/assembler/ARMv7Assembler.h

    r118413 r120172  
    484484        Condition m_condition : 16;
    485485    };
     486   
     487    ARMv7Assembler()
     488        : m_indexOfLastWatchpoint(INT_MIN)
     489        , m_indexOfTailOfLastWatchpoint(INT_MIN)
     490    {
     491    }
    486492
    487493private:
     
    18211827        m_formatter.oneWordOp8Imm8(OP_NOP_T1, 0);
    18221828    }
     1829   
     1830    AssemblerLabel labelForWatchpoint()
     1831    {
     1832        AssemblerLabel result = m_formatter.label();
     1833        if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint)
     1834            result = label();
     1835        m_indexOfLastWatchpoint = result.m_offset;
     1836        m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize();
     1837        return result;
     1838    }
    18231839
    18241840    AssemblerLabel label()
    18251841    {
    1826         return m_formatter.label();
     1842        AssemblerLabel result = m_formatter.label();
     1843        while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) {
     1844            nop();
     1845            result = m_formatter.label();
     1846        }
     1847        return result;
    18271848    }
    18281849   
     
    20682089        return reinterpret_cast<void*>(readInt32(where));
    20692090    }
     2091   
     2092    static void replaceWithJump(void* instructionStart, void* to)
     2093    {
     2094        ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1));
     2095        ASSERT(!(bitwise_cast<uintptr_t>(to) & 1));
     2096        uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart) + 2;
     2097       
     2098        // Ensure that we're not in one of those errata-triggering thingies. If we are, then
     2099        // prepend a nop.
     2100        bool spansTwo4K = ((reinterpret_cast<intptr_t>(ptr) & 0xfff) == 0x002);
     2101       
     2102        if (spansTwo4K) {
     2103            ptr[-2] = OP_NOP_T1;
     2104            ptr++;
     2105        }
     2106
     2107        linkJumpT4(ptr, to);
     2108        cacheFlush(ptr - 2, sizeof(uint16_t) * 2);
     2109    }
     2110   
     2111    static ptrdiff_t maxJumpReplacementSize()
     2112    {
     2113        return 6;
     2114    }
    20702115
    20712116    unsigned debugOffset() { return m_formatter.debugOffset(); }
     
    26052650    Vector<LinkRecord> m_jumpsToLink;
    26062651    Vector<int32_t> m_offsets;
     2652    int m_indexOfLastWatchpoint;
     2653    int m_indexOfTailOfLastWatchpoint;
    26072654};
    26082655
  • trunk/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h

    r118413 r120172  
    11/*
    2  * Copyright (C) 2008 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4949class LinkBuffer;
    5050class RepatchBuffer;
     51class Watchpoint;
    5152namespace DFG {
    5253class CorrectableJumpPoint;
     
    7071    // The following types are used as operands to MacroAssembler operations,
    7172    // describing immediate  and memory operands to the instructions to be planted.
    72 
    7373
    7474    enum Scale {
     
    280280        friend class MacroAssemblerCodeRef;
    281281        friend class LinkBuffer;
     282        friend class Watchpoint;
    282283
    283284    public:
     
    560561    }
    561562   
     563    Label watchpointLabel()
     564    {
     565        Label result;
     566        result.m_label = m_assembler.labelForWatchpoint();
     567        return result;
     568    }
     569   
    562570    Label align()
    563571    {
  • trunk/Source/JavaScriptCore/assembler/AssemblerBuffer.h

    r109307 r120172  
    11/*
    2  * Copyright (C) 2008 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2929#if ENABLE(ASSEMBLER)
    3030
     31#include "ExecutableAllocator.h"
    3132#include "JITCompilationEffort.h"
    3233#include "JSGlobalData.h"
    3334#include "stdint.h"
    3435#include <string.h>
    35 #include <jit/ExecutableAllocator.h>
    3636#include <wtf/Assertions.h>
    3737#include <wtf/FastMalloc.h>
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM.h

    r116233 r120172  
    10091009    {
    10101010        return FunctionPtr(reinterpret_cast<void(*)()>(ARMAssembler::readCallTarget(call.dataLocation())));
     1011    }
     1012
     1013    static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
     1014    {
     1015        ASSERT_NOT_REACHED();
     1016    }
     1017   
     1018    static ptrdiff_t maxJumpReplacementSize()
     1019    {
     1020        ASSERT_NOT_REACHED();
     1021        return 0;
    10111022    }
    10121023
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h

    r116233 r120172  
    11871187        m_assembler.nop();
    11881188    }
     1189   
     1190    static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
     1191    {
     1192        ARMv7Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
     1193    }
     1194   
     1195    static ptrdiff_t maxJumpReplacementSize()
     1196    {
     1197        return ARMv7Assembler::maxJumpReplacementSize();
     1198    }
    11891199
    11901200    // Forwards / external control flow operations:
     
    13571367    }
    13581368
     1369    Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
     1370    {
     1371        // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
     1372        move(TrustedImmPtr(address.m_ptr), addressTempRegister);
     1373        load8(Address(addressTempRegister), addressTempRegister);
     1374        return branchTest32(cond, addressTempRegister, mask);
     1375    }
     1376
    13591377    void jump(RegisterID target)
    13601378    {
     
    16801698    ALWAYS_INLINE Jump jump()
    16811699    {
     1700        m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
    16821701        moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
    16831702        return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
     
    16861705    ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond)
    16871706    {
     1707        m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
    16881708        m_assembler.it(cond, true, true);
    16891709        moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h

    r116233 r120172  
    18691869    }
    18701870
     1871    static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
     1872    {
     1873        ASSERT_NOT_REACHED();
     1874    }
     1875   
     1876    static ptrdiff_t maxJumpReplacementSize()
     1877    {
     1878        ASSERT_NOT_REACHED();
     1879        return 0;
     1880    }
     1881
    18711882private:
    18721883    // If m_fixedWidth is true, we will generate a fixed number of instructions.
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h

    r115144 r120172  
    19721972    }
    19731973
     1974    static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
     1975    {
     1976        ASSERT_NOT_REACHED();
     1977    }
     1978   
     1979    static ptrdiff_t maxJumpReplacementSize()
     1980    {
     1981        ASSERT_NOT_REACHED();
     1982        return 0;
     1983    }
     1984
    19741985protected:
    19751986    SH4Assembler::Condition SH4Condition(RelationalCondition cond)
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86.h

    r109038 r120172  
    5252    using MacroAssemblerX86Common::storeDouble;
    5353    using MacroAssemblerX86Common::convertInt32ToDouble;
     54    using MacroAssemblerX86Common::branchTest8;
    5455
    5556    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
     
    165166        m_assembler.movl_i32r(initialValue.asIntptr(), dest);
    166167        return DataLabelPtr(this);
     168    }
     169   
     170    Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
     171    {
     172        ASSERT(mask.m_value >= -128 && mask.m_value <= 255);
     173        if (mask.m_value == -1)
     174            m_assembler.cmpb_im(0, address.m_ptr);
     175        else
     176            m_assembler.testb_im(mask.m_value, address.m_ptr);
     177        return Jump(m_assembler.jCC(x86Condition(cond)));
    167178    }
    168179
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h

    r113930 r120172  
    14071407    {
    14081408        m_assembler.nop();
     1409    }
     1410
     1411    static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
     1412    {
     1413        X86Assembler::replaceWithJump(instructionStart.executableAddress(), destination.executableAddress());
     1414    }
     1415   
     1416    static ptrdiff_t maxJumpReplacementSize()
     1417    {
     1418        return X86Assembler::maxJumpReplacementSize();
    14091419    }
    14101420
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h

    r113930 r120172  
    11/*
    2  * Copyright (C) 2008 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    514514        return MacroAssemblerX86Common::branchTest8(cond, BaseIndex(scratchRegister, address.base, TimesOne), mask);
    515515    }
     516   
     517    Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
     518    {
     519        MacroAssemblerX86Common::move(TrustedImmPtr(address.m_ptr), scratchRegister);
     520        return MacroAssemblerX86Common::branchTest8(cond, Address(scratchRegister), mask);
     521    }
    516522
    517523    static bool supportsFloatingPoint() { return true; }
  • trunk/Source/JavaScriptCore/assembler/X86Assembler.h

    r118413 r120172  
    11/*
    2  * Copyright (C) 2008 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    248248
    249249    X86Assembler()
     250        : m_indexOfLastWatchpoint(INT_MIN)
     251        , m_indexOfTailOfLastWatchpoint(INT_MIN)
    250252    {
    251253    }
     
    799801        m_formatter.immediate8(imm);
    800802    }
     803   
     804#if CPU(X86)
     805    void cmpb_im(int imm, const void* addr)
     806    {
     807        m_formatter.oneByteOp(OP_GROUP1_EbIb, GROUP1_OP_CMP, addr);
     808        m_formatter.immediate8(imm);
     809    }
     810#endif
    801811
    802812    void cmpl_im(int imm, int offset, RegisterID base, RegisterID index, int scale)
     
    948958        m_formatter.immediate8(imm);
    949959    }
     960
     961#if CPU(X86)
     962    void testb_im(int imm, const void* addr)
     963    {
     964        m_formatter.oneByteOp(OP_GROUP3_EbIb, GROUP3_OP_TEST, addr);
     965        m_formatter.immediate8(imm);
     966    }
     967#endif
    950968
    951969    void testl_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale)
     
    17031721        return m_formatter.codeSize();
    17041722    }
     1723   
     1724    AssemblerLabel labelForWatchpoint()
     1725    {
     1726        AssemblerLabel result = m_formatter.label();
     1727        if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint)
     1728            result = label();
     1729        m_indexOfLastWatchpoint = result.m_offset;
     1730        m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize();
     1731        return result;
     1732    }
    17051733
    17061734    AssemblerLabel label()
    17071735    {
    1708         return m_formatter.label();
     1736        AssemblerLabel result = m_formatter.label();
     1737        while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) {
     1738            nop();
     1739            result = m_formatter.label();
     1740        }
     1741        return result;
    17091742    }
    17101743
     
    17881821    }
    17891822
     1823    static void replaceWithJump(void* instructionStart, void* to)
     1824    {
     1825        uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart);
     1826        uint8_t* dstPtr = reinterpret_cast<uint8_t*>(to);
     1827        intptr_t distance = (intptr_t)(dstPtr - (ptr + 5));
     1828        ptr[0] = static_cast<uint8_t>(OP_JMP_rel32);
     1829        *reinterpret_cast<int32_t*>(ptr + 1) = static_cast<int32_t>(distance);
     1830    }
     1831   
     1832    static ptrdiff_t maxJumpReplacementSize()
     1833    {
     1834        return 5;
     1835    }
     1836   
    17901837    static unsigned getCallReturnOffset(AssemblerLabel call)
    17911838    {
     
    23402387        AssemblerBuffer m_buffer;
    23412388    } m_formatter;
     2389    int m_indexOfLastWatchpoint;
     2390    int m_indexOfTailOfLastWatchpoint;
    23422391};
    23432392
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r119660 r120172  
    929929            break;
    930930        }
     931        case op_get_global_var_watchable: {
     932            int r0 = (++it)->u.operand;
     933            WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
     934            dataLog("[%4d] get_global_var_watchable\t %s, g%d(%p)\n", location, registerName(exec, r0).data(), m_globalObject->findRegisterIndex(registerPointer), registerPointer);
     935            it++;
     936            it++;
     937            break;
     938        }
    931939        case op_put_global_var: {
    932940            WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
    933941            int r0 = (++it)->u.operand;
    934942            dataLog("[%4d] put_global_var\t g%d(%p), %s\n", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data());
     943            break;
     944        }
     945        case op_put_global_var_check: {
     946            WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
     947            int r0 = (++it)->u.operand;
     948            dataLog("[%4d] put_global_var_check\t g%d(%p), %s\n", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data());
     949            it++;
     950            it++;
    935951            break;
    936952        }
     
    13071323        case op_call_put_result: {
    13081324            int r0 = (++it)->u.operand;
    1309             dataLog("[%4d] op_call_put_result\t\t %s\n", location, registerName(exec, r0).data());
     1325            dataLog("[%4d] call_put_result\t\t %s\n", location, registerName(exec, r0).data());
    13101326            it++;
    13111327            break;
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.h

    r119779 r120172  
    6363#include "UnconditionalFinalizer.h"
    6464#include "ValueProfile.h"
     65#include "Watchpoint.h"
    6566#include <wtf/RefCountedArray.h>
    6667#include <wtf/FastAllocBase.h>
     
    274275        }
    275276       
    276         void appendOSRExit(const DFG::OSRExit& osrExit)
     277        unsigned appendOSRExit(const DFG::OSRExit& osrExit)
    277278        {
    278279            createDFGDataIfNecessary();
     280            unsigned result = m_dfgData->osrExit.size();
    279281            m_dfgData->osrExit.append(osrExit);
     282            return result;
    280283        }
    281284       
     
    285288        }
    286289       
    287         void appendSpeculationRecovery(const DFG::SpeculationRecovery& recovery)
     290        unsigned appendSpeculationRecovery(const DFG::SpeculationRecovery& recovery)
    288291        {
    289292            createDFGDataIfNecessary();
     293            unsigned result = m_dfgData->speculationRecovery.size();
    290294            m_dfgData->speculationRecovery.append(recovery);
     295            return result;
     296        }
     297       
     298        unsigned appendWatchpoint(const Watchpoint& watchpoint)
     299        {
     300            createDFGDataIfNecessary();
     301            unsigned result = m_dfgData->watchpoints.size();
     302            m_dfgData->watchpoints.append(watchpoint);
     303            return result;
    291304        }
    292305       
     
    305318        }
    306319       
     320        unsigned numberOfWatchpoints()
     321        {
     322            if (!m_dfgData)
     323                return 0;
     324            return m_dfgData->watchpoints.size();
     325        }
     326       
    307327        DFG::OSRExit& osrExit(unsigned index)
    308328        {
     
    313333        {
    314334            return m_dfgData->speculationRecovery[index];
     335        }
     336       
     337        Watchpoint& watchpoint(unsigned index)
     338        {
     339            return m_dfgData->watchpoints[index];
    315340        }
    316341       
     
    12391264            SegmentedVector<DFG::OSRExit, 8> osrExit;
    12401265            Vector<DFG::SpeculationRecovery> speculationRecovery;
     1266            SegmentedVector<Watchpoint, 1, 0> watchpoints;
    12411267            Vector<WeakReferenceTransition> transitions;
    12421268            Vector<WriteBarrier<JSCell> > weakReferences;
  • trunk/Source/JavaScriptCore/bytecode/DFGExitProfile.h

    r118278 r120172  
    4242    ArgumentsEscaped, // We exited because arguments escaped but we didn't expect them to.
    4343    Uncountable, // We exited for none of the above reasons, and we should not count it. Most uses of this should be viewed as a FIXME.
     44    UncountableWatchpoint // We exited because of a watchpoint, which isn't counted because watchpoints do tracking themselves.
    4445};
    4546
     
    5960    case InadequateCoverage:
    6061        return "InadequateCoverage";
     62    case ArgumentsEscaped:
     63        return "ArgumentsEscaped";
     64    case Uncountable:
     65        return "Uncountable";
     66    case UncountableWatchpoint:
     67        return "UncountableWatchpoint";
    6168    default:
    6269        return "Unknown";
     
    7178    case BadType:
    7279    case Uncountable:
     80    case UncountableWatchpoint:
    7381        return false;
    7482    default:
  • trunk/Source/JavaScriptCore/bytecode/Instruction.h

    r119655 r120172  
    194194       
    195195        Instruction(WriteBarrier<Unknown>* registerPointer) { u.registerPointer = registerPointer; }
     196       
     197        Instruction(bool* predicatePointer) { u.predicatePointer = predicatePointer; }
    196198
    197199        union {
     
    206208            ValueProfile* profile;
    207209            void* pointer;
     210            bool* predicatePointer;
    208211        } u;
    209212       
  • trunk/Source/JavaScriptCore/bytecode/Opcode.h

    r118555 r120172  
    101101        macro(op_put_scoped_var, 4) \
    102102        macro(op_get_global_var, 4) /* has value profiling */ \
     103        macro(op_get_global_var_watchable, 5) /* has value profiling */ \
    103104        macro(op_put_global_var, 3) \
     105        macro(op_put_global_var_check, 5) \
    104106        macro(op_resolve_base, 5) /* has value profiling */ \
    105107        macro(op_ensure_property_exists, 3) \
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r119655 r120172  
    149149    case IndexedGlobal:
    150150    case ReadOnlyIndexedGlobal:
     151    case WatchedIndexedGlobal:
    151152    case DynamicIndexedGlobal:
    152153    case DynamicReadOnlyIndexedGlobal:
     
    217218}
    218219
    219 int BytecodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant)
    220 {
     220int BytecodeGenerator::addGlobalVar(
     221    const Identifier& ident, ConstantMode constantMode, FunctionMode functionMode)
     222{
     223    UNUSED_PARAM(functionMode);
    221224    int index = symbolTable().size();
    222     SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
     225    SymbolTableEntry newEntry(index, (constantMode == IsConstant) ? ReadOnly : 0);
     226    if (functionMode == IsFunctionToSpecialize)
     227        newEntry.attemptToWatch();
    223228    SymbolTable::AddResult result = symbolTable().add(ident.impl(), newEntry);
    224     if (!result.isNewEntry)
     229    if (!result.isNewEntry) {
     230        result.iterator->second.notifyWrite();
    225231        index = result.iterator->second.getIndex();
     232    }
    226233    return index;
    227234}
     
    290297    for (size_t i = 0; i < functionStack.size(); ++i) {
    291298        FunctionBodyNode* function = functionStack[i];
    292         globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties.
    293 
     299        bool propertyDidExist =
     300            globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties.
     301       
    294302        JSValue value = JSFunction::create(exec, makeFunction(exec, function), scopeChain);
    295         int index = addGlobalVar(function->ident(), false);
     303        int index = addGlobalVar(
     304            function->ident(), IsVariable,
     305            !propertyDidExist ? IsFunctionToSpecialize : NotFunctionOrNotSpecializable);
    296306        globalObject->registerAt(index).set(*m_globalData, globalObject, value);
    297307    }
     
    300310        if (globalObject->hasProperty(exec, *varStack[i].first))
    301311            continue;
    302         addGlobalVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant);
     312        addGlobalVar(
     313            *varStack[i].first,
     314            (varStack[i].second & DeclarationStacks::IsConstant) ? IsConstant : IsVariable,
     315            NotFunctionOrNotSpecializable);
    303316    }
    304317}
     
    12031216                if (flags & ResolveResult::DynamicFlag)
    12041217                    return ResolveResult::dynamicIndexedGlobalResolve(entry.getIndex(), depth, currentScope, flags);
    1205                 return ResolveResult::indexedGlobalResolve(entry.getIndex(), currentScope, flags);
     1218                return ResolveResult::indexedGlobalResolve(
     1219                    entry.getIndex(), currentScope,
     1220                    flags | (entry.couldBeWatched() ? ResolveResult::WatchedFlag : 0));
    12061221            }
    12071222#if !ASSERT_DISABLED
     
    12971312{
    12981313    if (resolveResult.isStatic())
    1299         return emitGetStaticVar(dst, resolveResult);
     1314        return emitGetStaticVar(dst, resolveResult, property);
    13001315   
    13011316    if (resolveResult.isGlobal() && !shouldAvoidResolveGlobal()) {
     
    13801395        if (resolveResult.isStatic()) {
    13811396            // Directly index the property lookup across multiple scopes.
    1382             emitGetStaticVar(propDst, resolveResult);
     1397            emitGetStaticVar(propDst, resolveResult, property);
    13831398            return baseDst;
    13841399        }
     
    14191434    if (resolveResult.isStatic()) {
    14201435        emitLoad(baseDst, jsUndefined());
    1421         emitGetStaticVar(propDst, resolveResult);
     1436        emitGetStaticVar(propDst, resolveResult, property);
    14221437        return baseDst;
    14231438    }
     
    14371452}
    14381453
    1439 RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult)
     1454RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& identifier)
    14401455{
    14411456    ValueProfile* profile = 0;
     
    14731488        return dst;
    14741489
     1490    case ResolveResult::WatchedIndexedGlobal:
     1491        // Skip the peephole for now. It's not clear that it's profitable given
     1492        // the DFG's capabilities, and the fact that if it's watchable then we
     1493        // don't expect to see any put_global_var's anyway.
     1494        profile = emitProfiledOpcode(op_get_global_var_watchable);
     1495        instructions().append(dst->index());
     1496        instructions().append(resolveResult.registerPointer());
     1497        instructions().append(addConstant(identifier)); // For the benefit of the DFG.
     1498        instructions().append(profile);
     1499        return dst;
     1500
    14751501    default:
    14761502        ASSERT_NOT_REACHED();
     
    14791505}
    14801506
    1481 RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, RegisterID* value)
     1507RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, const Identifier& identifier, RegisterID* value)
    14821508{
    14831509    switch (resolveResult.type()) {
     
    14991525        instructions().append(resolveResult.registerPointer());
    15001526        instructions().append(value->index());
     1527        return value;
     1528       
     1529    case ResolveResult::WatchedIndexedGlobal:
     1530        emitOpcode(op_put_global_var_check);
     1531        instructions().append(resolveResult.registerPointer());
     1532        instructions().append(value->index());
     1533        instructions().append(jsCast<JSGlobalObject*>(resolveResult.globalObject())->symbolTable().get(identifier.impl()).addressOfIsWatched());
     1534        instructions().append(addConstant(identifier));
    15011535        return value;
    15021536
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r119655 r120172  
    112112            ReadOnlyFlag = 0x20,
    113113            // The base object is the global object.
    114             GlobalFlag = 0x40
     114            GlobalFlag = 0x40,
     115            // The property is being watched, so writes should be special.
     116            WatchedFlag = 0x80
    115117        };
    116118        enum Type {
     
    132134            // just index into the global object.
    133135            IndexedGlobal = IndexedFlag | GlobalFlag | StaticFlag,
     136            // Like IndexedGlobal, but the property is being watched.
     137            WatchedIndexedGlobal = IndexedFlag | GlobalFlag | StaticFlag | WatchedFlag,
    134138            // Like IndexedGlobal, but the property is also read-only, like NaN,
    135139            // Infinity, or undefined.
     
    442446        RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); }
    443447
    444         RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&);
    445         RegisterID* emitPutStaticVar(const ResolveResult&, RegisterID* value);
     448        RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&, const Identifier&);
     449        RegisterID* emitPutStaticVar(const ResolveResult&, const Identifier&, RegisterID* value);
    446450
    447451        RegisterID* emitResolve(RegisterID* dst, const ResolveResult&, const Identifier& property);
     
    575579
    576580        // Returns the index of the added var.
    577         int addGlobalVar(const Identifier&, bool isConstant);
     581        enum ConstantMode { IsConstant, IsVariable };
     582        enum FunctionMode { IsFunctionToSpecialize, NotFunctionOrNotSpecializable };
     583        int addGlobalVar(const Identifier&, ConstantMode, FunctionMode);
    578584
    579585        void addParameter(const Identifier&, int parameterIndex);
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r117706 r120172  
    431431        RefPtr<RegisterID> func = generator.newTemporary();
    432432        CallArguments callArguments(generator, m_args);
    433         generator.emitGetStaticVar(func.get(), resolveResult);
     433        generator.emitGetStaticVar(func.get(), resolveResult, m_ident);
    434434        generator.emitLoad(callArguments.thisRegister(), jsUndefined());
    435435        return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
     
    619619
    620620    if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
    621         RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult);
     621        RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult, m_ident);
    622622        RegisterID* oldValue;
    623623        if (dst == generator.ignoredResult()) {
     
    627627            oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
    628628        }
    629         generator.emitPutStaticVar(resolveResult, value.get());
     629        generator.emitPutStaticVar(resolveResult, m_ident, value.get());
    630630        return oldValue;
    631631    }
     
    804804
    805805    if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
    806         RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult);
     806        RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident);
    807807        emitPreIncOrDec(generator, propDst.get(), m_operator);
    808         generator.emitPutStaticVar(resolveResult, propDst.get());
     808        generator.emitPutStaticVar(resolveResult, m_ident, propDst.get());
    809809        return generator.moveToDestinationIfNeeded(dst, propDst.get());
    810810    }
     
    12271227
    12281228    if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
    1229         RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult);
     1229        RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident);
    12301230        RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
    1231         generator.emitPutStaticVar(resolveResult, result);
     1231        generator.emitPutStaticVar(resolveResult, m_ident, result);
    12321232        return result;
    12331233    }
     
    12571257            dst = 0;
    12581258        RegisterID* value = generator.emitNode(dst, m_right);
    1259         generator.emitPutStaticVar(resolveResult, value);
     1259        generator.emitPutStaticVar(resolveResult, m_ident, value);
    12601260        return value;
    12611261    }
     
    13621362
    13631363    if (resolveResult.isStatic())
    1364         return generator.emitPutStaticVar(resolveResult, value.get());
     1364        return generator.emitPutStaticVar(resolveResult, m_ident, value.get());
    13651365   
    13661366    if (generator.codeType() != EvalCode)
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractState.cpp

    r119660 r120172  
    220220    ASSERT(m_block);
    221221    ASSERT(m_isValid);
    222        
     222   
     223    m_didClobber = false;
     224   
    223225    NodeIndex nodeIndex = m_block->at(indexInBlock);
    224226    Node& node = m_graph[nodeIndex];
     
    238240    case GetLocal: {
    239241        VariableAccessData* variableAccessData = node.variableAccessData();
     242        if (variableAccessData->prediction() == SpecNone) {
     243            m_isValid = false;
     244            node.setCanExit(true);
     245            break;
     246        }
    240247        bool canExit = false;
    241         canExit |= variableAccessData->prediction() == SpecNone;
    242248        AbstractValue value = m_variables.operand(variableAccessData->local());
    243249        if (!variableAccessData->isCaptured()) {
     
    14771483        // FIXME: Should be able to propagate the fact that we know what the function is.
    14781484        break;
    1479            
     1485       
    14801486    case PutById:
    14811487    case PutByIdDirect:
     
    14891495        forNode(nodeIndex).makeTop();
    14901496        break;
     1497       
     1498    case GlobalVarWatchpoint:
     1499        node.setCanExit(true);
     1500        break;
    14911501           
    14921502    case PutGlobalVar:
     1503    case PutGlobalVarCheck:
    14931504        node.setCanExit(false);
    14941505        break;
     
    15791590        m_variables.local(i).clobberStructures();
    15801591    m_haveStructures = false;
     1592    m_didClobber = true;
    15811593}
    15821594
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractState.h

    r119660 r120172  
    194194    bool execute(unsigned);
    195195   
     196    // Did the last executed node clobber the world?
     197    bool didClobber() const { return m_didClobber; }
     198   
    196199    // Is the execution state still valid? This will be false if execute() has
    197200    // returned false previously.
     
    275278   
    276279    bool m_isValid;
     280    bool m_didClobber;
    277281   
    278282    BranchDirection m_branchDirection; // This is only set for blocks that end in Branch and that execute to completion (i.e. m_isValid == true).
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r120121 r120172  
    12351235    // an inline candidate?
    12361236    CodeBlock* profiledBlock = executable->profiledCodeBlockFor(kind);
     1237    if (!profiledBlock)
     1238        return false;
     1239   
    12371240    if (!mightInlineFunctionFor(profiledBlock, kind))
    12381241        return false;
     
    22522255            SpeculatedType prediction = getPrediction();
    22532256           
     2257            JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
     2258
    22542259            NodeIndex getGlobalVar = addToGraph(
    22552260                GetGlobalVar,
    2256                 OpInfo(m_inlineStackTop->m_codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)),
     2261                OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)),
    22572262                OpInfo(prediction));
    22582263            set(currentInstruction[1].u.operand, getGlobalVar);
    22592264            NEXT_OPCODE(op_get_global_var);
     2265        }
     2266                   
     2267        case op_get_global_var_watchable: {
     2268            SpeculatedType prediction = getPrediction();
     2269           
     2270            JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
     2271           
     2272            unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
     2273            Identifier identifier = m_codeBlock->identifier(identifierNumber);
     2274            SymbolTableEntry entry = globalObject->symbolTable().get(identifier.impl());
     2275            if (!entry.couldBeWatched()) {
     2276                NodeIndex getGlobalVar = addToGraph(
     2277                    GetGlobalVar,
     2278                    OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)),
     2279                    OpInfo(prediction));
     2280                set(currentInstruction[1].u.operand, getGlobalVar);
     2281                NEXT_OPCODE(op_get_global_var_watchable);
     2282            }
     2283           
     2284            // The watchpoint is still intact! This means that we will get notified if the
     2285            // current value in the global variable changes. So, we can inline that value.
     2286            // Moreover, currently we can assume that this value is a JSFunction*, which
     2287            // implies that it's a cell. This simplifies things, since in general we'd have
     2288            // to use a JSConstant for non-cells and a WeakJSConstant for cells. So instead
     2289            // of having both cases we just assert that the value is a cell.
     2290           
     2291            // NB. If it wasn't for CSE, GlobalVarWatchpoint would have no need for the
     2292            // register pointer. But CSE tracks effects on global variables by comparing
     2293            // register pointers. Because CSE executes multiple times while the backend
     2294            // executes once, we use the following performance trade-off:
     2295            // - The node refers directly to the register pointer to make CSE super cheap.
     2296            // - To perform backend code generation, the node only contains the identifier
     2297            //   number, from which it is possible to get (via a few average-time O(1)
     2298            //   lookups) to the WatchpointSet.
     2299           
     2300            addToGraph(
     2301                GlobalVarWatchpoint,
     2302                OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)),
     2303                OpInfo(identifierNumber));
     2304           
     2305            JSValue specificValue = globalObject->registerAt(entry.getIndex()).get();
     2306            ASSERT(specificValue.isCell());
     2307            set(currentInstruction[1].u.operand,
     2308                addToGraph(WeakJSConstant, OpInfo(specificValue.asCell())));
     2309           
     2310            NEXT_OPCODE(op_get_global_var_watchable);
    22602311        }
    22612312
     
    22672318                value);
    22682319            NEXT_OPCODE(op_put_global_var);
     2320        }
     2321
     2322        case op_put_global_var_check: {
     2323            NodeIndex value = get(currentInstruction[2].u.operand);
     2324            CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock;
     2325            JSGlobalObject* globalObject = codeBlock->globalObject();
     2326            unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[4].u.operand];
     2327            Identifier identifier = m_codeBlock->identifier(identifierNumber);
     2328            SymbolTableEntry entry = globalObject->symbolTable().get(identifier.impl());
     2329            if (!entry.couldBeWatched()) {
     2330                addToGraph(
     2331                    PutGlobalVar,
     2332                    OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)),
     2333                    value);
     2334                NEXT_OPCODE(op_put_global_var_check);
     2335            }
     2336            addToGraph(
     2337                PutGlobalVarCheck,
     2338                OpInfo(codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)),
     2339                OpInfo(identifierNumber),
     2340                value);
     2341            NEXT_OPCODE(op_put_global_var_check);
    22692342        }
    22702343
  • trunk/Source/JavaScriptCore/dfg/DFGCCallHelpers.h

    r119647 r120172  
    9595        addCallArgument(arg2);
    9696    }
     97   
     98    ALWAYS_INLINE void setupArguments(TrustedImmPtr arg1)
     99    {
     100        resetCallArguments();
     101        addCallArgument(arg1);
     102    }
    97103
    98104    ALWAYS_INLINE void setupArgumentsExecState()
     
    434440        setupTwoStubArgs<GPRInfo::argumentGPR0, GPRInfo::argumentGPR1>(arg1, arg2);
    435441    }
     442   
     443    ALWAYS_INLINE void setupArguments(TrustedImmPtr arg1)
     444    {
     445        move(arg1, GPRInfo::argumentGPR0);
     446    }
    436447
    437448    ALWAYS_INLINE void setupArgumentsExecState()
  • trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp

    r119660 r120172  
    218218    }
    219219   
     220    bool globalVarWatchpointElimination(WriteBarrier<Unknown>* registerPointer)
     221    {
     222        for (unsigned i = m_indexInBlock; i--;) {
     223            NodeIndex index = m_currentBlock->at(i);
     224            Node& node = m_graph[index];
     225            switch (node.op()) {
     226            case GlobalVarWatchpoint:
     227                if (node.registerPointer() == registerPointer)
     228                    return true;
     229                break;
     230            case PutGlobalVar:
     231                if (node.registerPointer() == registerPointer)
     232                    return false;
     233                break;
     234            default:
     235                break;
     236            }
     237            if (m_graph.clobbersWorld(index))
     238                break;
     239        }
     240        return false;
     241    }
     242   
    220243    NodeIndex globalVarStoreElimination(WriteBarrier<Unknown>* registerPointer)
    221244    {
     
    227250            switch (node.op()) {
    228251            case PutGlobalVar:
     252            case PutGlobalVarCheck:
    229253                if (node.registerPointer() == registerPointer)
    230254                    return index;
     
    9861010            break;
    9871011           
     1012        case GlobalVarWatchpoint:
     1013            if (globalVarWatchpointElimination(node.registerPointer()))
     1014                eliminate();
     1015            break;
     1016           
    9881017        case PutGlobalVar:
     1018        case PutGlobalVarCheck:
    9891019            if (m_fixpointState == FixpointNotConverged)
    9901020                break;
  • trunk/Source/JavaScriptCore/dfg/DFGCapabilities.h

    r118310 r120172  
    124124    case op_put_by_id_transition_normal:
    125125    case op_get_global_var:
     126    case op_get_global_var_watchable:
    126127    case op_put_global_var:
     128    case op_put_global_var_check:
    127129    case op_jmp:
    128130    case op_loop:
  • trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp

    r119660 r120172  
    5757            if (!block->cfaFoundConstants)
    5858                continue;
     59#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
     60            dataLog("Constant folding considering Block #%u.\n", blockIndex);
     61#endif
    5962            state.beginBasicBlock(block);
    6063            for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
     
    9194                state.execute(indexInBlock);
    9295                if (!node.shouldGenerate()
    93                     || m_graph.clobbersWorld(node)
     96                    || state.didClobber()
    9497                    || node.hasConstant())
    9598                    continue;
  • trunk/Source/JavaScriptCore/dfg/DFGCorrectableJumpPoint.h

    r115141 r120172  
    6565        m_condition = check.m_condition;
    6666#endif
     67    }
     68   
     69    bool isSet()
     70    {
     71        return m_codeOffset != std::numeric_limits<uint32_t>::max();
    6772    }
    6873   
  • trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp

    r117620 r120172  
    4545    for (unsigned i = 0; i < codeBlock()->numberOfOSRExits(); ++i) {
    4646        OSRExit& exit = codeBlock()->osrExit(i);
    47         exit.m_check.initialJump().link(this);
     47        ASSERT(!exit.m_check.isSet() == (exit.m_watchpointIndex != std::numeric_limits<unsigned>::max()));
     48        if (exit.m_watchpointIndex == std::numeric_limits<unsigned>::max())
     49            exit.m_check.initialJump().link(this);
     50        else
     51            codeBlock()->watchpoint(exit.m_watchpointIndex).setDestination(label());
    4852        jitAssertHasValidCallFrame();
    4953        store32(TrustedImm32(i), &globalData()->osrExitIndex);
     
    191195        linkBuffer.link(exit.m_check.lateJump(), target);
    192196        exit.m_check.correctLateJump(linkBuffer);
     197        if (exit.m_watchpointIndex != std::numeric_limits<unsigned>::max())
     198            codeBlock()->watchpoint(exit.m_watchpointIndex).correctLabels(linkBuffer);
    193199    }
    194200   
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r119660 r120172  
    431431    }
    432432   
     433    bool hasIdentifierNumberForCheck()
     434    {
     435        return op() == GlobalVarWatchpoint || op() == PutGlobalVarCheck;
     436    }
     437   
     438    unsigned identifierNumberForCheck()
     439    {
     440        ASSERT(hasIdentifierNumberForCheck());
     441        return m_opInfo2;
     442    }
     443   
    433444    bool hasRegisterPointer()
    434445    {
    435         return op() == GetGlobalVar || op() == PutGlobalVar;
     446        return op() == GetGlobalVar || op() == PutGlobalVar || op() == GlobalVarWatchpoint || op() == PutGlobalVarCheck;
    436447    }
    437448   
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r118579 r120172  
    142142    macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \
    143143    macro(PutGlobalVar, NodeMustGenerate) \
     144    macro(GlobalVarWatchpoint, NodeMustGenerate) \
     145    macro(PutGlobalVarCheck, NodeMustGenerate) \
    144146    macro(CheckFunction, NodeMustGenerate) \
    145147    \
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp

    r118278 r120172  
    5252    , m_codeOriginForExitProfile(m_codeOrigin)
    5353    , m_recoveryIndex(recoveryIndex)
     54    , m_watchpointIndex(std::numeric_limits<unsigned>::max())
    5455    , m_kind(kind)
    5556    , m_count(0)
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExit.h

    r115093 r120172  
    9797   
    9898    unsigned m_recoveryIndex;
     99    unsigned m_watchpointIndex;
    99100   
    100101    ExitKind m_kind;
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r119857 r120172  
    923923{
    924924    return virtualFor(execCallee, CodeForConstruct);
     925}
     926
     927void DFG_OPERATION operationNotifyGlobalVarWrite(WatchpointSet* watchpointSet)
     928{
     929    watchpointSet->notifyWrite();
    925930}
    926931
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r119857 r120172  
    101101typedef void DFG_OPERATION (*V_DFGOperation_EJPP)(ExecState*, EncodedJSValue, EncodedJSValue, void*);
    102102typedef void DFG_OPERATION (*V_DFGOperation_EPZJ)(ExecState*, void*, int32_t, EncodedJSValue);
     103typedef void DFG_OPERATION (*V_DFGOperation_W)(WatchpointSet*);
    103104typedef void* DFG_OPERATION (*P_DFGOperation_E)(ExecState*);
    104105
     
    117118EncodedJSValue DFG_OPERATION operationCallCustomGetter(ExecState*, JSCell*, PropertySlot::GetValueFunc, Identifier*) WTF_INTERNAL;
    118119EncodedJSValue DFG_OPERATION operationCallGetter(ExecState*, JSCell*, JSCell*) WTF_INTERNAL;
     120void DFG_OPERATION operationNotifyGlobalVarWrite(WatchpointSet* watchpointSet) WTF_INTERNAL;
    119121EncodedJSValue DFG_OPERATION operationResolve(ExecState*, Identifier*) WTF_INTERNAL;
    120122EncodedJSValue DFG_OPERATION operationResolveBase(ExecState*, Identifier*) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r119660 r120172  
    492492        }
    493493           
    494         case PutGlobalVar: {
     494        case PutGlobalVar:
     495        case PutGlobalVarCheck: {
    495496            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
    496497            break;
     
    670671        case CheckNumber:
    671672        case CheckArgumentsNotCreated:
     673        case GlobalVarWatchpoint:
    672674            changed |= mergeDefaultFlags(node);
    673675            break;
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r119865 r120172  
    14151415        return appendCallWithExceptionCheck(operation);
    14161416    }
     1417    JITCompiler::Call callOperation(V_DFGOperation_W operation, WatchpointSet* watchpointSet)
     1418    {
     1419        m_jit.setupArguments(TrustedImmPtr(watchpointSet));
     1420        return appendCall(operation);
     1421    }
    14171422    template<typename FunctionType, typename ArgumentType1>
    14181423    JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1)
     
    16731678        return appendCallWithExceptionCheck(operation);
    16741679    }
     1680    JITCompiler::Call callOperation(V_DFGOperation_W operation, WatchpointSet* watchpointSet)
     1681    {
     1682        m_jit.setupArguments(TrustedImmPtr(watchpointSet));
     1683        return appendCall(operation);
     1684    }
    16751685    template<typename FunctionType, typename ArgumentType1>
    16761686    JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1)
     
    17931803        m_jit.move(GPRInfo::returnValueGPR, result);
    17941804        return call;
     1805    }
     1806    JITCompiler::Call appendCall(const FunctionPtr& function)
     1807    {
     1808        prepareForExternalCall();
     1809        return m_jit.appendCall(function);
    17951810    }
    17961811    JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, GPRReg result1, GPRReg result2)
     
    21942209        speculationCheck(kind, jsValueSource, nodeUse.index(), jumpToFail, recovery);
    21952210    }
     2211    // Use this like you would use speculationCheck(), except that you don't pass it a jump
     2212    // (because you don't have to execute a branch; that's kind of the whole point), and you
     2213    // must register the returned Watchpoint with something relevant. In general, this should
     2214    // be used with extreme care. Use speculationCheck() unless you've got an amazing reason
     2215    // not to.
     2216    Watchpoint* speculationWatchpoint(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex)
     2217    {
     2218        if (!m_compileOkay)
     2219            return 0;
     2220        ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
     2221        OSRExit& exit = m_jit.codeBlock()->osrExit(
     2222            m_jit.codeBlock()->appendOSRExit(
     2223                OSRExit(kind, jsValueSource,
     2224                        m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex),
     2225                        JITCompiler::Jump(), this)));
     2226        exit.m_watchpointIndex = m_jit.codeBlock()->appendWatchpoint(
     2227            Watchpoint(m_jit.watchpointLabel()));
     2228        return &m_jit.codeBlock()->watchpoint(exit.m_watchpointIndex);
     2229    }
     2230    // The default for speculation watchpoints is that they're uncounted, because the
     2231    // act of firing a watchpoint invalidates it. So, future recompilations will not
     2232    // attempt to set this watchpoint again.
     2233    Watchpoint* speculationWatchpoint()
     2234    {
     2235        return speculationWatchpoint(UncountableWatchpoint, JSValueSource(), NoNode);
     2236    }
    21962237    void forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::Jump jumpToFail, const ValueRecovery& valueRecovery)
    21972238    {
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r119660 r120172  
    35973597    }
    35983598
     3599    case PutGlobalVarCheck: {
     3600        JSValueOperand value(this, node.child1());
     3601       
     3602        WatchpointSet* watchpointSet =
     3603            m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get(
     3604                identifier(node.identifierNumberForCheck())->impl()).watchpointSet();
     3605        addSlowPathGenerator(
     3606            slowPathCall(
     3607                m_jit.branchTest8(
     3608                    JITCompiler::NonZero,
     3609                    JITCompiler::AbsoluteAddress(watchpointSet->addressOfIsWatched())),
     3610                this, operationNotifyGlobalVarWrite, NoResult, watchpointSet));
     3611       
     3612        if (Heap::isWriteBarrierEnabled()) {
     3613            GPRTemporary scratch(this);
     3614            GPRReg scratchReg = scratch.gpr();
     3615           
     3616            writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.tagGPR(), node.child1(), WriteBarrierForVariableAccess, scratchReg);
     3617        }
     3618
     3619        // FIXME: if we happen to have a spare register - and _ONLY_ if we happen to have
     3620        // a spare register - a good optimization would be to put the register pointer into
     3621        // a register and then do a zero offset store followed by a four-offset store (or
     3622        // vice-versa depending on endianness).
     3623        m_jit.store32(value.tagGPR(), node.registerPointer()->tagPointer());
     3624        m_jit.store32(value.payloadGPR(), node.registerPointer()->payloadPointer());
     3625
     3626        noResult(m_compileIndex);
     3627        break;
     3628    }
     3629       
     3630    case GlobalVarWatchpoint: {
     3631        m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get(
     3632            identifier(node.identifierNumberForCheck())->impl()).addWatchpoint(
     3633                speculationWatchpoint());
     3634       
     3635#if DFG_ENABLE(JIT_ASSERT)
     3636        GPRTemporary scratch(this);
     3637        GPRReg scratchGPR = scratch.gpr();
     3638        m_jit.load32(node.registerPointer()->tagPointer(), scratchGPR);
     3639        JITCompiler::Jump notOK = m_jit.branch32(
     3640            JITCompiler::NotEqual, scratchGPR,
     3641            TrustedImm32(node.registerPointer()->get().tag()));
     3642        m_jit.load32(node.registerPointer()->payloadPointer(), scratchGPR);
     3643        JITCompiler::Jump ok = m_jit.branch32(
     3644            JITCompiler::Equal, scratchGPR,
     3645            TrustedImm32(node.registerPointer()->get().payload()));
     3646        notOK.link(&m_jit);
     3647        m_jit.breakpoint();
     3648        ok.link(&m_jit);
     3649#endif
     3650       
     3651        noResult(m_compileIndex);
     3652        break;
     3653    }
     3654
    35993655    case CheckHasInstance: {
    36003656        SpeculateCellOperand base(this, node.child1());
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r119660 r120172  
    36163616    }
    36173617
     3618    case PutGlobalVarCheck: {
     3619        JSValueOperand value(this, node.child1());
     3620       
     3621        WatchpointSet* watchpointSet =
     3622            m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get(
     3623                identifier(node.identifierNumberForCheck())->impl()).watchpointSet();
     3624        addSlowPathGenerator(
     3625            slowPathCall(
     3626                m_jit.branchTest8(
     3627                    JITCompiler::NonZero,
     3628                    JITCompiler::AbsoluteAddress(watchpointSet->addressOfIsWatched())),
     3629                this, operationNotifyGlobalVarWrite, NoResult, watchpointSet));
     3630       
     3631        if (Heap::isWriteBarrierEnabled()) {
     3632            GPRTemporary scratch(this);
     3633            GPRReg scratchReg = scratch.gpr();
     3634           
     3635            writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.gpr(), node.child1(), WriteBarrierForVariableAccess, scratchReg);
     3636        }
     3637       
     3638        m_jit.storePtr(value.gpr(), node.registerPointer());
     3639
     3640        noResult(m_compileIndex);
     3641        break;
     3642    }
     3643       
     3644    case GlobalVarWatchpoint: {
     3645        m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get(
     3646            identifier(node.identifierNumberForCheck())->impl()).addWatchpoint(
     3647                speculationWatchpoint());
     3648       
     3649#if DFG_ENABLE(JIT_ASSERT)
     3650        GPRTemporary scratch(this);
     3651        GPRReg scratchGPR = scratch.gpr();
     3652        m_jit.loadPtr(node.registerPointer(), scratchGPR);
     3653        JITCompiler::Jump ok = m_jit.branchPtr(
     3654            JITCompiler::Equal, scratchGPR,
     3655            TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(node.registerPointer()->get()))));
     3656        m_jit.breakpoint();
     3657        ok.link(&m_jit);
     3658#endif
     3659       
     3660        noResult(m_compileIndex);
     3661        break;
     3662    }
     3663
    36183664    case CheckHasInstance: {
    36193665        SpeculateCellOperand base(this, node.child1());
  • trunk/Source/JavaScriptCore/jit/JIT.cpp

    r118270 r120172  
    260260        DEFINE_OP(op_get_argument_by_val)
    261261        DEFINE_OP(op_get_by_pname)
     262        DEFINE_OP(op_get_global_var_watchable)
    262263        DEFINE_OP(op_get_global_var)
    263264        DEFINE_OP(op_get_pnames)
     
    325326        DEFINE_OP(op_put_getter_setter)
    326327        DEFINE_OP(op_put_global_var)
     328        DEFINE_OP(op_put_global_var_check)
    327329        DEFINE_OP(op_put_scoped_var)
    328330        DEFINE_OP(op_resolve)
     
    482484        DEFINE_SLOWCASE_OP(op_put_by_id)
    483485        DEFINE_SLOWCASE_OP(op_put_by_val)
     486        DEFINE_SLOWCASE_OP(op_put_global_var_check);
    484487        DEFINE_SLOWCASE_OP(op_resolve_global)
    485488        DEFINE_SLOWCASE_OP(op_resolve_global_dynamic)
  • trunk/Source/JavaScriptCore/jit/JIT.h

    r118270 r120172  
    464464        bool getMappedPayload(int virtualRegisterIndex, RegisterID& payload);
    465465        bool getMappedTag(int virtualRegisterIndex, RegisterID& tag);
    466 
     466       
    467467        void emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex);
    468468        void emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex, RegisterID tag);
     
    600600        void emit_op_get_by_pname(Instruction*);
    601601        void emit_op_get_global_var(Instruction*);
     602        void emit_op_get_global_var_watchable(Instruction* instruction) { emit_op_get_global_var(instruction); }
    602603        void emit_op_get_scoped_var(Instruction*);
    603604        void emit_op_init_lazy_reg(Instruction*);
     
    663664        void emit_op_put_getter_setter(Instruction*);
    664665        void emit_op_put_global_var(Instruction*);
     666        void emit_op_put_global_var_check(Instruction*);
    665667        void emit_op_put_scoped_var(Instruction*);
    666668        void emit_op_resolve(Instruction*);
     
    740742        void emitSlow_op_put_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&);
    741743        void emitSlow_op_put_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&);
     744        void emitSlow_op_put_global_var_check(Instruction*, Vector<SlowCaseEntry>::iterator&);
    742745        void emitSlow_op_resolve_global(Instruction*, Vector<SlowCaseEntry>::iterator&);
    743746        void emitSlow_op_resolve_global_dynamic(Instruction*, Vector<SlowCaseEntry>::iterator&);
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp

    r119655 r120172  
    10281028}
    10291029
     1030void JIT::emit_op_put_global_var_check(Instruction* currentInstruction)
     1031{
     1032    emitGetVirtualRegister(currentInstruction[2].u.operand, regT0);
     1033   
     1034    addSlowCase(branchTest8(NonZero, AbsoluteAddress(currentInstruction[3].u.predicatePointer)));
     1035
     1036    JSGlobalObject* globalObject = m_codeBlock->globalObject();
     1037   
     1038    storePtr(regT0, currentInstruction[1].u.registerPointer);
     1039    if (Heap::isWriteBarrierEnabled())
     1040        emitWriteBarrier(globalObject, regT0, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess);
     1041}
     1042
     1043void JIT::emitSlow_op_put_global_var_check(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     1044{
     1045    linkSlowCase(iter);
     1046   
     1047    JITStubCall stubCall(this, cti_op_put_global_var_check);
     1048    stubCall.addArgument(regT0);
     1049    stubCall.addArgument(TrustedImm32(currentInstruction[4].u.operand));
     1050    stubCall.call();
     1051}
     1052
    10301053void JIT::resetPatchGetById(RepatchBuffer& repatchBuffer, StructureStubInfo* stubInfo)
    10311054{
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp

    r119655 r120172  
    10911091}
    10921092
     1093void JIT::emit_op_put_global_var_check(Instruction* currentInstruction)
     1094{
     1095    WriteBarrier<Unknown>* registerPointer = currentInstruction[1].u.registerPointer;
     1096    int value = currentInstruction[2].u.operand;
     1097   
     1098    JSGlobalObject* globalObject = m_codeBlock->globalObject();
     1099   
     1100    emitLoad(value, regT1, regT0);
     1101   
     1102    addSlowCase(branchTest8(NonZero, AbsoluteAddress(currentInstruction[3].u.predicatePointer)));
     1103   
     1104    if (Heap::isWriteBarrierEnabled()) {
     1105        move(TrustedImmPtr(globalObject), regT2);
     1106        emitWriteBarrier(globalObject, regT1, regT3, ShouldFilterImmediates, WriteBarrierForVariableAccess);
     1107    }
     1108   
     1109    store32(regT1, registerPointer->tagPointer());
     1110    store32(regT0, registerPointer->payloadPointer());
     1111    unmap();
     1112}
     1113
     1114void JIT::emitSlow_op_put_global_var_check(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     1115{
     1116    linkSlowCase(iter);
     1117   
     1118    JITStubCall stubCall(this, cti_op_put_global_var_check);
     1119    stubCall.addArgument(regT1, regT0);
     1120    stubCall.addArgument(TrustedImm32(currentInstruction[4].u.operand));
     1121    stubCall.call();
     1122}
     1123
    10931124void JIT::resetPatchGetById(RepatchBuffer& repatchBuffer, StructureStubInfo* stubInfo)
    10941125{
  • trunk/Source/JavaScriptCore/jit/JITStubs.cpp

    r120159 r120172  
    23782378}
    23792379
     2380DEFINE_STUB_FUNCTION(void, op_put_global_var_check)
     2381{
     2382    STUB_INIT_STACK_FRAME(stackFrame);
     2383   
     2384    CallFrame* callFrame = stackFrame.callFrame;
     2385    CodeBlock* codeBlock = callFrame->codeBlock();
     2386    symbolTablePut(codeBlock->globalObject(), callFrame, codeBlock->identifier(stackFrame.args[1].int32()), stackFrame.args[0].jsValue(), true);
     2387}
     2388
    23802389DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve)
    23812390{
  • trunk/Source/JavaScriptCore/jit/JITStubs.h

    r119857 r120172  
    446446    void JIT_STUB cti_op_put_by_val(STUB_ARGS_DECLARATION) WTF_INTERNAL;
    447447    void JIT_STUB cti_op_put_getter_setter(STUB_ARGS_DECLARATION) WTF_INTERNAL;
     448    void JIT_STUB cti_op_put_global_var_check(STUB_ARGS_DECLARATION) WTF_INTERNAL;
    448449    void JIT_STUB cti_op_tear_off_activation(STUB_ARGS_DECLARATION) WTF_INTERNAL;
    449450    void JIT_STUB cti_op_tear_off_arguments(STUB_ARGS_DECLARATION) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp

    r119602 r120172  
    854854    LLINT_OP(2) = result;
    855855    // FIXME: technically should have profiling, but we don't do it because the DFG won't use it.
     856    LLINT_END();
     857}
     858
     859LLINT_SLOW_PATH_DECL(slow_path_put_global_var_check)
     860{
     861    LLINT_BEGIN();
     862    CodeBlock* codeBlock = exec->codeBlock();
     863    symbolTablePut(codeBlock->globalObject(), exec, codeBlock->identifier(pc[4].u.operand), LLINT_OP_C(2).jsValue(), true);
    856864    LLINT_END();
    857865}
  • trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.h

    r119857 r120172  
    148148LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_with_base);
    149149LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_with_this);
     150LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_global_var_check);
    150151LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id);
    151152LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_arguments_length);
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm

    r119655 r120172  
    10401040
    10411041
    1042 _llint_op_get_global_var:
     1042macro getGlobalVar(size)
    10431043    traceExecution()
    10441044    loadp 8[PC], t0
     
    10481048    storei t2, TagOffset[cfr, t3, 8]
    10491049    storei t1, PayloadOffset[cfr, t3, 8]
    1050     loadi 12[PC], t3
     1050    loadi (size - 1) * 4[PC], t3
    10511051    valueProfile(t2, t1, t3)
    1052     dispatch(4)
     1052    dispatch(size)
     1053end
     1054
     1055_llint_op_get_global_var:
     1056    getGlobalVar(4)
     1057
     1058
     1059_llint_op_get_global_var_watchable:
     1060    getGlobalVar(5)
    10531061
    10541062
     
    10621070    storei t3, PayloadOffset[t0]
    10631071    dispatch(3)
     1072
     1073
     1074_llint_op_put_global_var_check:
     1075    traceExecution()
     1076    loadp 12[PC], t2
     1077    loadi 8[PC], t1
     1078    loadi 4[PC], t0
     1079    btbnz [t2], .opPutGlobalVarCheckSlow
     1080    loadConstantOrVariable(t1, t2, t3)
     1081    writeBarrier(t2, t3)
     1082    storei t2, TagOffset[t0]
     1083    storei t3, PayloadOffset[t0]
     1084    dispatch(5)
     1085.opPutGlobalVarCheckSlow:
     1086    callSlowPath(_llint_slow_path_put_global_var_check)
     1087    dispatch(5)
    10641088
    10651089
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r119655 r120172  
    894894
    895895
    896 _llint_op_get_global_var:
     896macro getGlobalVar(size)
    897897    traceExecution()
    898898    loadp 16[PB, PC, 8], t0
     
    900900    loadp [t0], t1
    901901    storep t1, [cfr, t3, 8]
    902     loadp 24[PB, PC, 8], t0
     902    loadp (size - 1) * 8[PB, PC, 8], t0
    903903    valueProfile(t1, t0)
    904     dispatch(4)
     904    dispatch(size)
     905end
     906
     907_llint_op_get_global_var:
     908    getGlobalVar(4)
     909
     910
     911_llint_op_get_global_var_watchable:
     912    getGlobalVar(5)
    905913
    906914
     
    913921    storep t2, [t0]
    914922    dispatch(3)
     923
     924
     925_llint_op_put_global_var_check:
     926    traceExecution()
     927    loadp 24[PB, PC, 8], t2
     928    loadis 16[PB, PC, 8], t1
     929    loadp 8[PB, PC, 8], t0
     930    btbnz [t2], .opPutGlobalVarCheckSlow
     931    loadConstantOrVariable(t1, t2)
     932    writeBarrier(t2)
     933    storep t2, [t0]
     934    dispatch(5)
     935.opPutGlobalVarCheckSlow:
     936    callSlowPath(_llint_slow_path_put_global_var_check)
     937    dispatch(5)
    915938
    916939
  • trunk/Source/JavaScriptCore/runtime/JSObject.cpp

    r120045 r120172  
    505505}
    506506
    507 void JSObject::removeDirect(JSGlobalData& globalData, PropertyName propertyName)
     507bool JSObject::removeDirect(JSGlobalData& globalData, PropertyName propertyName)
    508508{
    509509    if (structure()->get(globalData, propertyName) == WTF::notFound)
    510         return;
     510        return false;
    511511
    512512    size_t offset;
    513513    if (structure()->isUncacheableDictionary()) {
    514514        offset = structure()->removePropertyWithoutTransition(globalData, propertyName);
    515         if (offset != WTF::notFound)
    516             putUndefinedAtDirectOffset(offset);
    517         return;
     515        if (offset == WTF::notFound)
     516            return false;
     517        putUndefinedAtDirectOffset(offset);
     518        return true;
    518519    }
    519520
    520521    setStructure(globalData, Structure::removePropertyTransition(globalData, structure(), propertyName, offset));
    521     if (offset != WTF::notFound)
    522         putUndefinedAtDirectOffset(offset);
     522    if (offset == WTF::notFound)
     523        return false;
     524    putUndefinedAtDirectOffset(offset);
     525    return true;
    523526}
    524527
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r119865 r120172  
    177177        void transitionTo(JSGlobalData&, Structure*);
    178178
    179         void removeDirect(JSGlobalData&, PropertyName);
     179        bool removeDirect(JSGlobalData&, PropertyName); // Return true if anything is removed.
    180180        bool hasCustomProperties() { return structure()->didTransition(); }
    181181        bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); }
  • trunk/Source/JavaScriptCore/runtime/JSSymbolTableObject.h

    r119655 r120172  
    7373    SymbolTableObjectType* object, PropertyName propertyName, PropertySlot& slot)
    7474{
    75     SymbolTableEntry entry = object->symbolTable().inlineGet(propertyName.publicName());
    76     if (entry.isNull())
     75    SymbolTable& symbolTable = object->symbolTable();
     76    SymbolTable::iterator iter = symbolTable.find(propertyName.publicName());
     77    if (iter == symbolTable.end())
    7778        return false;
     79    SymbolTableEntry::Fast entry = iter->second;
     80    ASSERT(!entry.isNull());
    7881    slot.setValue(object->registerAt(entry.getIndex()).get());
    7982    return true;
     
    8487    SymbolTableObjectType* object, PropertyName propertyName, PropertyDescriptor& descriptor)
    8588{
    86     SymbolTableEntry entry = object->symbolTable().inlineGet(propertyName.publicName());
    87     if (entry.isNull())
     89    SymbolTable& symbolTable = object->symbolTable();
     90    SymbolTable::iterator iter = symbolTable.find(propertyName.publicName());
     91    if (iter == symbolTable.end())
    8892        return false;
     93    SymbolTableEntry::Fast entry = iter->second;
     94    ASSERT(!entry.isNull());
    8995    descriptor.setDescriptor(
    9096        object->registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete);
     
    97103    bool& slotIsWriteable)
    98104{
    99     SymbolTableEntry entry = object->symbolTable().inlineGet(propertyName.publicName());
    100     if (entry.isNull())
     105    SymbolTable& symbolTable = object->symbolTable();
     106    SymbolTable::iterator iter = symbolTable.find(propertyName.publicName());
     107    if (iter == symbolTable.end())
    101108        return false;
     109    SymbolTableEntry::Fast entry = iter->second;
     110    ASSERT(!entry.isNull());
    102111    slot.setValue(object->registerAt(entry.getIndex()).get());
    103112    slotIsWriteable = !entry.isReadOnly();
     
    113122    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object));
    114123   
    115     SymbolTableEntry entry = object->symbolTable().inlineGet(propertyName.publicName());
    116     if (entry.isNull())
     124    SymbolTable& symbolTable = object->symbolTable();
     125    SymbolTable::iterator iter = symbolTable.find(propertyName.publicName());
     126    if (iter == symbolTable.end())
    117127        return false;
    118     if (entry.isReadOnly()) {
     128    bool wasFat;
     129    SymbolTableEntry::Fast fastEntry = iter->second.getFast(wasFat);
     130    ASSERT(!fastEntry.isNull());
     131    if (fastEntry.isReadOnly()) {
    119132        if (shouldThrow)
    120133            throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
    121134        return true;
    122135    }
    123     object->registerAt(entry.getIndex()).set(globalData, object, value);
     136    if (UNLIKELY(wasFat))
     137        iter->second.notifyWrite();
     138    object->registerAt(fastEntry.getIndex()).set(globalData, object, value);
    124139    return true;
    125140}
     
    137152    SymbolTableEntry& entry = iter->second;
    138153    ASSERT(!entry.isNull());
     154    entry.notifyWrite();
    139155    entry.setAttributes(attributes);
    140156    object->registerAt(entry.getIndex()).set(globalData, object, value);
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.h

    r109268 r120172  
    11/*
    2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
     2 * Copyright (C) 2007, 2008, 2012 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3232#include "JSObject.h"
    3333#include "UString.h"
     34#include "Watchpoint.h"
    3435#include <wtf/AlwaysInline.h>
    3536#include <wtf/HashTraits.h>
    3637
    3738namespace JSC {
     39
     40    class Watchpoint;
     41    class WatchpointSet;
    3842
    3943    static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); }
     
    4347    // four bits all set or all unset.
    4448
     49    // In addition to implementing semantics-mandated variable attributes and
     50    // implementation-mandated variable indexing, this class also implements
     51    // watchpoints to be used for JIT optimizations. Because watchpoints are
     52    // meant to be relatively rare, this class optimizes heavily for the case
     53    // that they are not being used. To that end, this class uses the thin-fat
     54    // idiom: either it is thin, in which case it contains an in-place encoded
     55    // word that consists of attributes, the index, and a bit saying that it is
     56    // thin; or it is fat, in which case it contains a pointer to a malloc'd
     57    // data structure and a bit saying that it is fat. The malloc'd data
     58    // structure will be malloced a second time upon copy, to preserve the
     59    // property that in-place edits to SymbolTableEntry do not manifest in any
     60    // copies. However, the malloc'd FatEntry data structure contains a ref-
     61    // counted pointer to a shared WatchpointSet. Thus, in-place edits of the
     62    // WatchpointSet will manifest in all copies. Here's a picture:
     63    //
     64    // SymbolTableEntry --> FatEntry --> WatchpointSet
     65    //
     66    // If you make a copy of a SymbolTableEntry, you will have:
     67    //
     68    // original: SymbolTableEntry --> FatEntry --> WatchpointSet
     69    // copy:     SymbolTableEntry --> FatEntry -----^
     70
    4571    struct SymbolTableEntry {
     72        // Use the SymbolTableEntry::Fast class, either via implicit cast or by calling
     73        // getFast(), when you (1) only care about isNull(), getIndex(), and isReadOnly(),
     74        // and (2) you are in a hot path where you need to minimize the number of times
     75        // that you branch on isFat() when getting the bits().
     76        class Fast {
     77        public:
     78            Fast()
     79                : m_bits(0)
     80            {
     81            }
     82           
     83            ALWAYS_INLINE Fast(const SymbolTableEntry& entry)
     84                : m_bits(entry.bits())
     85            {
     86            }
     87       
     88            bool isNull() const
     89            {
     90                return !m_bits;
     91            }
     92
     93            int getIndex() const
     94            {
     95                return static_cast<int>(m_bits >> FlagBits);
     96            }
     97       
     98            bool isReadOnly() const
     99            {
     100                return m_bits & ReadOnlyFlag;
     101            }
     102           
     103            unsigned getAttributes() const
     104            {
     105                unsigned attributes = 0;
     106                if (m_bits & ReadOnlyFlag)
     107                    attributes |= ReadOnly;
     108                if (m_bits & DontEnumFlag)
     109                    attributes |= DontEnum;
     110                return attributes;
     111            }
     112
     113            bool isFat() const
     114            {
     115                return m_bits & FatFlag;
     116            }
     117           
     118        private:
     119            friend struct SymbolTableEntry;
     120            intptr_t m_bits;
     121        };
     122
    46123        SymbolTableEntry()
    47124            : m_bits(0)
     
    50127
    51128        SymbolTableEntry(int index)
     129            : m_bits(0)
    52130        {
    53131            ASSERT(isValidIndex(index));
     
    56134
    57135        SymbolTableEntry(int index, unsigned attributes)
     136            : m_bits(0)
    58137        {
    59138            ASSERT(isValidIndex(index));
     
    61140        }
    62141       
     142        ~SymbolTableEntry()
     143        {
     144            freeFatEntry();
     145        }
     146       
     147        SymbolTableEntry(const SymbolTableEntry& other)
     148            : m_bits(0)
     149        {
     150            *this = other;
     151        }
     152       
     153        SymbolTableEntry& operator=(const SymbolTableEntry& other)
     154        {
     155            if (UNLIKELY(other.isFat()))
     156                return copySlow(other);
     157            freeFatEntry();
     158            m_bits = other.m_bits;
     159            return *this;
     160        }
     161       
    63162        bool isNull() const
    64163        {
    65             return !m_bits;
     164            return !bits();
    66165        }
    67166
    68167        int getIndex() const
    69168        {
    70             return m_bits >> FlagBits;
    71         }
    72 
     169            return static_cast<int>(bits() >> FlagBits);
     170        }
     171       
     172        ALWAYS_INLINE Fast getFast() const
     173        {
     174            return Fast(*this);
     175        }
     176       
     177        ALWAYS_INLINE Fast getFast(bool& wasFat) const
     178        {
     179            Fast result;
     180            wasFat = isFat();
     181            if (wasFat)
     182                result.m_bits = fatEntry()->m_bits;
     183            else
     184                result.m_bits = m_bits;
     185            return result;
     186        }
     187       
    73188        unsigned getAttributes() const
    74189        {
    75             unsigned attributes = 0;
    76             if (m_bits & ReadOnlyFlag)
    77                 attributes |= ReadOnly;
    78             if (m_bits & DontEnumFlag)
    79                 attributes |= DontEnum;
    80             return attributes;
     190            return getFast().getAttributes();
    81191        }
    82192
     
    88198        bool isReadOnly() const
    89199        {
    90             return m_bits & ReadOnlyFlag;
    91         }
    92 
     200            return bits() & ReadOnlyFlag;
     201        }
     202       
     203        bool couldBeWatched();
     204       
     205        // Notify an opportunity to create a watchpoint for a variable. This is
     206        // idempotent and fail-silent. It is idempotent in the sense that if
     207        // a watchpoint set had already been created, then another one will not
     208        // be created. Hence two calls to this method have the same effect as
     209        // one call. It is also fail-silent, in the sense that if a watchpoint
     210        // set had been created and had already been invalidated, then this will
     211        // just return. This means that couldBeWatched() may return false even
     212        // immediately after a call to attemptToWatch().
     213        void attemptToWatch();
     214       
     215        bool* addressOfIsWatched();
     216       
     217        void addWatchpoint(Watchpoint*);
     218       
     219        WatchpointSet* watchpointSet()
     220        {
     221            return fatEntry()->m_watchpoints.get();
     222        }
     223       
     224        ALWAYS_INLINE void notifyWrite()
     225        {
     226            if (LIKELY(!isFat()))
     227                return;
     228            notifyWriteSlow();
     229        }
     230       
    93231    private:
    94         static const unsigned ReadOnlyFlag = 0x1;
    95         static const unsigned DontEnumFlag = 0x2;
    96         static const unsigned NotNullFlag = 0x4;
    97         static const unsigned FlagBits = 3;
     232        static const intptr_t FatFlag = 0x1;
     233        static const intptr_t ReadOnlyFlag = 0x2;
     234        static const intptr_t DontEnumFlag = 0x4;
     235        static const intptr_t NotNullFlag = 0x8;
     236        static const intptr_t FlagBits = 4;
     237       
     238        class FatEntry {
     239            WTF_MAKE_FAST_ALLOCATED;
     240        public:
     241            FatEntry(intptr_t bits)
     242                : m_bits(bits | FatFlag)
     243            {
     244            }
     245           
     246            intptr_t m_bits; // always has FatFlag set and exactly matches what the bits would have been if this wasn't fat.
     247           
     248            RefPtr<WatchpointSet> m_watchpoints;
     249        };
     250       
     251        SymbolTableEntry& copySlow(const SymbolTableEntry&);
     252        JS_EXPORT_PRIVATE void notifyWriteSlow();
     253       
     254        bool isFat() const
     255        {
     256            return m_bits & FatFlag;
     257        }
     258       
     259        const FatEntry* fatEntry() const
     260        {
     261            ASSERT(isFat());
     262            return bitwise_cast<const FatEntry*>(m_bits & ~FatFlag);
     263        }
     264       
     265        FatEntry* fatEntry()
     266        {
     267            ASSERT(isFat());
     268            return bitwise_cast<FatEntry*>(m_bits & ~FatFlag);
     269        }
     270       
     271        FatEntry* inflate()
     272        {
     273            if (LIKELY(isFat()))
     274                return fatEntry();
     275            return inflateSlow();
     276        }
     277       
     278        FatEntry* inflateSlow();
     279       
     280        ALWAYS_INLINE intptr_t bits() const
     281        {
     282            if (isFat())
     283                return fatEntry()->m_bits;
     284            return m_bits;
     285        }
     286       
     287        ALWAYS_INLINE intptr_t& bits()
     288        {
     289            if (isFat())
     290                return fatEntry()->m_bits;
     291            return m_bits;
     292        }
     293       
     294        void freeFatEntry()
     295        {
     296            if (LIKELY(!isFat()))
     297                return;
     298            freeFatEntrySlow();
     299        }
     300       
     301        void freeFatEntrySlow();
    98302
    99303        void pack(int index, bool readOnly, bool dontEnum)
    100304        {
    101             m_bits = (index << FlagBits) | NotNullFlag;
     305            intptr_t& bitsRef = bits();
     306            bitsRef = (static_cast<intptr_t>(index) << FlagBits) | NotNullFlag;
    102307            if (readOnly)
    103                 m_bits |= ReadOnlyFlag;
     308                bitsRef |= ReadOnlyFlag;
    104309            if (dontEnum)
    105                 m_bits |= DontEnumFlag;
     310                bitsRef |= DontEnumFlag;
    106311        }
    107312       
    108313        bool isValidIndex(int index)
    109314        {
    110             return ((index << FlagBits) >> FlagBits) == index;
    111         }
    112 
    113         int m_bits;
     315            return ((static_cast<intptr_t>(index) << FlagBits) >> FlagBits) == static_cast<intptr_t>(index);
     316        }
     317
     318        intptr_t m_bits;
    114319    };
    115320
  • trunk/Source/WTF/ChangeLog

    r120153 r120172  
     12012-06-10  Filip Pizlo  <[email protected]>
     2
     3        DFG should be able to set watchpoints on global variables
     4        https://bugs.webkit.org/show_bug.cgi?id=88692
     5
     6        Reviewed by Geoffrey Garen.
     7       
     8        Added ability to set the inline capacity of segmented vectors.
     9
     10        * wtf/SegmentedVector.h:
     11        (WTF):
     12        (SegmentedVectorIterator):
     13        (WTF::SegmentedVectorIterator::operator=):
     14        (WTF::SegmentedVectorIterator::SegmentedVectorIterator):
     15        (SegmentedVector):
     16
    1172012-06-12  Geoffrey Garen  <[email protected]>
    218
  • trunk/Source/WTF/wtf/SegmentedVector.h

    r117198 r120172  
    3535
    3636    // An iterator for SegmentedVector. It supports only the pre ++ operator
    37     template <typename T, size_t SegmentSize> class SegmentedVector;
    38     template <typename T, size_t SegmentSize> class SegmentedVectorIterator {
     37    template <typename T, size_t SegmentSize = 8, size_t InlineCapacity = 32> class SegmentedVector;
     38    template <typename T, size_t SegmentSize = 8, size_t InlineCapacity = 32> class SegmentedVectorIterator {
    3939    private:
    40         friend class SegmentedVector<T, SegmentSize>;
     40        friend class SegmentedVector<T, SegmentSize, InlineCapacity>;
    4141    public:
    42         typedef SegmentedVectorIterator<T, SegmentSize> Iterator;
     42        typedef SegmentedVectorIterator<T, SegmentSize, InlineCapacity> Iterator;
    4343
    4444        ~SegmentedVectorIterator() { }
     
    7676        }
    7777
    78         SegmentedVectorIterator& operator=(const SegmentedVectorIterator<T, SegmentSize>& other)
     78        SegmentedVectorIterator& operator=(const SegmentedVectorIterator<T, SegmentSize, InlineCapacity>& other)
    7979        {
    8080            m_vector = other.m_vector;
     
    8585
    8686    private:
    87         SegmentedVectorIterator(SegmentedVector<T, SegmentSize>& vector, size_t segment, size_t index)
     87        SegmentedVectorIterator(SegmentedVector<T, SegmentSize, InlineCapacity>& vector, size_t segment, size_t index)
    8888            : m_vector(vector)
    8989            , m_segment(segment)
     
    9292        }
    9393
    94         SegmentedVector<T, SegmentSize>& m_vector;
     94        SegmentedVector<T, SegmentSize, InlineCapacity>& m_vector;
    9595        size_t m_segment;
    9696        size_t m_index;
     
    9999    // SegmentedVector is just like Vector, but it doesn't move the values
    100100    // stored in its buffer when it grows. Therefore, it is safe to keep
    101     // pointers into a SegmentedVector.
    102     template <typename T, size_t SegmentSize> class SegmentedVector {
    103         friend class SegmentedVectorIterator<T, SegmentSize>;
     101    // pointers into a SegmentedVector. The default tuning values are
     102    // optimized for segmented vectors that get large; you may want to use
     103    // SegmentedVector<thingy, 1, 0> if you don't expect a lot of entries.
     104    template <typename T, size_t SegmentSize, size_t InlineCapacity>
     105    class SegmentedVector {
     106        friend class SegmentedVectorIterator<T, SegmentSize, InlineCapacity>;
    104107    public:
    105         typedef SegmentedVectorIterator<T, SegmentSize> Iterator;
     108        typedef SegmentedVectorIterator<T, SegmentSize, InlineCapacity> Iterator;
    106109
    107110        SegmentedVector()
     
    251254        size_t m_size;
    252255        Segment m_inlineSegment;
    253         Vector<Segment*, 32> m_segments;
     256        Vector<Segment*, InlineCapacity> m_segments;
    254257    };
    255258
Note: See TracChangeset for help on using the changeset viewer.