Add InvalidationPoints to the DFG and use them for all watchpoints
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Oct 2013 19:58:08 +0000 (19:58 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Oct 2013 19:58:08 +0000 (19:58 +0000)
https://bugs.webkit.org/show_bug.cgi?id=123472

Reviewed by Mark Hahnenberg.

This makes a fundamental change to how watchpoints work in the DFG.

Previously, a watchpoint was an instruction whose execution semantics were something
like:

    if (watchpoint->invalidated)
        exit

We would implement this without any branch by using jump replacement.

This is a very good optimization. But it's a bit awkward once you get a lot of
watchpoints: semantically we will have lots of these branches in the code, which the
compiler needs to reason about even though they don't actually result in any emitted
code.

Separately, we also had a mechanism for jettisoning a CodeBlock. This mechanism would
be invoked if a CodeBlock exited a lot. It would ensure that a CodeBlock wouldn't be
called into again, but it would do nothing for CodeBlocks that were already on the
stack.

This change flips jettisoning and watchpoint invalidation on their heads. Now, the jump
replacement has nothing to do with watchpoints; instead it's something that happens if
you ever jettison a CodeBlock. Jump replacement is now an all-or-nothing operation over
all of the potential call-return safe-exit-points in a CodeBlock. We call these
"InvalidationPoint"s. A watchpoint instruction is now "lowered" by having the DFG
collect all of the watchpoint sets that the CodeBlock cares about, and then registering
a CodeBlockJettisoningWatchpoint with all of them. That is, if the watchpoint fires, it
jettisons the CodeBlock, which in turn ensures that the CodeBlock can't be called into
(because the entrypoint now points to baseline code) and can't be returned into
(because returning exits to baseline before the next bytecode instruction).

This will allow for a sensible lowering of watchpoints to LLVM IR. It will also allow
for jettison() to be used effectively for things like breakpointing and single-stepping
in the debugger.

Well, basically, this mechanism just takes us into the HotSpot-style world where anyone
can, at any time and for any reason, request that an optimized CodeBlock is rendered
immediately invalid. You can use this for many cool things, I'm sure.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* assembler/AbstractMacroAssembler.h:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::jettison):
* bytecode/CodeBlock.h:
* bytecode/CodeBlockJettisoningWatchpoint.cpp: Added.
(JSC::CodeBlockJettisoningWatchpoint::fireInternal):
* bytecode/CodeBlockJettisoningWatchpoint.h: Added.
(JSC::CodeBlockJettisoningWatchpoint::CodeBlockJettisoningWatchpoint):
* bytecode/ExitKind.cpp:
(JSC::exitKindToString):
* bytecode/ExitKind.h:
* bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp: Added.
(JSC::ProfiledCodeBlockJettisoningWatchpoint::fireInternal):
* bytecode/ProfiledCodeBlockJettisoningWatchpoint.h: Added.
(JSC::ProfiledCodeBlockJettisoningWatchpoint::ProfiledCodeBlockJettisoningWatchpoint):
* dfg/DFGAbstractHeap.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGClobberize.cpp:
(JSC::DFG::writesOverlap):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
(JSC::DFG::AbstractHeapOverlaps::AbstractHeapOverlaps):
(JSC::DFG::AbstractHeapOverlaps::operator()):
(JSC::DFG::AbstractHeapOverlaps::result):
* dfg/DFGCommonData.cpp:
(JSC::DFG::CommonData::invalidate):
* dfg/DFGCommonData.h:
(JSC::DFG::CommonData::CommonData):
* dfg/DFGDesiredWatchpoints.cpp:
(JSC::DFG::DesiredWatchpoints::addLazily):
(JSC::DFG::DesiredWatchpoints::reallyAdd):
* dfg/DFGDesiredWatchpoints.h:
(JSC::DFG::WatchpointForGenericWatchpointSet::WatchpointForGenericWatchpointSet):
(JSC::DFG::GenericDesiredWatchpoints::addLazily):
(JSC::DFG::GenericDesiredWatchpoints::reallyAdd):
(JSC::DFG::GenericDesiredWatchpoints::areStillValid):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGInvalidationPointInjectionPhase.cpp: Added.
(JSC::DFG::InvalidationPointInjectionPhase::InvalidationPointInjectionPhase):
(JSC::DFG::InvalidationPointInjectionPhase::run):
(JSC::DFG::InvalidationPointInjectionPhase::handle):
(JSC::DFG::InvalidationPointInjectionPhase::insertInvalidationCheck):
(JSC::DFG::performInvalidationPointInjection):
* dfg/DFGInvalidationPointInjectionPhase.h: Added.
* dfg/DFGJITCode.h:
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::linkOSRExits):
(JSC::DFG::JITCompiler::link):
* dfg/DFGJITCompiler.h:
* dfg/DFGJumpReplacement.cpp: Added.
(JSC::DFG::JumpReplacement::fire):
* dfg/DFGJumpReplacement.h: Added.
(JSC::DFG::JumpReplacement::JumpReplacement):
* dfg/DFGNodeType.h:
* dfg/DFGOSRExitCompilationInfo.h:
* dfg/DFGOperations.cpp:
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
(JSC::DFG::Plan::reallyAdd):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::emitInvalidationPoint):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality):
(JSC::DFG::SpeculativeJIT::compileGetByValOnString):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::masqueradesAsUndefinedWatchpointIsStillValid):
(JSC::DFG::SpeculativeJIT::speculateStringObjectForStructure):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGWatchpointCollectionPhase.cpp: Added.
(JSC::DFG::WatchpointCollectionPhase::WatchpointCollectionPhase):
(JSC::DFG::WatchpointCollectionPhase::run):
(JSC::DFG::WatchpointCollectionPhase::handle):
(JSC::DFG::WatchpointCollectionPhase::handleEdge):
(JSC::DFG::WatchpointCollectionPhase::handleMasqueradesAsUndefined):
(JSC::DFG::WatchpointCollectionPhase::handleStringGetByVal):
(JSC::DFG::WatchpointCollectionPhase::addLazily):
(JSC::DFG::WatchpointCollectionPhase::globalObject):
(JSC::DFG::performWatchpointCollection):
* dfg/DFGWatchpointCollectionPhase.h: Added.
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileStructureTransitionWatchpoint):
(JSC::FTL::LowerDFGToLLVM::compileGetByVal):
(JSC::FTL::LowerDFGToLLVM::compileGlobalVarWatchpoint):
(JSC::FTL::LowerDFGToLLVM::compileCompareEqConstant):
(JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
(JSC::FTL::LowerDFGToLLVM::compileCompareStrictEqConstant):
(JSC::FTL::LowerDFGToLLVM::compileInvalidationPoint):
(JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined):
(JSC::FTL::LowerDFGToLLVM::speculateNonNullObject):
* jit/JITOperations.cpp:
* jit/JumpReplacementWatchpoint.cpp: Removed.
* jit/JumpReplacementWatchpoint.h: Removed.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@158304 268f45cc-cd09-0410-ab3c-d52691b4dbfc

45 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/CodeBlockJettisoningWatchpoint.cpp [new file with mode: 0644]
Source/JavaScriptCore/bytecode/CodeBlockJettisoningWatchpoint.h [moved from Source/JavaScriptCore/jit/JumpReplacementWatchpoint.h with 58% similarity]
Source/JavaScriptCore/bytecode/ExitKind.cpp
Source/JavaScriptCore/bytecode/ExitKind.h
Source/JavaScriptCore/bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp [new file with mode: 0644]
Source/JavaScriptCore/bytecode/ProfiledCodeBlockJettisoningWatchpoint.h [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGAbstractHeap.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGClobberize.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGCommonData.cpp
Source/JavaScriptCore/dfg/DFGCommonData.h
Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp
Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGInvalidationPointInjectionPhase.cpp [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGInvalidationPointInjectionPhase.h [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGJITCode.h
Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
Source/JavaScriptCore/dfg/DFGJITCompiler.h
Source/JavaScriptCore/dfg/DFGJumpReplacement.cpp [moved from Source/JavaScriptCore/jit/JumpReplacementWatchpoint.cpp with 62% similarity]
Source/JavaScriptCore/dfg/DFGJumpReplacement.h [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOSRExitCompilationInfo.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGPlan.cpp
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.h [new file with mode: 0644]
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
Source/JavaScriptCore/jit/JITOperations.cpp

index 1e64850..bb8ac98 100644 (file)
@@ -50,6 +50,7 @@ set(JavaScriptCore_SOURCES
     bytecode/CallLinkStatus.cpp
     bytecode/CodeBlock.cpp
     bytecode/CodeBlockHash.cpp
+    bytecode/CodeBlockJettisoningWatchpoint.cpp
     bytecode/CodeOrigin.cpp
     bytecode/CodeType.cpp
     bytecode/DFGExitProfile.cpp
@@ -64,6 +65,7 @@ set(JavaScriptCore_SOURCES
     bytecode/Opcode.cpp
     bytecode/PolymorphicPutByIdList.cpp
     bytecode/PreciseJumpTargets.cpp
+    bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp
     bytecode/PutByIdStatus.cpp
     bytecode/ReduceWhitespace.cpp
     bytecode/SamplingTool.cpp
@@ -124,9 +126,11 @@ set(JavaScriptCore_SOURCES
     dfg/DFGFlushedAt.cpp
     dfg/DFGGraph.cpp
     dfg/DFGInPlaceAbstractState.cpp
+    dfg/DFGInvalidationPointInjectionPhase.cpp
     dfg/DFGJITCode.cpp
     dfg/DFGJITCompiler.cpp
     dfg/DFGJITFinalizer.cpp
+    dfg/DFGJumpReplacement.cpp
     dfg/DFGLICMPhase.cpp
     dfg/DFGLazyJSValue.cpp
     dfg/DFGLivenessAnalysisPhase.cpp
@@ -168,6 +172,7 @@ set(JavaScriptCore_SOURCES
     dfg/DFGVariableEvent.cpp
     dfg/DFGVariableEventStream.cpp
     dfg/DFGVirtualRegisterAllocationPhase.cpp
+    dfg/DFGWatchpointCollectionPhase.cpp
     dfg/DFGWorklist.cpp
 
     disassembler/ARMv7Disassembler.cpp
@@ -236,7 +241,6 @@ set(JavaScriptCore_SOURCES
     jit/JITStubs.cpp
     jit/JITThunks.cpp
     jit/JITToDFGDeferredCompilationCallback.cpp
-    jit/JumpReplacementWatchpoint.cpp
     jit/RegisterSet.cpp
     jit/Repatch.cpp
     jit/TempRegisterSet.cpp
index 6b97625..1b8dcaf 100644 (file)
@@ -1,3 +1,171 @@
+2013-10-29  Filip Pizlo  <fpizlo@apple.com>
+
+        Add InvalidationPoints to the DFG and use them for all watchpoints
+        https://bugs.webkit.org/show_bug.cgi?id=123472
+
+        Reviewed by Mark Hahnenberg.
+        
+        This makes a fundamental change to how watchpoints work in the DFG.
+        
+        Previously, a watchpoint was an instruction whose execution semantics were something
+        like:
+        
+            if (watchpoint->invalidated)
+                exit
+        
+        We would implement this without any branch by using jump replacement.
+        
+        This is a very good optimization. But it's a bit awkward once you get a lot of
+        watchpoints: semantically we will have lots of these branches in the code, which the
+        compiler needs to reason about even though they don't actually result in any emitted
+        code.
+        
+        Separately, we also had a mechanism for jettisoning a CodeBlock. This mechanism would
+        be invoked if a CodeBlock exited a lot. It would ensure that a CodeBlock wouldn't be
+        called into again, but it would do nothing for CodeBlocks that were already on the
+        stack.
+        
+        This change flips jettisoning and watchpoint invalidation on their heads. Now, the jump
+        replacement has nothing to do with watchpoints; instead it's something that happens if
+        you ever jettison a CodeBlock. Jump replacement is now an all-or-nothing operation over
+        all of the potential call-return safe-exit-points in a CodeBlock. We call these
+        "InvalidationPoint"s. A watchpoint instruction is now "lowered" by having the DFG
+        collect all of the watchpoint sets that the CodeBlock cares about, and then registering
+        a CodeBlockJettisoningWatchpoint with all of them. That is, if the watchpoint fires, it
+        jettisons the CodeBlock, which in turn ensures that the CodeBlock can't be called into
+        (because the entrypoint now points to baseline code) and can't be returned into
+        (because returning exits to baseline before the next bytecode instruction).
+        
+        This will allow for a sensible lowering of watchpoints to LLVM IR. It will also allow
+        for jettison() to be used effectively for things like breakpointing and single-stepping
+        in the debugger.
+        
+        Well, basically, this mechanism just takes us into the HotSpot-style world where anyone
+        can, at any time and for any reason, request that an optimized CodeBlock is rendered
+        immediately invalid. You can use this for many cool things, I'm sure.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * assembler/AbstractMacroAssembler.h:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::jettison):
+        * bytecode/CodeBlock.h:
+        * bytecode/CodeBlockJettisoningWatchpoint.cpp: Added.
+        (JSC::CodeBlockJettisoningWatchpoint::fireInternal):
+        * bytecode/CodeBlockJettisoningWatchpoint.h: Added.
+        (JSC::CodeBlockJettisoningWatchpoint::CodeBlockJettisoningWatchpoint):
+        * bytecode/ExitKind.cpp:
+        (JSC::exitKindToString):
+        * bytecode/ExitKind.h:
+        * bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp: Added.
+        (JSC::ProfiledCodeBlockJettisoningWatchpoint::fireInternal):
+        * bytecode/ProfiledCodeBlockJettisoningWatchpoint.h: Added.
+        (JSC::ProfiledCodeBlockJettisoningWatchpoint::ProfiledCodeBlockJettisoningWatchpoint):
+        * dfg/DFGAbstractHeap.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::::executeEffects):
+        * dfg/DFGClobberize.cpp:
+        (JSC::DFG::writesOverlap):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        (JSC::DFG::AbstractHeapOverlaps::AbstractHeapOverlaps):
+        (JSC::DFG::AbstractHeapOverlaps::operator()):
+        (JSC::DFG::AbstractHeapOverlaps::result):
+        * dfg/DFGCommonData.cpp:
+        (JSC::DFG::CommonData::invalidate):
+        * dfg/DFGCommonData.h:
+        (JSC::DFG::CommonData::CommonData):
+        * dfg/DFGDesiredWatchpoints.cpp:
+        (JSC::DFG::DesiredWatchpoints::addLazily):
+        (JSC::DFG::DesiredWatchpoints::reallyAdd):
+        * dfg/DFGDesiredWatchpoints.h:
+        (JSC::DFG::WatchpointForGenericWatchpointSet::WatchpointForGenericWatchpointSet):
+        (JSC::DFG::GenericDesiredWatchpoints::addLazily):
+        (JSC::DFG::GenericDesiredWatchpoints::reallyAdd):
+        (JSC::DFG::GenericDesiredWatchpoints::areStillValid):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGInvalidationPointInjectionPhase.cpp: Added.
+        (JSC::DFG::InvalidationPointInjectionPhase::InvalidationPointInjectionPhase):
+        (JSC::DFG::InvalidationPointInjectionPhase::run):
+        (JSC::DFG::InvalidationPointInjectionPhase::handle):
+        (JSC::DFG::InvalidationPointInjectionPhase::insertInvalidationCheck):
+        (JSC::DFG::performInvalidationPointInjection):
+        * dfg/DFGInvalidationPointInjectionPhase.h: Added.
+        * dfg/DFGJITCode.h:
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::linkOSRExits):
+        (JSC::DFG::JITCompiler::link):
+        * dfg/DFGJITCompiler.h:
+        * dfg/DFGJumpReplacement.cpp: Added.
+        (JSC::DFG::JumpReplacement::fire):
+        * dfg/DFGJumpReplacement.h: Added.
+        (JSC::DFG::JumpReplacement::JumpReplacement):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOSRExitCompilationInfo.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGPlan.cpp:
+        (JSC::DFG::Plan::compileInThreadImpl):
+        (JSC::DFG::Plan::reallyAdd):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::emitInvalidationPoint):
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality):
+        (JSC::DFG::SpeculativeJIT::compileGetByValOnString):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::masqueradesAsUndefinedWatchpointIsStillValid):
+        (JSC::DFG::SpeculativeJIT::speculateStringObjectForStructure):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
+        (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
+        (JSC::DFG::SpeculativeJIT::compileObjectEquality):
+        (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
+        (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
+        (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
+        (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
+        (JSC::DFG::SpeculativeJIT::compileObjectEquality):
+        (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
+        (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
+        (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGWatchpointCollectionPhase.cpp: Added.
+        (JSC::DFG::WatchpointCollectionPhase::WatchpointCollectionPhase):
+        (JSC::DFG::WatchpointCollectionPhase::run):
+        (JSC::DFG::WatchpointCollectionPhase::handle):
+        (JSC::DFG::WatchpointCollectionPhase::handleEdge):
+        (JSC::DFG::WatchpointCollectionPhase::handleMasqueradesAsUndefined):
+        (JSC::DFG::WatchpointCollectionPhase::handleStringGetByVal):
+        (JSC::DFG::WatchpointCollectionPhase::addLazily):
+        (JSC::DFG::WatchpointCollectionPhase::globalObject):
+        (JSC::DFG::performWatchpointCollection):
+        * dfg/DFGWatchpointCollectionPhase.h: Added.
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::LowerDFGToLLVM::compileStructureTransitionWatchpoint):
+        (JSC::FTL::LowerDFGToLLVM::compileGetByVal):
+        (JSC::FTL::LowerDFGToLLVM::compileGlobalVarWatchpoint):
+        (JSC::FTL::LowerDFGToLLVM::compileCompareEqConstant):
+        (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
+        (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEqConstant):
+        (JSC::FTL::LowerDFGToLLVM::compileInvalidationPoint):
+        (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined):
+        (JSC::FTL::LowerDFGToLLVM::speculateNonNullObject):
+        * jit/JITOperations.cpp:
+        * jit/JumpReplacementWatchpoint.cpp: Removed.
+        * jit/JumpReplacementWatchpoint.h: Removed.
+
 2013-10-25  Mark Hahnenberg  <mhahnenberg@apple.com>
 
         JSExport doesn't support constructors
index 326074c..f1d281e 100644 (file)
@@ -112,6 +112,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/bytecode/CodeBlock.h \
        Source/JavaScriptCore/bytecode/CodeBlockHash.cpp \
        Source/JavaScriptCore/bytecode/CodeBlockHash.h \
+       Source/JavaScriptCore/bytecode/CodeBlockJettisoningWatchpoint.cpp \
+       Source/JavaScriptCore/bytecode/CodeBlockJettisoningWatchpoint.h \
        Source/JavaScriptCore/bytecode/CodeBlockWithJITType.h \
        Source/JavaScriptCore/bytecode/CodeOrigin.cpp \
        Source/JavaScriptCore/bytecode/CodeOrigin.h \
@@ -150,6 +152,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.h \
        Source/JavaScriptCore/bytecode/PreciseJumpTargets.cpp \
        Source/JavaScriptCore/bytecode/PreciseJumpTargets.h \
+       Source/JavaScriptCore/bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp \
+       Source/JavaScriptCore/bytecode/ProfiledCodeBlockJettisoningWatchpoint.h \
        Source/JavaScriptCore/bytecode/SpeculatedType.cpp \
        Source/JavaScriptCore/bytecode/SpeculatedType.h \
        Source/JavaScriptCore/bytecode/PutByIdStatus.cpp \
@@ -284,6 +288,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.h \
        Source/JavaScriptCore/dfg/DFGInlineCacheWrapper.h \
        Source/JavaScriptCore/dfg/DFGInlineCacheWrapperInlines.h \
+       Source/JavaScriptCore/dfg/DFGInvalidationPointInjectionPhase.cpp \
+       Source/JavaScriptCore/dfg/DFGInvalidationPointInjectionPhase.h \
        Source/JavaScriptCore/dfg/DFGInsertionSet.h \
        Source/JavaScriptCore/dfg/DFGJITCode.cpp \
        Source/JavaScriptCore/dfg/DFGJITCode.h \
@@ -291,6 +297,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/dfg/DFGJITCompiler.h \
        Source/JavaScriptCore/dfg/DFGJITFinalizer.cpp \
        Source/JavaScriptCore/dfg/DFGJITFinalizer.h \
+       Source/JavaScriptCore/dfg/DFGJumpReplacement.cpp \
+       Source/JavaScriptCore/dfg/DFGJumpReplacement.h \
        Source/JavaScriptCore/dfg/DFGLICMPhase.cpp \
        Source/JavaScriptCore/dfg/DFGLICMPhase.h \
        Source/JavaScriptCore/dfg/DFGLazyJSValue.cpp \
@@ -389,6 +397,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/dfg/DFGVariadicFunction.h \
        Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp \
        Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.h \
+       Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp \
+       Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.h \
        Source/JavaScriptCore/dfg/DFGWorklist.cpp \
        Source/JavaScriptCore/dfg/DFGWorklist.h \
        Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp \
@@ -665,8 +675,6 @@ javascriptcore_sources += \
        Source/JavaScriptCore/jit/JITToDFGDeferredCompilationCallback.h \
        Source/JavaScriptCore/jit/JITWriteBarrier.h \
        Source/JavaScriptCore/jit/JSInterfaceJIT.h \
-       Source/JavaScriptCore/jit/JumpReplacementWatchpoint.cpp \
-       Source/JavaScriptCore/jit/JumpReplacementWatchpoint.h \
        Source/JavaScriptCore/jit/RegisterSet.cpp \
        Source/JavaScriptCore/jit/RegisterSet.h \
        Source/JavaScriptCore/jit/Repatch.cpp \
index cde59ce..c89fae7 100644 (file)
     <ClCompile Include="..\bytecode\CallLinkStatus.cpp" />\r
     <ClCompile Include="..\bytecode\CodeBlock.cpp" />\r
     <ClCompile Include="..\bytecode\CodeBlockHash.cpp" />\r
+    <ClCompile Include="..\bytecode\CodeBlockJettisoningWatchpoint.cpp" />\r
     <ClCompile Include="..\bytecode\CodeOrigin.cpp" />\r
     <ClCompile Include="..\bytecode\CodeType.cpp" />\r
     <ClCompile Include="..\bytecode\DeferredCompilationCallback.cpp" />\r
     <ClCompile Include="..\bytecode\MethodOfGettingAValueProfile.cpp" />\r
     <ClCompile Include="..\bytecode\Opcode.cpp" />\r
     <ClCompile Include="..\bytecode\PolymorphicPutByIdList.cpp" />\r
+    <ClCompile Include="..\bytecode\ProfiledCodeBlockJettisoningWatchpoint.cpp" />\r
     <ClCompile Include="..\bytecode\PreciseJumpTargets.cpp" />\r
     <ClCompile Include="..\bytecode\PutByIdStatus.cpp" />\r
     <ClCompile Include="..\bytecode\ReduceWhitespace.cpp" />\r
     <ClCompile Include="..\jit\JITStubs.cpp" />\r
     <ClCompile Include="..\jit\JITThunks.cpp" />\r
     <ClCompile Include="..\jit\JITToDFGDeferredCompilationCallback.cpp" />\r
-    <ClCompile Include="..\jit\JumpReplacementWatchpoint.cpp" />\r
     <ClCompile Include="..\jit\Repatch.cpp" />\r
     <ClCompile Include="..\jit\ThunkGenerators.cpp" />\r
     <ClCompile Include="..\llint\LLIntCLoop.cpp" />\r
     <ClInclude Include="..\bytecode\CallReturnOffsetToBytecodeOffset.h" />\r
     <ClInclude Include="..\bytecode\CodeBlock.h" />\r
     <ClInclude Include="..\bytecode\CodeBlockHash.h" />\r
+    <ClInclude Include="..\bytecode\CodeBlockJettisoningWatchpoint.h" />\r
     <ClInclude Include="..\bytecode\CodeBlockWithJITType.h" />\r
     <ClInclude Include="..\bytecode\CodeOrigin.h" />\r
     <ClInclude Include="..\bytecode\CodeType.h" />\r
     <ClInclude Include="..\bytecode\Opcode.h" />\r
     <ClInclude Include="..\bytecode\Operands.h" />\r
     <ClInclude Include="..\bytecode\PolymorphicPutByIdList.h" />\r
+    <ClInclude Include="..\bytecode\ProfiledCodeBlockJettisoningWatchpoint.h" />\r
     <ClInclude Include="..\bytecode\PreciseJumpTargets.h" />\r
     <ClInclude Include="..\bytecode\PutByIdStatus.h" />\r
     <ClInclude Include="..\bytecode\PutKind.h" />\r
     <ClInclude Include="..\jit\JITToDFGDeferredCompilationCallback.h" />\r
     <ClInclude Include="..\jit\JITWriteBarrier.h" />\r
     <ClInclude Include="..\jit\JSInterfaceJIT.h" />\r
-    <ClInclude Include="..\jit\JumpReplacementWatchpoint.h" />\r
     <ClCompile Include="..\jit\RegisterSet.cpp" />\r
     <ClInclude Include="..\jit\RegisterSet.h" />\r
     <ClInclude Include="..\jit\Repatch.h" />\r
index 5cb22d0..c2e2b1f 100644 (file)
                0F766D2F15A8DCE0008F363E /* GCAwareJITStubRoutine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F766D2D15A8DCDD008F363E /* GCAwareJITStubRoutine.cpp */; };
                0F766D3015A8DCE2008F363E /* GCAwareJITStubRoutine.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F766D2E15A8DCDD008F363E /* GCAwareJITStubRoutine.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F766D3115AA8112008F363E /* JITStubRoutine.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F766D1C15A5028D008F363E /* JITStubRoutine.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               0F766D3415AE2538008F363E /* JumpReplacementWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F766D3215AE2535008F363E /* JumpReplacementWatchpoint.cpp */; };
-               0F766D3515AE253B008F363E /* JumpReplacementWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F766D3315AE2535008F363E /* JumpReplacementWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F766D3815AE4A1C008F363E /* StructureStubClearingWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F766D3615AE4A1A008F363E /* StructureStubClearingWatchpoint.cpp */; };
                0F766D3915AE4A1F008F363E /* StructureStubClearingWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F766D3715AE4A1A008F363E /* StructureStubClearingWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F7700921402FF3C0078EB39 /* SamplingCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7700911402FF280078EB39 /* SamplingCounter.cpp */; };
                0FC8150B14043C0E00CFA603 /* WriteBarrierSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */; };
                0FC815151405119B00CFA603 /* VTableSpectrum.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC815141405118D00CFA603 /* VTableSpectrum.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FC81516140511B500CFA603 /* VTableSpectrum.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC815121405118600CFA603 /* VTableSpectrum.cpp */; };
+               0FC97F33182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC97F2F182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.cpp */; };
+               0FC97F34182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC97F30182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FC97F35182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC97F31182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.cpp */; };
+               0FC97F36182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC97F32182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FC97F3D18202119002C9B26 /* DFGInvalidationPointInjectionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC97F3718202119002C9B26 /* DFGInvalidationPointInjectionPhase.cpp */; };
+               0FC97F3E18202119002C9B26 /* DFGInvalidationPointInjectionPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC97F3818202119002C9B26 /* DFGInvalidationPointInjectionPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FC97F3F18202119002C9B26 /* DFGJumpReplacement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC97F3918202119002C9B26 /* DFGJumpReplacement.cpp */; };
+               0FC97F4018202119002C9B26 /* DFGJumpReplacement.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC97F3A18202119002C9B26 /* DFGJumpReplacement.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FC97F4118202119002C9B26 /* DFGWatchpointCollectionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC97F3B18202119002C9B26 /* DFGWatchpointCollectionPhase.cpp */; };
+               0FC97F4218202119002C9B26 /* DFGWatchpointCollectionPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC97F3C18202119002C9B26 /* DFGWatchpointCollectionPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FCCAE4516D0CF7400D0C65B /* ParserError.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCCAE4316D0CF6E00D0C65B /* ParserError.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FCEFAAB1804C13E00472CE4 /* FTLSaveRestore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFAA91804C13E00472CE4 /* FTLSaveRestore.cpp */; };
                0FCEFAAC1804C13E00472CE4 /* FTLSaveRestore.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCEFAAA1804C13E00472CE4 /* FTLSaveRestore.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F766D2A15A8CC34008F363E /* JITStubRoutineSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubRoutineSet.h; sourceTree = "<group>"; };
                0F766D2D15A8DCDD008F363E /* GCAwareJITStubRoutine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCAwareJITStubRoutine.cpp; sourceTree = "<group>"; };
                0F766D2E15A8DCDD008F363E /* GCAwareJITStubRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCAwareJITStubRoutine.h; sourceTree = "<group>"; };
-               0F766D3215AE2535008F363E /* JumpReplacementWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JumpReplacementWatchpoint.cpp; sourceTree = "<group>"; };
-               0F766D3315AE2535008F363E /* JumpReplacementWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JumpReplacementWatchpoint.h; sourceTree = "<group>"; };
                0F766D3615AE4A1A008F363E /* StructureStubClearingWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructureStubClearingWatchpoint.cpp; sourceTree = "<group>"; };
                0F766D3715AE4A1A008F363E /* StructureStubClearingWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureStubClearingWatchpoint.h; sourceTree = "<group>"; };
                0F77008E1402FDD60078EB39 /* SamplingCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingCounter.h; sourceTree = "<group>"; };
                0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WriteBarrierSupport.h; sourceTree = "<group>"; };
                0FC815121405118600CFA603 /* VTableSpectrum.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VTableSpectrum.cpp; sourceTree = "<group>"; };
                0FC815141405118D00CFA603 /* VTableSpectrum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VTableSpectrum.h; sourceTree = "<group>"; };
+               0FC97F2F182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeBlockJettisoningWatchpoint.cpp; sourceTree = "<group>"; };
+               0FC97F30182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeBlockJettisoningWatchpoint.h; sourceTree = "<group>"; };
+               0FC97F31182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProfiledCodeBlockJettisoningWatchpoint.cpp; sourceTree = "<group>"; };
+               0FC97F32182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProfiledCodeBlockJettisoningWatchpoint.h; sourceTree = "<group>"; };
+               0FC97F3718202119002C9B26 /* DFGInvalidationPointInjectionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGInvalidationPointInjectionPhase.cpp; path = dfg/DFGInvalidationPointInjectionPhase.cpp; sourceTree = "<group>"; };
+               0FC97F3818202119002C9B26 /* DFGInvalidationPointInjectionPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGInvalidationPointInjectionPhase.h; path = dfg/DFGInvalidationPointInjectionPhase.h; sourceTree = "<group>"; };
+               0FC97F3918202119002C9B26 /* DFGJumpReplacement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGJumpReplacement.cpp; path = dfg/DFGJumpReplacement.cpp; sourceTree = "<group>"; };
+               0FC97F3A18202119002C9B26 /* DFGJumpReplacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGJumpReplacement.h; path = dfg/DFGJumpReplacement.h; sourceTree = "<group>"; };
+               0FC97F3B18202119002C9B26 /* DFGWatchpointCollectionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGWatchpointCollectionPhase.cpp; path = dfg/DFGWatchpointCollectionPhase.cpp; sourceTree = "<group>"; };
+               0FC97F3C18202119002C9B26 /* DFGWatchpointCollectionPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGWatchpointCollectionPhase.h; path = dfg/DFGWatchpointCollectionPhase.h; sourceTree = "<group>"; };
                0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlotVisitorInlines.h; sourceTree = "<group>"; };
                0FCCAE4316D0CF6E00D0C65B /* ParserError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParserError.h; sourceTree = "<group>"; };
                0FCEFAA91804C13E00472CE4 /* FTLSaveRestore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLSaveRestore.cpp; path = ftl/FTLSaveRestore.cpp; sourceTree = "<group>"; };
                                0FC712E117CD878F008CC93C /* JITToDFGDeferredCompilationCallback.h */,
                                A76F54A213B28AAB00EF2BCE /* JITWriteBarrier.h */,
                                A76C51741182748D00715B05 /* JSInterfaceJIT.h */,
-                               0F766D3215AE2535008F363E /* JumpReplacementWatchpoint.cpp */,
-                               0F766D3315AE2535008F363E /* JumpReplacementWatchpoint.h */,
                                0FC3141418146D7000033232 /* RegisterSet.cpp */,
                                0FC314101814559100033232 /* RegisterSet.h */,
                                0F24E54917EE274900ABB217 /* Repatch.cpp */,
                                A704D90017A0BAA8006BA554 /* DFGInPlaceAbstractState.cpp */,
                                A704D90117A0BAA8006BA554 /* DFGInPlaceAbstractState.h */,
                                0F2BDC1F151E803800CD8910 /* DFGInsertionSet.h */,
+                               0FC97F3718202119002C9B26 /* DFGInvalidationPointInjectionPhase.cpp */,
+                               0FC97F3818202119002C9B26 /* DFGInvalidationPointInjectionPhase.h */,
                                0FEA0A2F170D40BF00BB722C /* DFGJITCode.cpp */,
                                0FEA0A30170D40BF00BB722C /* DFGJITCode.h */,
                                86EC9DBB1328DF82002B2AD7 /* DFGJITCompiler.cpp */,
                                86EC9DBC1328DF82002B2AD7 /* DFGJITCompiler.h */,
                                A78A9770179738B8009DF744 /* DFGJITFinalizer.cpp */,
                                A78A9771179738B8009DF744 /* DFGJITFinalizer.h */,
+                               0FC97F3918202119002C9B26 /* DFGJumpReplacement.cpp */,
+                               0FC97F3A18202119002C9B26 /* DFGJumpReplacement.h */,
                                A73A53581799CD5D00170C19 /* DFGLazyJSValue.cpp */,
                                A73A53591799CD5D00170C19 /* DFGLazyJSValue.h */,
                                A7D9A29217A0BC7400EE2618 /* DFGLICMPhase.cpp */,
                                0F85A31E16AB76AE0077571E /* DFGVariadicFunction.h */,
                                0FFFC95314EF909500C72532 /* DFGVirtualRegisterAllocationPhase.cpp */,
                                0FFFC95414EF909500C72532 /* DFGVirtualRegisterAllocationPhase.h */,
+                               0FC97F3B18202119002C9B26 /* DFGWatchpointCollectionPhase.cpp */,
+                               0FC97F3C18202119002C9B26 /* DFGWatchpointCollectionPhase.h */,
                                0FDB2CE5174830A2007B3C1B /* DFGWorklist.cpp */,
                                0FDB2CE6174830A2007B3C1B /* DFGWorklist.h */,
                        );
                                969A07910ED1D3AE00F1F681 /* CodeBlock.h */,
                                0F8F943D1667632D00D61971 /* CodeBlockHash.cpp */,
                                0F8F943E1667632D00D61971 /* CodeBlockHash.h */,
+                               0FC97F2F182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.cpp */,
+                               0FC97F30182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.h */,
                                0F96EBB116676EF4008BADE3 /* CodeBlockWithJITType.h */,
                                0F8F9445166764EE00D61971 /* CodeOrigin.cpp */,
                                0FBD7E671447998F00481315 /* CodeOrigin.h */,
                                0F9FC8C014E1B5FB00D52AE0 /* PolymorphicPutByIdList.h */,
                                0F98205D16BFE37F00240D02 /* PreciseJumpTargets.cpp */,
                                0F98205E16BFE37F00240D02 /* PreciseJumpTargets.h */,
+                               0FC97F31182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.cpp */,
+                               0FC97F32182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.h */,
                                0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */,
                                0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */,
                                0F9FC8C114E1B5FB00D52AE0 /* PutKind.h */,
                                0F2BDC16151C5D4F00CD8910 /* DFGFixupPhase.h in Headers */,
                                A7D89CF817A0B8CC00773AD8 /* DFGFlushFormat.h in Headers */,
                                A7D89CFA17A0B8CC00773AD8 /* DFGFlushLivenessAnalysisPhase.h in Headers */,
+                               0FC97F3E18202119002C9B26 /* DFGInvalidationPointInjectionPhase.h in Headers */,
                                86EC9DC61328DF82002B2AD7 /* DFGGenerationInfo.h in Headers */,
                                86EC9DC81328DF82002B2AD7 /* DFGGraph.h in Headers */,
                                A704D90617A0BAA8006BA554 /* DFGInPlaceAbstractState.h in Headers */,
                                DDF7ABD411F60ED200108E36 /* GCActivityCallback.h in Headers */,
                                BCBE2CAE14E985AA000593AD /* GCAssertions.h in Headers */,
                                0F766D3015A8DCE2008F363E /* GCAwareJITStubRoutine.h in Headers */,
+                               0FC97F4018202119002C9B26 /* DFGJumpReplacement.h in Headers */,
                                0F2B66AC17B6B53F00A7AE3F /* GCIncomingRefCounted.h in Headers */,
                                0F2B66AD17B6B54500A7AE3F /* GCIncomingRefCountedInlines.h in Headers */,
                                0F2B66AE17B6B54500A7AE3F /* GCIncomingRefCountedSet.h in Headers */,
                                0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */,
                                BC18C42A0E16F5CD00B34460 /* JSType.h in Headers */,
                                0F2B66FB17B6B5AB00A7AE3F /* JSTypedArrayConstructors.h in Headers */,
+                               0FC97F36182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.h in Headers */,
                                0F2B66FD17B6B5AB00A7AE3F /* JSTypedArrayPrototypes.h in Headers */,
                                0FCEFAAC1804C13E00472CE4 /* FTLSaveRestore.h in Headers */,
                                0F2B66FF17B6B5AB00A7AE3F /* JSTypedArrays.h in Headers */,
                                1442566215EDE98D0066A49B /* JSWithScope.h in Headers */,
                                86E3C619167BABEE006D760A /* JSWrapperMap.h in Headers */,
                                BC18C42E0E16F5CD00B34460 /* JSWrapperObject.h in Headers */,
-                               0F766D3515AE253B008F363E /* JumpReplacementWatchpoint.h in Headers */,
                                BCFD8C930EEB2EE700283848 /* JumpTable.h in Headers */,
                                A72FFD64139985A800E5365A /* KeywordLookup.h in Headers */,
                                969A072A0ED1CE6900F1F681 /* Label.h in Headers */,
                                969A079B0ED1D3AE00F1F681 /* Opcode.h in Headers */,
                                0F2BDC2C151FDE9100CD8910 /* Operands.h in Headers */,
                                A70447EA17A0BD4600F5898E /* OperandsInlines.h in Headers */,
+                               0FC97F34182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.h in Headers */,
                                BC18C4480E16F5CD00B34460 /* Operations.h in Headers */,
                                0FE228ED1436AB2700196C48 /* Options.h in Headers */,
                                BC18C44B0E16F5CD00B34460 /* Parser.h in Headers */,
                                BC18C45D0E16F5CD00B34460 /* Register.h in Headers */,
                                969A072B0ED1CE6900F1F681 /* RegisterID.h in Headers */,
                                0FB7F39D15ED8E4600F167B2 /* Reject.h in Headers */,
+                               0FC97F4218202119002C9B26 /* DFGWatchpointCollectionPhase.h in Headers */,
                                86D3B3C410159D7F002865E7 /* RepatchBuffer.h in Headers */,
                                869EBCB70E8C6D4A008722CC /* ResultType.h in Headers */,
                                C22B31B9140577D700DB475A /* SamplingCounter.h in Headers */,
                                1428082D107EC0570013E7B2 /* CallData.cpp in Sources */,
                                0FCEFAB11805CA6D00472CE4 /* InitializeLLVMMac.mm in Sources */,
                                1429D8DD0ED2205B00B89619 /* CallFrame.cpp in Sources */,
+                               0FC97F33182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.cpp in Sources */,
                                0F0B83B014BCF71600885B4F /* CallLinkInfo.cpp in Sources */,
                                0F93329D14CA7DC30085F3C6 /* CallLinkStatus.cpp in Sources */,
                                0F73D7AE165A142D00ACAB71 /* ClosureCallStubRoutine.cpp in Sources */,
                                A70B083217A0B79B00DAF14B /* DFGBinarySwitch.cpp in Sources */,
                                A7D89CF317A0B8CC00773AD8 /* DFGBlockInsertionSet.cpp in Sources */,
                                86EC9DC41328DF82002B2AD7 /* DFGByteCodeParser.cpp in Sources */,
+                               0FC97F35182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.cpp in Sources */,
                                0FD82E2114172CE300179C94 /* DFGCapabilities.cpp in Sources */,
                                0FFFC95714EF90A000C72532 /* DFGCFAPhase.cpp in Sources */,
                                0F3B3A271544C995003ED0FF /* DFGCFGSimplificationPhase.cpp in Sources */,
                                86EC9DC71328DF82002B2AD7 /* DFGGraph.cpp in Sources */,
                                A704D90517A0BAA8006BA554 /* DFGInPlaceAbstractState.cpp in Sources */,
                                0FEA0A33170D40BF00BB722C /* DFGJITCode.cpp in Sources */,
+                               0FC97F3D18202119002C9B26 /* DFGInvalidationPointInjectionPhase.cpp in Sources */,
                                86EC9DCB1328DF82002B2AD7 /* DFGJITCompiler.cpp in Sources */,
                                A78A9778179738B8009DF744 /* DFGJITFinalizer.cpp in Sources */,
                                A73A535A1799CD5D00170C19 /* DFGLazyJSValue.cpp in Sources */,
                                86E3C616167BABEE006D760A /* JSContext.mm in Sources */,
                                0FD8A31317D4326C00CA2C40 /* CodeBlockSet.cpp in Sources */,
                                14BD5A300A3E91F600BAF59C /* JSContextRef.cpp in Sources */,
+                               0FC97F4118202119002C9B26 /* DFGWatchpointCollectionPhase.cpp in Sources */,
                                A72028B61797601E0098028C /* JSCTestRunnerUtils.cpp in Sources */,
                                0F2B66EB17B6B5AB00A7AE3F /* JSDataView.cpp in Sources */,
                                0F2B66ED17B6B5AB00A7AE3F /* JSDataViewPrototype.cpp in Sources */,
                                1442566115EDE98D0066A49B /* JSWithScope.cpp in Sources */,
                                86E3C618167BABEE006D760A /* JSWrapperMap.mm in Sources */,
                                14280870107EC1340013E7B2 /* JSWrapperObject.cpp in Sources */,
-                               0F766D3415AE2538008F363E /* JumpReplacementWatchpoint.cpp in Sources */,
                                BCFD8C920EEB2EE700283848 /* JumpTable.cpp in Sources */,
                                0FB5467914F5C46B002C2989 /* LazyOperandValueProfile.cpp in Sources */,
                                95AB83420DA4322500BC83F3 /* LegacyProfiler.cpp in Sources */,
                                A7CA3AE317DA41AE006538AF /* WeakMapConstructor.cpp in Sources */,
                                86F3EEBE168CDE930077B92A /* ObjCCallbackFunction.mm in Sources */,
                                14469DE5107EC7E700650446 /* ObjectConstructor.cpp in Sources */,
+                               0FC97F3F18202119002C9B26 /* DFGJumpReplacement.cpp in Sources */,
                                14469DE6107EC7E700650446 /* ObjectPrototype.cpp in Sources */,
                                E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */,
                                969A079A0ED1D3AE00F1F681 /* Opcode.cpp in Sources */,
index 9fef855..d3a2a22 100644 (file)
@@ -63,7 +63,6 @@ inline bool isX86()
 #endif
 }
 
-class JumpReplacementWatchpoint;
 class LinkBuffer;
 class RepatchBuffer;
 class Watchpoint;
@@ -342,7 +341,6 @@ public:
         friend class AbstractMacroAssembler;
         friend struct DFG::OSRExit;
         friend class Jump;
-        friend class JumpReplacementWatchpoint;
         friend class MacroAssemblerCodeRef;
         friend class LinkBuffer;
         friend class Watchpoint;
index 1bc766a..c0f0162 100644 (file)
@@ -2775,16 +2775,6 @@ const SlowArgument* CodeBlock::machineSlowArguments()
 }
 
 #if ENABLE(JIT)
-void CodeBlock::reoptimize()
-{
-    ASSERT(replacement() != this);
-    ASSERT(replacement()->alternative() == this);
-    if (DFG::shouldShowDisassembly())
-        dataLog(*replacement(), " will be jettisoned due to reoptimization of ", *this, ".\n");
-    replacement()->jettison();
-    countReoptimization();
-}
-
 CodeBlock* ProgramCodeBlock::replacement()
 {
     return jsCast<ProgramExecutable*>(ownerExecutable())->codeBlock();
@@ -2817,16 +2807,53 @@ DFG::CapabilityLevel FunctionCodeBlock::capabilityLevelInternal()
     return DFG::functionForCallCapabilityLevel(this);
 }
 
-void CodeBlock::jettison()
+void CodeBlock::jettison(ReoptimizationMode mode)
 {
+    if (DFG::shouldShowDisassembly()) {
+        dataLog("Jettisoning ", *this);
+        if (mode == CountReoptimization)
+            dataLog(" and counting reoptimization");
+        dataLog(".\n");
+    }
+    
     DeferGC deferGC(*m_heap);
-    ASSERT(JITCode::isOptimizingJIT(jitType()));
-    ASSERT(this == replacement());
+    RELEASE_ASSERT(JITCode::isOptimizingJIT(jitType()));
+    
+    // We want to accomplish two things here:
+    // 1) Make sure that if this CodeBlock is on the stack right now, then if we return to it
+    //    we should OSR exit at the top of the next bytecode instruction after the return.
+    // 2) Make sure that if we call the owner executable, then we shouldn't call this CodeBlock.
+    
+    // This accomplishes the OSR-exit-on-return part, and does its own book-keeping about
+    // whether the invalidation has already happened.
+    if (!jitCode()->dfgCommon()->invalidate()) {
+        // Nothing to do since we've already been invalidated. That means that we cannot be
+        // the optimized replacement.
+        RELEASE_ASSERT(this != replacement());
+        return;
+    }
+    
+    if (DFG::shouldShowDisassembly())
+        dataLog("    Did invalidate ", *this, "\n");
+    
+    // Count the reoptimization if that's what the user wanted.
+    if (mode == CountReoptimization) {
+        baselineVersion()->countReoptimization();
+        if (DFG::shouldShowDisassembly())
+            dataLog("    Did count reoptimization for ", *this, "\n");
+    }
+    
+    // Now take care of the entrypoint.
+    if (this != replacement()) {
+        // This means that we were never the entrypoint. This can happen for OSR entry code
+        // blocks.
+        return;
+    }
     alternative()->optimizeAfterWarmUp();
     tallyFrequentExitSites();
-    if (DFG::shouldShowDisassembly())
-        dataLog("Jettisoning ", *this, ".\n");
     alternative()->install();
+    if (DFG::shouldShowDisassembly())
+        dataLog("    Did install baseline version of ", *this, "\n");
 }
 #endif
 
index a947cc0..ae90378 100644 (file)
@@ -61,7 +61,6 @@
 #include "JITCode.h"
 #include "JITWriteBarrier.h"
 #include "JSGlobalObject.h"
-#include "JumpReplacementWatchpoint.h"
 #include "JumpTable.h"
 #include "LLIntCallLinkInfo.h"
 #include "LazyOperandValueProfile.h"
@@ -92,6 +91,8 @@ inline VirtualRegister unmodifiedArgumentsRegister(VirtualRegister argumentsRegi
 
 static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); }
 
+enum ReoptimizationMode { DontCountReoptimization, CountReoptimization };
+
 class CodeBlock : public ThreadSafeRefCounted<CodeBlock>, public UnconditionalFinalizer, public WeakReferenceHarvester {
     WTF_MAKE_FAST_ALLOCATED;
     friend class JIT;
@@ -277,7 +278,8 @@ public:
     {
         return jitType() == JITCode::BaselineJIT;
     }
-    void jettison();
+    
+    void jettison(ReoptimizationMode = DontCountReoptimization);
     
     virtual CodeBlock* replacement() = 0;
 
@@ -855,10 +857,6 @@ public:
     void updateAllPredictions() { }
 #endif
 
-#if ENABLE(JIT)
-    void reoptimize();
-#endif
-
 #if ENABLE(VERBOSE_VALUE_PROFILE)
     void dumpValueProfiles();
 #endif
diff --git a/Source/JavaScriptCore/bytecode/CodeBlockJettisoningWatchpoint.cpp b/Source/JavaScriptCore/bytecode/CodeBlockJettisoningWatchpoint.cpp
new file mode 100644 (file)
index 0000000..be50c97
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "CodeBlockJettisoningWatchpoint.h"
+
+#include "CodeBlock.h"
+#include "DFGCommon.h"
+
+namespace JSC {
+
+void CodeBlockJettisoningWatchpoint::fireInternal()
+{
+    if (DFG::shouldShowDisassembly())
+        dataLog("Firing watchpoint ", RawPointer(this), " on ", *m_codeBlock, "\n");
+
+    m_codeBlock->jettison(CountReoptimization);
+
+    if (isOnList())
+        remove();
+}
+
+} // namespace JSC
+
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
-#ifndef JumpReplacementWatchpoint_h
-#define JumpReplacementWatchpoint_h
+#ifndef CodeBlockJettisoningWatchpoint_h
+#define CodeBlockJettisoningWatchpoint_h
 
 #include "Watchpoint.h"
-#include <wtf/Platform.h>
-
-#if ENABLE(JIT)
-
-#include "CodeLocation.h"
-#include "MacroAssembler.h"
 
 namespace JSC {
 
-class JumpReplacementWatchpoint : public Watchpoint {
+class CodeBlock;
+
+class CodeBlockJettisoningWatchpoint : public Watchpoint {
 public:
-    JumpReplacementWatchpoint()
-        : m_source(std::numeric_limits<uintptr_t>::max())
-        , m_destination(std::numeric_limits<uintptr_t>::max())
-    {
-    }
-    
-    JumpReplacementWatchpoint(MacroAssembler::Label source)
-        : m_source(source.m_label.m_offset)
-        , m_destination(std::numeric_limits<uintptr_t>::max())
+    CodeBlockJettisoningWatchpoint()
+        : m_codeBlock(0)
     {
     }
     
-    MacroAssembler::Label sourceLabel() const
+    CodeBlockJettisoningWatchpoint(CodeBlock* codeBlock)
+        : m_codeBlock(codeBlock)
     {
-        MacroAssembler::Label label;
-        label.m_label.m_offset = m_source;
-        return label;
     }
     
-    void setDestination(MacroAssembler::Label destination)
-    {
-        m_destination = destination.m_label.m_offset;
-    }
-    
-    void correctLabels(LinkBuffer&);
-
 protected:
     virtual void fireInternal() OVERRIDE;
 
 private:
-    uintptr_t m_source;
-    uintptr_t m_destination;
+    CodeBlock* m_codeBlock;
 };
 
 } // namespace JSC
 
-#endif // ENABLE(JIT)
-
-#endif // JumpReplacementWatchpoint_h
+#endif // CodeBlockJettisoningWatchpoint_h
 
index bdd4f48..442a589 100644 (file)
@@ -76,6 +76,8 @@ const char* exitKindToString(ExitKind kind)
         return "Uncountable";
     case UncountableWatchpoint:
         return "UncountableWatchpoint";
+    case UncountableInvalidation:
+        return "UncountableInvalidation";
     case WatchdogTimerFired:
         return "WatchdogTimerFired";
     }
index a162921..f523040 100644 (file)
@@ -49,6 +49,7 @@ enum ExitKind {
     ArgumentsEscaped, // We exited because arguments escaped but we didn't expect them to.
     NotStringObject, // We exited because we shouldn't have attempted to optimize string object access.
     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.
+    UncountableInvalidation, // We exited because the code block was invalidated; this means that we've already counted the reasons why the code block was invalidated.
     UncountableWatchpoint, // We exited because of a watchpoint, which isn't counted because watchpoints do tracking themselves.
     WatchdogTimerFired // We exited because we need to service the watchdog timer.
 };
diff --git a/Source/JavaScriptCore/bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp b/Source/JavaScriptCore/bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp
new file mode 100644 (file)
index 0000000..b520d9f
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "ProfiledCodeBlockJettisoningWatchpoint.h"
+
+#include "CodeBlock.h"
+#include "DFGCommon.h"
+#include "DFGExitProfile.h"
+
+namespace JSC {
+
+void ProfiledCodeBlockJettisoningWatchpoint::fireInternal()
+{
+    if (DFG::shouldShowDisassembly()) {
+        dataLog(
+            "Firing profiled watchpoint ", RawPointer(this), " on ", *m_codeBlock, " due to ",
+            m_exitKind, " at ", m_codeOrigin, "\n");
+    }
+    
+    baselineCodeBlockForOriginAndBaselineCodeBlock(
+        m_codeOrigin, m_codeBlock->baselineVersion())->addFrequentExitSite(
+            DFG::FrequentExitSite(m_codeOrigin.bytecodeIndex, m_exitKind));
+    
+    m_codeBlock->jettison(CountReoptimization);
+
+    if (isOnList())
+        remove();
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/bytecode/ProfiledCodeBlockJettisoningWatchpoint.h b/Source/JavaScriptCore/bytecode/ProfiledCodeBlockJettisoningWatchpoint.h
new file mode 100644 (file)
index 0000000..e992e90
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef ProfiledCodeBlockJettisoningWatchpoint_h
+#define ProfiledCodeBlockJettisoningWatchpoint_h
+
+#include "CodeOrigin.h"
+#include "ExitKind.h"
+#include "Watchpoint.h"
+
+namespace JSC {
+
+class CodeBlock;
+
+class ProfiledCodeBlockJettisoningWatchpoint : public Watchpoint {
+public:
+    ProfiledCodeBlockJettisoningWatchpoint()
+        : m_exitKind(ExitKindUnset)
+        , m_codeBlock(0)
+    {
+    }
+    
+    ProfiledCodeBlockJettisoningWatchpoint(
+        CodeOrigin codeOrigin, ExitKind exitKind, CodeBlock* codeBlock)
+        : m_codeOrigin(codeOrigin)
+        , m_exitKind(exitKind)
+        , m_codeBlock(codeBlock)
+    {
+    }
+    
+protected:
+    virtual void fireInternal() OVERRIDE;
+
+private:
+    CodeOrigin m_codeOrigin;
+    ExitKind m_exitKind;
+    CodeBlock* m_codeBlock;
+};
+
+} // namespace JSC
+
+#endif // ProfiledCodeBlockJettisoningWatchpoint_h
+
index 379de10..7060404 100644 (file)
@@ -71,6 +71,8 @@ namespace JSC { namespace DFG {
     macro(RegExpState) \
     macro(InternalState) \
     macro(Absolute) \
+    /* Use this for writes only, to indicate that this may fire watchpoints. Usually this is never directly written but instead we test to see if a node clobbers this; it just so happens that you have to write world to clobber it. */\
+    macro(Watchpoint_fire) \
     /* Use this for reads only, just to indicate that if the world got clobbered, then this operation will not work. */\
     macro(MiscFields) \
     /* Use this for writes only, just to indicate that hoisting the node is invalid. This works because we don't hoist anything that has any side effects at all. */\
index d008a92..414c93e 100644 (file)
@@ -1535,6 +1535,10 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         node->setCanExit(true);
         m_state.setIsValid(false);
         break;
+        
+    case InvalidationPoint:
+        node->setCanExit(true);
+        break;
             
     case CheckWatchdogTimer:
         node->setCanExit(true);
index 275dcf7..be61856 100644 (file)
@@ -40,6 +40,14 @@ bool doesWrites(Graph& graph, Node* node)
     return addWrite.result();
 }
 
+bool writesOverlap(Graph& graph, Node* node, AbstractHeap heap)
+{
+    NoOpClobberize addRead;
+    AbstractHeapOverlaps addWrite(heap);
+    clobberize(graph, node, addRead, addWrite);
+    return addWrite.result();
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
index 463c3ff..abbb551 100644 (file)
@@ -137,6 +137,7 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
     case CheckTierUpAtReturn:
     case CheckTierUpAndOSREnter:
     case LoopHint:
+    case InvalidationPoint:
         write(SideState);
         return;
 
@@ -669,6 +670,30 @@ private:
 
 bool doesWrites(Graph&, Node*);
 
+class AbstractHeapOverlaps {
+public:
+    AbstractHeapOverlaps(AbstractHeap heap)
+        : m_heap(heap)
+        , m_result(false)
+    {
+    }
+    
+    void operator()(AbstractHeap otherHeap)
+    {
+        if (m_result)
+            return;
+        m_result = m_heap.overlaps(otherHeap);
+    }
+    
+    bool result() const { return m_result; }
+
+private:
+    AbstractHeap m_heap;
+    bool m_result;
+};
+
+bool writesOverlap(Graph&, Node*, AbstractHeap);
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
index 513085e..7b7ed0e 100644 (file)
@@ -62,6 +62,16 @@ void CommonData::shrinkToFit()
     transitions.shrinkToFit();
 }
 
+bool CommonData::invalidate()
+{
+    if (!isStillValid)
+        return false;
+    for (unsigned i = jumpReplacements.size(); i--;)
+        jumpReplacements[i].fire();
+    isStillValid = false;
+    return true;
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
index e039420..cee302b 100644 (file)
 
 #if ENABLE(DFG_JIT)
 
+#include "CodeBlockJettisoningWatchpoint.h"
+#include "DFGJumpReplacement.h"
 #include "InlineCallFrameSet.h"
 #include "JSCell.h"
+#include "ProfiledCodeBlockJettisoningWatchpoint.h"
 #include "ProfilerCompilation.h"
 #include "SymbolTable.h"
 #include <wtf/Noncopyable.h>
@@ -69,13 +72,16 @@ class CommonData {
     WTF_MAKE_NONCOPYABLE(CommonData);
 public:
     CommonData()
-        : machineCaptureStart(std::numeric_limits<int>::max())
+        : isStillValid(true)
+        , machineCaptureStart(std::numeric_limits<int>::max())
     { }
     
     void notifyCompilingStructureTransition(Plan&, CodeBlock*, Node*);
     unsigned addCodeOrigin(CodeOrigin codeOrigin);
     
     void shrinkToFit();
+    
+    bool invalidate(); // Returns true if we did invalidate, or false if the code block was already invalidated.
 
     OwnPtr<InlineCallFrameSet> inlineCallFrames;
     Vector<CodeOrigin, 0, UnsafeVectorOverflow> codeOrigins;
@@ -83,10 +89,14 @@ public:
     Vector<Identifier> dfgIdentifiers;
     Vector<WeakReferenceTransition> transitions;
     Vector<WriteBarrier<JSCell>> weakReferences;
+    SegmentedVector<CodeBlockJettisoningWatchpoint, 1, 0> watchpoints;
+    SegmentedVector<ProfiledCodeBlockJettisoningWatchpoint, 1, 0> profiledWatchpoints;
+    Vector<JumpReplacement> jumpReplacements;
     
     RefPtr<Profiler::Compilation> compilation;
     bool livenessHasBeenProved; // Initialized and used on every GC.
     bool allTransitionsHaveBeenMarked; // Initialized and used on every GC.
+    bool isStillValid;
     
     int machineCaptureStart;
     std::unique_ptr<SlowArgument[]> slowArguments;
index b5da4c2..bfc50b6 100644 (file)
@@ -33,20 +33,30 @@ namespace JSC { namespace DFG {
 DesiredWatchpoints::DesiredWatchpoints() { }
 DesiredWatchpoints::~DesiredWatchpoints() { }
 
-void DesiredWatchpoints::addLazily(Watchpoint* watchpoint, WatchpointSet* set)
+void DesiredWatchpoints::addLazily(WatchpointSet* set)
 {
-    m_sets.addLazily(WatchpointForWatchpointSet(watchpoint, set));
+    m_sets.addLazily(set);
 }
 
-void DesiredWatchpoints::addLazily(Watchpoint* watchpoint, InlineWatchpointSet& set)
+void DesiredWatchpoints::addLazily(InlineWatchpointSet& set)
 {
-    m_inlineSets.addLazily(WatchpointForInlineWatchpointSet(watchpoint, &set));
+    m_inlineSets.addLazily(&set);
 }
 
-void DesiredWatchpoints::reallyAdd()
+void DesiredWatchpoints::addLazily(CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSet* set)
 {
-    m_sets.reallyAdd();
-    m_inlineSets.reallyAdd();
+    m_sets.addLazily(codeOrigin, exitKind, set);
+}
+
+void DesiredWatchpoints::addLazily(CodeOrigin codeOrigin, ExitKind exitKind, InlineWatchpointSet& set)
+{
+    m_inlineSets.addLazily(codeOrigin, exitKind, &set);
+}
+
+void DesiredWatchpoints::reallyAdd(CodeBlock* codeBlock, CommonData& commonData)
+{
+    m_sets.reallyAdd(codeBlock, commonData);
+    m_inlineSets.reallyAdd(codeBlock, commonData);
 }
 
 bool DesiredWatchpoints::areStillValid() const
index 29f057d..909bd93 100644 (file)
 
 #if ENABLE(DFG_JIT)
 
+#include "CodeOrigin.h"
+#include "DFGCommonData.h"
 #include "Watchpoint.h"
 #include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
 #include <wtf/Noncopyable.h>
 #include <wtf/Vector.h>
 
@@ -40,24 +43,24 @@ namespace JSC { namespace DFG {
 template<typename WatchpointSetType>
 struct WatchpointForGenericWatchpointSet {
     WatchpointForGenericWatchpointSet()
-        : m_watchpoint(0)
+        : m_exitKind(ExitKindUnset)
         , m_set(0)
     {
     }
     
-    WatchpointForGenericWatchpointSet(Watchpoint* watchpoint, WatchpointSetType* set)
-        : m_watchpoint(watchpoint)
+    WatchpointForGenericWatchpointSet(
+        CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSetType* set)
+        : m_codeOrigin(codeOrigin)
+        , m_exitKind(exitKind)
         , m_set(set)
     {
     }
     
-    Watchpoint* m_watchpoint;
+    CodeOrigin m_codeOrigin;
+    ExitKind m_exitKind;
     WatchpointSetType* m_set;
 };
 
-typedef WatchpointForGenericWatchpointSet<WatchpointSet> WatchpointForWatchpointSet;
-typedef WatchpointForGenericWatchpointSet<InlineWatchpointSet> WatchpointForInlineWatchpointSet;
-
 template<typename WatchpointSetType>
 class GenericDesiredWatchpoints {
     WTF_MAKE_NONCOPYABLE(GenericDesiredWatchpoints);
@@ -70,25 +73,53 @@ public:
     {
     }
     
-    void addLazily(const WatchpointForGenericWatchpointSet<WatchpointSetType>& watchpoint)
+    void addLazily(WatchpointSetType* set)
+    {
+        m_sets.add(set);
+    }
+    
+    void addLazily(CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSetType* set)
     {
-        m_watchpoints.append(watchpoint);
+        m_profiledWatchpoints.append(
+            WatchpointForGenericWatchpointSet<WatchpointSetType>(codeOrigin, exitKind, set));
     }
     
-    void reallyAdd()
+    void reallyAdd(CodeBlock* codeBlock, CommonData& common)
     {
         RELEASE_ASSERT(!m_reallyAdded);
-        for (unsigned i = m_watchpoints.size(); i--;)
-            m_watchpoints[i].m_set->add(m_watchpoints[i].m_watchpoint);
+        
+        typename HashSet<WatchpointSetType*>::iterator iter = m_sets.begin();
+        typename HashSet<WatchpointSetType*>::iterator end = m_sets.end();
+        for (; iter != end; ++iter) {
+            common.watchpoints.append(CodeBlockJettisoningWatchpoint(codeBlock));
+            (*iter)->add(&common.watchpoints.last());
+        }
+        
+        for (unsigned i = m_profiledWatchpoints.size(); i--;) {
+            WatchpointForGenericWatchpointSet<WatchpointSetType> watchpoint =
+                m_profiledWatchpoints[i];
+            common.profiledWatchpoints.append(
+                ProfiledCodeBlockJettisoningWatchpoint(watchpoint.m_codeOrigin, watchpoint.m_exitKind, codeBlock));
+            watchpoint.m_set->add(&common.profiledWatchpoints.last());
+        }
+        
         m_reallyAdded = true;
     }
     
     bool areStillValid() const
     {
-        for (unsigned i = m_watchpoints.size(); i--;) {
-            if (m_watchpoints[i].m_set->hasBeenInvalidated())
+        typename HashSet<WatchpointSetType*>::iterator iter = m_sets.begin();
+        typename HashSet<WatchpointSetType*>::iterator end = m_sets.end();
+        for (; iter != end; ++iter) {
+            if ((*iter)->hasBeenInvalidated())
+                return false;
+        }
+        
+        for (unsigned i = m_profiledWatchpoints.size(); i--;) {
+            if (m_profiledWatchpoints[i].m_set->hasBeenInvalidated())
                 return false;
         }
+        
         return true;
     }
     
@@ -126,7 +157,8 @@ public:
     }
 
 private:
-    Vector<WatchpointForGenericWatchpointSet<WatchpointSetType>> m_watchpoints;
+    Vector<WatchpointForGenericWatchpointSet<WatchpointSetType>> m_profiledWatchpoints;
+    HashSet<WatchpointSetType*> m_sets;
 #if !ASSERT_DISABLED
     StateMap m_firstKnownState;
 #endif
@@ -138,10 +170,12 @@ public:
     DesiredWatchpoints();
     ~DesiredWatchpoints();
     
-    void addLazily(Watchpoint*, WatchpointSet*);
-    void addLazily(Watchpoint*, InlineWatchpointSet&);
+    void addLazily(WatchpointSet*);
+    void addLazily(InlineWatchpointSet&);
+    void addLazily(CodeOrigin, ExitKind, WatchpointSet*);
+    void addLazily(CodeOrigin, ExitKind, InlineWatchpointSet&);
     
-    void reallyAdd();
+    void reallyAdd(CodeBlock*, CommonData&);
     
     bool areStillValid() const;
     
index a94c0fa..cb3849e 100644 (file)
@@ -885,6 +885,7 @@ private:
         case CheckTierUpAndOSREnter:
         case Int52ToDouble:
         case Int52ToValue:
+        case InvalidationPoint:
             RELEASE_ASSERT_NOT_REACHED();
             break;
 
diff --git a/Source/JavaScriptCore/dfg/DFGInvalidationPointInjectionPhase.cpp b/Source/JavaScriptCore/dfg/DFGInvalidationPointInjectionPhase.cpp
new file mode 100644 (file)
index 0000000..d71a7cb
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "DFGInvalidationPointInjectionPhase.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGClobberize.h"
+#include "DFGGraph.h"
+#include "DFGInsertionSet.h"
+#include "DFGPhase.h"
+#include "Operations.h"
+
+namespace JSC { namespace DFG {
+
+class InvalidationPointInjectionPhase : public Phase {
+    static const bool verbose = false;
+    
+public:
+    InvalidationPointInjectionPhase(Graph& graph)
+        : Phase(graph, "invalidation point injection")
+        , m_insertionSet(graph)
+    {
+    }
+    
+    bool run()
+    {
+        ASSERT(m_graph.m_form != SSA);
+        
+        BitVector blocksThatNeedInvalidationPoints;
+        
+        for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+            BasicBlock* block = m_graph.block(blockIndex);
+            if (!block)
+                continue;
+            
+            for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex)
+                handle(nodeIndex, block->at(nodeIndex));
+            
+            // Note: this assumes that control flow occurs at bytecode instruction boundaries.
+            if (m_originThatHadFire.isSet()) {
+                for (unsigned i = block->numSuccessors(); i--;)
+                    blocksThatNeedInvalidationPoints.set(block->successor(i)->index);
+            }
+            
+            m_insertionSet.execute(block);
+        }
+        
+        for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+            if (!blocksThatNeedInvalidationPoints.get(blockIndex))
+                continue;
+            
+            BasicBlock* block = m_graph.block(blockIndex);
+            insertInvalidationCheck(0, block->at(0));
+            m_insertionSet.execute(block);
+        }
+        
+        return true;
+    }
+
+private:
+    void handle(unsigned nodeIndex, Node* node)
+    {
+        if (m_originThatHadFire.isSet() && m_originThatHadFire != node->codeOrigin) {
+            insertInvalidationCheck(nodeIndex, node);
+            m_originThatHadFire = CodeOrigin();
+        }
+        
+        if (writesOverlap(m_graph, node, Watchpoint_fire))
+            m_originThatHadFire = node->codeOrigin;
+    }
+    
+    void insertInvalidationCheck(unsigned nodeIndex, Node* node)
+    {
+        m_insertionSet.insertNode(nodeIndex, SpecNone, InvalidationPoint, node->codeOrigin);
+    }
+    
+    CodeOrigin m_originThatHadFire;
+    InsertionSet m_insertionSet;
+};
+
+bool performInvalidationPointInjection(Graph& graph)
+{
+    SamplingRegion samplingRegion("DFG Invalidation Point Injection Phase");
+    return runPhase<InvalidationPointInjectionPhase>(graph);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGInvalidationPointInjectionPhase.h b/Source/JavaScriptCore/dfg/DFGInvalidationPointInjectionPhase.h
new file mode 100644 (file)
index 0000000..a135fdc
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGInvalidationPointInjectionPhase_h
+#define DFGInvalidationPointInjectionPhase_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+class Graph;
+
+// Inserts an invalidation check at the beginning of any CodeOrigin that follows a CodeOrigin
+// that had a call (clobbered World).
+
+bool performInvalidationPointInjection(Graph&);
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGInvalidationPointInjectionPhase_h
+
index 52dddc5..3a89944 100644 (file)
@@ -38,7 +38,6 @@
 #include "DFGVariableEventStream.h"
 #include "ExecutionCounter.h"
 #include "JITCode.h"
-#include "JumpReplacementWatchpoint.h"
 #include <wtf/SegmentedVector.h>
 
 namespace JSC { namespace DFG {
@@ -88,13 +87,6 @@ public:
         return result;
     }
     
-    unsigned appendWatchpoint(const JumpReplacementWatchpoint& watchpoint)
-    {
-        unsigned result = watchpoints.size();
-        watchpoints.append(watchpoint);
-        return result;
-    }
-    
     void reconstruct(
         CodeBlock*, CodeOrigin, unsigned streamIndex, Operands<ValueRecovery>& result);
     
@@ -127,7 +119,6 @@ public:
     Vector<DFG::OSREntryData> osrEntry;
     SegmentedVector<DFG::OSRExit, 8> osrExit;
     Vector<DFG::SpeculationRecovery> speculationRecovery;
-    SegmentedVector<JumpReplacementWatchpoint, 1, 0> watchpoints;
     DFG::VariableEventStream variableEventStream;
     DFG::MinifiedGraph minifiedDFG;
 #if ENABLE(FTL_JIT)
index 126abfe..76afa0d 100644 (file)
@@ -66,11 +66,11 @@ void JITCompiler::linkOSRExits()
         for (unsigned i = 0; i < m_jitCode->osrExit.size(); ++i) {
             OSRExitCompilationInfo& info = m_exitCompilationInfo[i];
             Vector<Label> labels;
-            if (info.m_watchpointIndex == std::numeric_limits<unsigned>::max()) {
+            if (!info.m_failureJumps.empty()) {
                 for (unsigned j = 0; j < info.m_failureJumps.jumps().size(); ++j)
                     labels.append(info.m_failureJumps.jumps()[j].label());
             } else
-                labels.append(m_jitCode->watchpoints[info.m_watchpointIndex].sourceLabel());
+                labels.append(info.m_replacementSource);
             m_exitSiteLabels.append(labels);
         }
     }
@@ -79,11 +79,10 @@ void JITCompiler::linkOSRExits()
         OSRExit& exit = m_jitCode->osrExit[i];
         OSRExitCompilationInfo& info = m_exitCompilationInfo[i];
         JumpList& failureJumps = info.m_failureJumps;
-        ASSERT(failureJumps.empty() == (info.m_watchpointIndex != std::numeric_limits<unsigned>::max()));
-        if (info.m_watchpointIndex == std::numeric_limits<unsigned>::max())
+        if (!failureJumps.empty())
             failureJumps.link(this);
         else
-            m_jitCode->watchpoints[info.m_watchpointIndex].setDestination(label());
+            info.m_replacementDestination = label();
         jitAssertHasValidCallFrame();
         store32(TrustedImm32(i), &vm()->osrExitIndex);
         exit.setPatchableCodeOffset(patchableJump());
@@ -257,8 +256,11 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
         OSRExitCompilationInfo& info = m_exitCompilationInfo[i];
         linkBuffer.link(exit.getPatchableCodeOffsetAsJump(), target);
         exit.correctJump(linkBuffer);
-        if (info.m_watchpointIndex != std::numeric_limits<unsigned>::max())
-            m_jitCode->watchpoints[info.m_watchpointIndex].correctLabels(linkBuffer);
+        if (info.m_replacementSource.isSet()) {
+            m_jitCode->common.jumpReplacements.append(JumpReplacement(
+                linkBuffer.locationOf(info.m_replacementSource),
+                linkBuffer.locationOf(info.m_replacementDestination)));
+        }
     }
     
     if (m_graph.compilation()) {
index 1103fbf..f6ecbfd 100644 (file)
@@ -116,15 +116,6 @@ public:
     // Accessors for properties.
     Graph& graph() { return m_graph; }
     
-    void addLazily(Watchpoint* watchpoint, WatchpointSet* set)
-    {
-        m_graph.watchpoints().addLazily(watchpoint, set);
-    }
-    void addLazily(Watchpoint* watchpoint, InlineWatchpointSet& set)
-    {
-        m_graph.watchpoints().addLazily(watchpoint, set);
-    }
-    
     // Methods to set labels for the disassembler.
     void setStartOfCode()
     {
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  */
 
 #include "config.h"
-#include "JumpReplacementWatchpoint.h"
+#include "DFGJumpReplacement.h"
 
-#if ENABLE(JIT)
+#if ENABLE(DFG_JIT)
 
-#include "LinkBuffer.h"
+#include "MacroAssembler.h"
 #include "Options.h"
 
-namespace JSC {
+namespace JSC { namespace DFG {
 
-void JumpReplacementWatchpoint::correctLabels(LinkBuffer& linkBuffer)
+void JumpReplacement::fire()
 {
-    MacroAssembler::Label label;
-    label.m_label.m_offset = m_source;
-    m_source = bitwise_cast<uintptr_t>(linkBuffer.locationOf(label).dataLocation());
-    label.m_label.m_offset = m_destination;
-    m_destination = bitwise_cast<uintptr_t>(linkBuffer.locationOf(label).dataLocation());
-}
-
-void JumpReplacementWatchpoint::fireInternal()
-{
-    void* source = bitwise_cast<void*>(m_source);
-    void* destination = bitwise_cast<void*>(m_destination);
     if (Options::showDisassembly())
-        dataLogF("Firing jump replacement watchpoint from %p, to %p.\n", source, destination);
-    MacroAssembler::replaceWithJump(CodeLocationLabel(source), CodeLocationLabel(destination));
-    if (isOnList())
-        remove();
+        dataLogF("Firing jump replacement watchpoint from %p, to %p.\n", m_source.dataLocation(), m_destination.dataLocation());
+    MacroAssembler::replaceWithJump(m_source, m_destination);
 }
 
-} // namespace JSC
+} } // namespace JSC::DFG
 
-#endif // ENABLE(JIT)
+#endif // ENABLE(DFG_JIT)
 
diff --git a/Source/JavaScriptCore/dfg/DFGJumpReplacement.h b/Source/JavaScriptCore/dfg/DFGJumpReplacement.h
new file mode 100644 (file)
index 0000000..e6cf69a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGJumpReplacement_h
+#define DFGJumpReplacement_h
+
+#if ENABLE(DFG_JIT)
+
+#include "CodeLocation.h"
+
+namespace JSC { namespace DFG {
+
+class JumpReplacement {
+public:
+    JumpReplacement(CodeLocationLabel source, CodeLocationLabel destination)
+        : m_source(source)
+        , m_destination(destination)
+    {
+    }
+    
+    void fire();
+
+private:
+    CodeLocationLabel m_source;
+    CodeLocationLabel m_destination;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGJumpReplacement_h
+
index 4048d5d..856a2f4 100644 (file)
@@ -89,7 +89,11 @@ namespace JSC { namespace DFG {
     macro(GetLocalUnlinked, NodeResultJS) \
     \
     /* Marker for an argument being set at the prologue of a function. */\
-    macro(SetArgument, 0 | NodeDoesNotExit) \
+    macro(SetArgument, NodeDoesNotExit) \
+    \
+    /* Marker of location in the IR where we may possibly perform jump replacement to */\
+    /* invalidate this code block. */\
+    macro(InvalidationPoint, NodeMustGenerate) \
     \
     /* Nodes for bitwise operations. */\
     macro(BitAnd, NodeResultInt32 | NodeMustGenerate) \
index d16497f..9eeb453 100644 (file)
 namespace JSC { namespace DFG {
 
 struct OSRExitCompilationInfo {
-    OSRExitCompilationInfo()
-        : m_watchpointIndex(std::numeric_limits<unsigned>::max())
-    {
-    }
-    
     MacroAssembler::JumpList m_failureJumps;
-    unsigned m_watchpointIndex;
+    MacroAssembler::Label m_replacementSource;
+    MacroAssembler::Label m_replacementDestination;
 };
 
 } } // namespace JSC::DFG
index 4da0c91..21b742d 100644 (file)
@@ -1097,7 +1097,7 @@ extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock)
         return;
     }
 
-    codeBlock->reoptimize();
+    optimizedCodeBlock->jettison(CountReoptimization);
 }
 
 #if ENABLE(FTL_JIT)
index 119af8a..365ec74 100644 (file)
@@ -41,6 +41,7 @@
 #include "DFGFailedFinalizer.h"
 #include "DFGFlushLivenessAnalysisPhase.h"
 #include "DFGFixupPhase.h"
+#include "DFGInvalidationPointInjectionPhase.h"
 #include "DFGJITCompiler.h"
 #include "DFGLICMPhase.h"
 #include "DFGLivenessAnalysisPhase.h"
@@ -56,6 +57,7 @@
 #include "DFGUnificationPhase.h"
 #include "DFGValidate.h"
 #include "DFGVirtualRegisterAllocationPhase.h"
+#include "DFGWatchpointCollectionPhase.h"
 #include "OperandsInlines.h"
 #include "Operations.h"
 #include <wtf/CurrentTime.h>
@@ -187,6 +189,7 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
     performBackwardsPropagation(dfg);
     performPredictionPropagation(dfg);
     performFixup(dfg);
+    performInvalidationPointInjection(dfg);
     performTypeCheckHoisting(dfg);
     
     unsigned count = 1;
@@ -228,7 +231,24 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
     switch (mode) {
     case DFGMode: {
         performTierUpCheckInjection(dfg);
-        break;
+
+        performCPSRethreading(dfg);
+        performDCE(dfg);
+        performStackLayout(dfg);
+        performVirtualRegisterAllocation(dfg);
+        performWatchpointCollection(dfg);
+        dumpAndVerifyGraph(dfg, "Graph after optimization:");
+        
+        JITCompiler dataFlowJIT(dfg);
+        if (codeBlock->codeType() == FunctionCode) {
+            dataFlowJIT.compileFunction();
+            dataFlowJIT.linkFunction();
+        } else {
+            dataFlowJIT.compile();
+            dataFlowJIT.link();
+        }
+        
+        return DFGPath;
     }
     
     case FTLMode:
@@ -253,6 +273,7 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
         performLivenessAnalysis(dfg);
         performFlushLivenessAnalysis(dfg);
         performOSRAvailabilityAnalysis(dfg);
+        performWatchpointCollection(dfg);
         
         dumpAndVerifyGraph(dfg, "Graph just before FTL lowering:");
         
@@ -280,31 +301,14 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
         return FTLPath;
 #else
         RELEASE_ASSERT_NOT_REACHED();
-        break;
+        return FailPath;
 #endif // ENABLE(FTL_JIT)
     }
         
     default:
         RELEASE_ASSERT_NOT_REACHED();
-        break;
-    }
-    
-    performCPSRethreading(dfg);
-    performDCE(dfg);
-    performStackLayout(dfg);
-    performVirtualRegisterAllocation(dfg);
-    dumpAndVerifyGraph(dfg, "Graph after optimization:");
-
-    JITCompiler dataFlowJIT(dfg);
-    if (codeBlock->codeType() == FunctionCode) {
-        dataFlowJIT.compileFunction();
-        dataFlowJIT.linkFunction();
-    } else {
-        dataFlowJIT.compile();
-        dataFlowJIT.link();
+        return FailPath;
     }
-    
-    return DFGPath;
 }
 
 bool Plan::isStillValid()
@@ -315,7 +319,7 @@ bool Plan::isStillValid()
 
 void Plan::reallyAdd(CommonData* commonData)
 {
-    watchpoints.reallyAdd();
+    watchpoints.reallyAdd(codeBlock.get(), *commonData);
     identifiers.reallyAdd(vm, commonData);
     weakReferences.reallyAdd(vm, commonData);
     transitions.reallyAdd(vm, commonData);
index fc0954f..9b88e7f 100644 (file)
@@ -512,7 +512,8 @@ private:
         case ZombieHint:
         case CheckTierUpInLoop:
         case CheckTierUpAtReturn:
-        case CheckTierUpAndOSREnter: {
+        case CheckTierUpAndOSREnter:
+        case InvalidationPoint: {
             // This node should never be visible at this stage of compilation. It is
             // inserted by fixup(), which follows this phase.
             RELEASE_ASSERT_NOT_REACHED();
index 77cf740..0970cbe 100644 (file)
@@ -239,6 +239,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case LoopHint:
     case Int52ToDouble:
     case Int52ToValue:
+    case InvalidationPoint:
         return true;
         
     case GetByVal:
index 0a87fe4..8cc5b23 100644 (file)
@@ -200,26 +200,20 @@ void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource
     speculationCheck(kind, jsValueSource, edge.node(), jumpToFail, recovery);
 }
 
-JumpReplacementWatchpoint* SpeculativeJIT::speculationWatchpoint(ExitKind kind, JSValueSource jsValueSource, Node* node)
+void SpeculativeJIT::emitInvalidationPoint(Node* node)
 {
     if (!m_compileOkay)
-        return 0;
-    ASSERT(m_isCheckingArgumentTypes || m_canExit);
+        return;
+    ASSERT(m_canExit);
+    ASSERT(m_speculationDirection == BackwardSpeculation);
     OSRExitCompilationInfo& info = m_jit.appendExitInfo(JITCompiler::JumpList());
     m_jit.jitCode()->appendOSRExit(OSRExit(
-        kind, jsValueSource,
+        UncountableInvalidation, JSValueSource(),
         m_jit.graph().methodOfGettingAValueProfileFor(node),
         this, m_stream->size()));
-    info.m_watchpointIndex = m_jit.jitCode()->appendWatchpoint(
-        JumpReplacementWatchpoint(m_jit.watchpointLabel()));
-    if (m_speculationDirection == ForwardSpeculation)
-        convertLastOSRExitToForward();
-    return &m_jit.jitCode()->watchpoints[info.m_watchpointIndex];
-}
-
-JumpReplacementWatchpoint* SpeculativeJIT::speculationWatchpoint(ExitKind kind)
-{
-    return speculationWatchpoint(kind, JSValueSource(), 0);
+    info.m_replacementSource = m_jit.watchpointLabel();
+    ASSERT(info.m_replacementSource.isSet());
+    noResult(node);
 }
 
 void SpeculativeJIT::convertLastOSRExitToForward(const ValueRecovery& valueRecovery)
@@ -1353,8 +1347,6 @@ void SpeculativeJIT::compilePeepHoleObjectEquality(Node* node, Node* branchNode)
     GPRReg op2GPR = op2.gpr();
     
     if (masqueradesAsUndefinedWatchpointIsStillValid()) {
-        speculationWatchpointForMasqueradesAsUndefined();
-
         if (m_state.forNode(node->child1()).m_type & ~SpecObject) {
             speculationCheck(
                 BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), 
@@ -2004,18 +1996,6 @@ void SpeculativeJIT::compileGetByValOnString(Node* node)
     }
 #endif
 
-    if (node->arrayMode().isOutOfBounds()) {
-        JSGlobalObject* globalObject = m_jit.globalObjectFor(node->codeOrigin);
-        if (globalObject->stringPrototypeChainIsSane()) {
-            m_jit.addLazily(
-                speculationWatchpoint(),
-                globalObject->stringPrototype()->structure()->transitionWatchpointSet());
-            m_jit.addLazily(
-                speculationWatchpoint(),
-                globalObject->objectPrototype()->structure()->transitionWatchpointSet());
-        }
-    }
-
     ASSERT(ArrayMode(Array::String).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1())));
 
     // unsigned comparison so we can filter out negative indices and indices that are too large
index 80e385f..fb1ad17 100644 (file)
@@ -284,20 +284,10 @@ public:
     {
         return m_jit.graph().masqueradesAsUndefinedWatchpointIsStillValid(codeOrigin);
     }
-    void speculationWatchpointForMasqueradesAsUndefined(const CodeOrigin& codeOrigin)
-    {
-        m_jit.addLazily(
-            speculationWatchpoint(),
-            m_jit.graph().globalObjectFor(codeOrigin)->masqueradesAsUndefinedWatchpoint());
-    }
     bool masqueradesAsUndefinedWatchpointIsStillValid()
     {
         return masqueradesAsUndefinedWatchpointIsStillValid(m_currentNode->codeOrigin);
     }
-    void speculationWatchpointForMasqueradesAsUndefined()
-    {
-        speculationWatchpointForMasqueradesAsUndefined(m_currentNode->codeOrigin);
-    }
 
     void writeBarrier(GPRReg ownerGPR, GPRReg valueGPR, Edge valueUse, WriteBarrierUseKind, GPRReg scratchGPR1 = InvalidGPRReg, GPRReg scratchGPR2 = InvalidGPRReg);
     void writeBarrier(GPRReg ownerGPR, JSCell* value, WriteBarrierUseKind, GPRReg scratchGPR1 = InvalidGPRReg, GPRReg scratchGPR2 = InvalidGPRReg);
@@ -2131,16 +2121,8 @@ public:
     // Add a speculation check with additional recovery.
     void backwardSpeculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&);
     void backwardSpeculationCheck(ExitKind, JSValueSource, Edge, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&);
-    // Use this like you would use speculationCheck(), except that you don't pass it a jump
-    // (because you don't have to execute a branch; that's kind of the whole point), and you
-    // must register the returned Watchpoint with something relevant. In general, this should
-    // be used with extreme care. Use speculationCheck() unless you've got an amazing reason
-    // not to.
-    JumpReplacementWatchpoint* speculationWatchpoint(ExitKind, JSValueSource, Node*);
-    // The default for speculation watchpoints is that they're uncounted, because the
-    // act of firing a watchpoint invalidates it. So, future recompilations will not
-    // attempt to set this watchpoint again.
-    JumpReplacementWatchpoint* speculationWatchpoint(ExitKind = UncountableWatchpoint);
+    
+    void emitInvalidationPoint(Node*);
     
     // It is generally a good idea to not use this directly.
     void convertLastOSRExitToForward(const ValueRecovery& = ValueRecovery());
@@ -3022,18 +3004,13 @@ void SpeculativeJIT::speculateStringObjectForStructure(Edge edge, StructureLocat
 {
     Structure* stringObjectStructure =
         m_jit.globalObjectFor(m_currentNode->codeOrigin)->stringObjectStructure();
-    Structure* stringPrototypeStructure = stringObjectStructure->storedPrototype().asCell()->structure();
-    ASSERT(m_jit.graph().watchpoints().isValidOrMixed(stringPrototypeStructure->transitionWatchpointSet()));
     
-    if (!m_state.forNode(edge).m_currentKnownStructure.isSubsetOf(StructureSet(m_jit.globalObjectFor(m_currentNode->codeOrigin)->stringObjectStructure()))) {
+    if (!m_state.forNode(edge).m_currentKnownStructure.isSubsetOf(StructureSet(stringObjectStructure))) {
         speculationCheck(
             NotStringObject, JSValueRegs(), 0,
             m_jit.branchPtr(
                 JITCompiler::NotEqual, structureLocation, TrustedImmPtr(stringObjectStructure)));
     }
-    m_jit.addLazily(
-        speculationWatchpoint(NotStringObject),
-        stringPrototypeStructure->transitionWatchpointSet());
 }
 
 #define DFG_TYPE_CHECK(source, edge, typesPassedThrough, jumpToFail) do { \
index c090a21..9c3fad5 100644 (file)
@@ -266,7 +266,6 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv
         if (!isKnownCell(operand.node()))
             notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
 
-        speculationWatchpointForMasqueradesAsUndefined();
         m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR);
         notMasqueradesAsUndefined = m_jit.jump();
     } else {
@@ -333,7 +332,6 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branch
         if (!isKnownCell(operand.node()))
             notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
 
-        speculationWatchpointForMasqueradesAsUndefined();
         jump(invert ? taken : notTaken, ForceJump);
     } else {
         GPRTemporary localGlobalObject(this);
@@ -1160,7 +1158,6 @@ void SpeculativeJIT::compileObjectEquality(Node* node)
     GPRReg op2GPR = op2.gpr();
     
     if (masqueradesAsUndefinedWatchpointIsStillValid()) {
-        speculationWatchpointForMasqueradesAsUndefined();
         DFG_TYPE_CHECK(
             JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1238,7 +1235,6 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r
     }
 
     if (masqueradesAsUndefinedWatchpointValid) {
-        speculationWatchpointForMasqueradesAsUndefined();
         DFG_TYPE_CHECK(
             JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1266,7 +1262,6 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r
     
     // We know that within this branch, rightChild must be a cell.
     if (masqueradesAsUndefinedWatchpointValid) {
-        speculationWatchpointForMasqueradesAsUndefined();
         DFG_TYPE_CHECK(
             JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
             m_jit.branchPtr(
@@ -1347,7 +1342,6 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild
     }
 
     if (masqueradesAsUndefinedWatchpointValid) {
-        speculationWatchpointForMasqueradesAsUndefined();
         DFG_TYPE_CHECK(
             JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1374,7 +1368,6 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild
     
     // We know that within this branch, rightChild must be a cell.
     if (masqueradesAsUndefinedWatchpointValid) {
-        speculationWatchpointForMasqueradesAsUndefined();
         DFG_TYPE_CHECK(
             JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
             m_jit.branchPtr(
@@ -1493,8 +1486,6 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
 
     MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
     if (masqueradesAsUndefinedWatchpointValid) {
-        speculationWatchpointForMasqueradesAsUndefined();
-
         DFG_TYPE_CHECK(
             JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
             m_jit.branchPtr(
@@ -1625,7 +1616,6 @@ void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BasicBlock* taken, Ba
     
     MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
     if (masqueradesAsUndefinedWatchpointIsStillValid()) {
-        speculationWatchpointForMasqueradesAsUndefined();
         DFG_TYPE_CHECK(
             JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
             m_jit.branchPtr(
@@ -2433,17 +2423,6 @@ void SpeculativeJIT::compile(Node* node)
         }
         case Array::Double: {
             if (node->arrayMode().isInBounds()) {
-                if (node->arrayMode().isSaneChain()) {
-                    JSGlobalObject* globalObject = m_jit.globalObjectFor(node->codeOrigin);
-                    ASSERT(globalObject->arrayPrototypeChainIsSane());
-                    m_jit.addLazily(
-                        speculationWatchpoint(),
-                        globalObject->arrayPrototype()->structure()->transitionWatchpointSet());
-                    m_jit.addLazily(
-                        speculationWatchpoint(),
-                        globalObject->objectPrototype()->structure()->transitionWatchpointSet());
-                }
-                
                 SpeculateStrictInt32Operand property(this, node->child2());
                 StorageOperand storage(this, node->child3());
             
@@ -3210,10 +3189,6 @@ void SpeculativeJIT::compile(Node* node)
     case NewArray: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
         if (!globalObject->isHavingABadTime() && !hasArrayStorage(node->indexingType())) {
-            m_jit.addLazily(
-                speculationWatchpoint(),
-                globalObject->havingABadTimeWatchpoint());
-            
             Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType());
             ASSERT(structure->indexingType() == node->indexingType());
             ASSERT(
@@ -3382,10 +3357,6 @@ void SpeculativeJIT::compile(Node* node)
     case NewArrayWithSize: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
         if (!globalObject->isHavingABadTime() && !hasArrayStorage(node->indexingType())) {
-            m_jit.addLazily(
-                speculationWatchpoint(),
-                globalObject->havingABadTimeWatchpoint());
-            
             SpeculateStrictInt32Operand size(this, node->child1());
             GPRTemporary result(this);
             GPRTemporary storage(this);
@@ -3460,10 +3431,6 @@ void SpeculativeJIT::compile(Node* node)
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
         IndexingType indexingType = node->indexingType();
         if (!globalObject->isHavingABadTime() && !hasArrayStorage(indexingType)) {
-            m_jit.addLazily(
-                speculationWatchpoint(),
-                globalObject->havingABadTimeWatchpoint());
-            
             unsigned numElements = node->numConstants();
             
             GPRTemporary result(this);
@@ -3617,9 +3584,6 @@ void SpeculativeJIT::compile(Node* node)
     }
 
     case AllocationProfileWatchpoint: {
-        m_jit.addLazily(
-            speculationWatchpoint(),
-            jsCast<JSFunction*>(node->function())->allocationProfileWatchpointSet());
         noResult(node);
         break;
     }
@@ -3901,10 +3865,6 @@ void SpeculativeJIT::compile(Node* node)
         // quite a hint already.
         
         m_jit.addWeakReference(node->structure());
-        m_jit.addLazily(
-            speculationWatchpoint(
-                node->child1()->op() == WeakJSConstant ? BadWeakConstantCacheWatchpoint : BadCacheWatchpoint),
-            node->structure()->transitionWatchpointSet());
         
 #if !ASSERT_DISABLED
         SpeculateCellOperand op1(this, node->child1());
@@ -4087,10 +4047,6 @@ void SpeculativeJIT::compile(Node* node)
     }
 
     case GlobalVarWatchpoint: {
-        WatchpointSet* set = m_jit.globalObjectFor(node->codeOrigin)->symbolTable()->get(
-            identifierUID(node->identifierNumberForCheck())).watchpointSet();
-        m_jit.addLazily(speculationWatchpoint(), set);
-        
 #if DFG_ENABLE(JIT_ASSERT)
         GPRTemporary scratch(this);
         GPRReg scratchGPR = scratch.gpr();
@@ -4112,9 +4068,6 @@ void SpeculativeJIT::compile(Node* node)
     }
 
     case VarInjectionWatchpoint: {
-        WatchpointSet* set = m_jit.globalObjectFor(node->codeOrigin)->varInjectionWatchpoint();
-        m_jit.addLazily(speculationWatchpoint(), set);
-        
         noResult(node);
         break;
     }
@@ -4150,7 +4103,6 @@ void SpeculativeJIT::compile(Node* node)
         isCell.link(&m_jit);
         JITCompiler::Jump notMasqueradesAsUndefined;
         if (masqueradesAsUndefinedWatchpointIsStillValid()) {
-            speculationWatchpointForMasqueradesAsUndefined();
             m_jit.move(TrustedImm32(0), result.gpr());
             notMasqueradesAsUndefined = m_jit.jump();
         } else {
@@ -4711,6 +4663,10 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case InvalidationPoint:
+        emitInvalidationPoint(node);
+        break;
+
     case CheckWatchdogTimer:
         speculationCheck(
             WatchdogTimerFired, JSValueRegs(), 0,
index 31eb9bb..04ec1a3 100644 (file)
@@ -264,8 +264,6 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv
         if (!isKnownCell(operand.node()))
             notCell = m_jit.branchTest64(MacroAssembler::NonZero, argGPR, GPRInfo::tagMaskRegister);
 
-        speculationWatchpointForMasqueradesAsUndefined();
-
         m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultGPR);
         notMasqueradesAsUndefined = m_jit.jump();
     } else {
@@ -331,8 +329,6 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branch
         if (!isKnownCell(operand.node()))
             notCell = m_jit.branchTest64(MacroAssembler::NonZero, argGPR, GPRInfo::tagMaskRegister);
 
-        speculationWatchpointForMasqueradesAsUndefined();
-        
         jump(invert ? taken : notTaken, ForceJump);
     } else {
         GPRTemporary localGlobalObject(this);
@@ -1519,7 +1515,6 @@ void SpeculativeJIT::compileObjectEquality(Node* node)
     GPRReg resultGPR = result.gpr();
    
     if (masqueradesAsUndefinedWatchpointIsStillValid()) {
-        speculationWatchpointForMasqueradesAsUndefined();
         DFG_TYPE_CHECK(
             JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1593,7 +1588,6 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r
     }
 
     if (masqueradesAsUndefinedWatchpointValid) {
-        speculationWatchpointForMasqueradesAsUndefined();
         DFG_TYPE_CHECK(
             JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1620,7 +1614,6 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r
     
     // We know that within this branch, rightChild must be a cell. 
     if (masqueradesAsUndefinedWatchpointValid) {
-        speculationWatchpointForMasqueradesAsUndefined();
         DFG_TYPE_CHECK(
             JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1698,7 +1691,6 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild
     }
 
     if (masqueradesAsUndefinedWatchpointValid) {
-        speculationWatchpointForMasqueradesAsUndefined();
         DFG_TYPE_CHECK(
             JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1725,7 +1717,6 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild
     
     // We know that within this branch, rightChild must be a cell. 
     if (masqueradesAsUndefinedWatchpointValid) {
-        speculationWatchpointForMasqueradesAsUndefined();
         DFG_TYPE_CHECK(
             JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1872,7 +1863,6 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
 
     MacroAssembler::Jump notCell = m_jit.branchTest64(MacroAssembler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
     if (masqueradesAsUndefinedWatchpointValid) {
-        speculationWatchpointForMasqueradesAsUndefined();
         DFG_TYPE_CHECK(
             JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal,
@@ -2016,8 +2006,6 @@ void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BasicBlock* taken, Ba
     
     MacroAssembler::Jump notCell = m_jit.branchTest64(MacroAssembler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
     if (masqueradesAsUndefinedWatchpointIsStillValid()) {
-        speculationWatchpointForMasqueradesAsUndefined();
-
         DFG_TYPE_CHECK(
             JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -2738,17 +2726,6 @@ void SpeculativeJIT::compile(Node* node)
 
         case Array::Double: {
             if (node->arrayMode().isInBounds()) {
-                if (node->arrayMode().isSaneChain()) {
-                    JSGlobalObject* globalObject = m_jit.globalObjectFor(node->codeOrigin);
-                    ASSERT(globalObject->arrayPrototypeChainIsSane());
-                    m_jit.addLazily(
-                        speculationWatchpoint(),
-                        globalObject->arrayPrototype()->structure()->transitionWatchpointSet());
-                    m_jit.addLazily(
-                        speculationWatchpoint(),
-                        globalObject->objectPrototype()->structure()->transitionWatchpointSet());
-                }
-                
                 SpeculateStrictInt32Operand property(this, node->child2());
                 StorageOperand storage(this, node->child3());
             
@@ -3524,10 +3501,6 @@ void SpeculativeJIT::compile(Node* node)
     case NewArray: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
         if (!globalObject->isHavingABadTime() && !hasArrayStorage(node->indexingType())) {
-            m_jit.addLazily(
-                speculationWatchpoint(),
-                globalObject->havingABadTimeWatchpoint());
-            
             Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType());
             RELEASE_ASSERT(structure->indexingType() == node->indexingType());
             ASSERT(
@@ -3699,10 +3672,6 @@ void SpeculativeJIT::compile(Node* node)
     case NewArrayWithSize: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
         if (!globalObject->isHavingABadTime() && !hasArrayStorage(node->indexingType())) {
-            m_jit.addLazily(
-                speculationWatchpoint(),
-                globalObject->havingABadTimeWatchpoint());
-            
             SpeculateStrictInt32Operand size(this, node->child1());
             GPRTemporary result(this);
             GPRTemporary storage(this);
@@ -3774,10 +3743,6 @@ void SpeculativeJIT::compile(Node* node)
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
         IndexingType indexingType = node->indexingType();
         if (!globalObject->isHavingABadTime() && !hasArrayStorage(indexingType)) {
-            m_jit.addLazily(
-                speculationWatchpoint(),
-                globalObject->havingABadTimeWatchpoint());
-            
             unsigned numElements = node->numConstants();
             
             GPRTemporary result(this);
@@ -3920,9 +3885,6 @@ void SpeculativeJIT::compile(Node* node)
     }
         
     case AllocationProfileWatchpoint: {
-        m_jit.addLazily(
-            speculationWatchpoint(),
-            jsCast<JSFunction*>(node->function())->allocationProfileWatchpointSet());
         noResult(node);
         break;
     }
@@ -4195,10 +4157,6 @@ void SpeculativeJIT::compile(Node* node)
         // quite a hint already.
         
         m_jit.addWeakReference(node->structure());
-        m_jit.addLazily(
-            speculationWatchpoint(
-                node->child1()->op() == WeakJSConstant ? BadWeakConstantCacheWatchpoint : BadCacheWatchpoint),
-            node->structure()->transitionWatchpointSet());
 
 #if !ASSERT_DISABLED
         SpeculateCellOperand op1(this, node->child1());
@@ -4368,10 +4326,6 @@ void SpeculativeJIT::compile(Node* node)
     }
 
     case GlobalVarWatchpoint: {
-        WatchpointSet* set = m_jit.globalObjectFor(node->codeOrigin)->symbolTable()->get(
-            identifierUID(node->identifierNumberForCheck())).watchpointSet();
-        m_jit.addLazily(speculationWatchpoint(), set);
-        
 #if DFG_ENABLE(JIT_ASSERT)
         GPRTemporary scratch(this);
         GPRReg scratchGPR = scratch.gpr();
@@ -4388,9 +4342,6 @@ void SpeculativeJIT::compile(Node* node)
     }
 
     case VarInjectionWatchpoint: {
-        WatchpointSet* set = m_jit.globalObjectFor(node->codeOrigin)->varInjectionWatchpoint();
-        m_jit.addLazily(speculationWatchpoint(), set);
-        
         noResult(node);
         break;
     }
@@ -4426,7 +4377,6 @@ void SpeculativeJIT::compile(Node* node)
         isCell.link(&m_jit);
         JITCompiler::Jump notMasqueradesAsUndefined;
         if (masqueradesAsUndefinedWatchpointIsStillValid()) {
-            speculationWatchpointForMasqueradesAsUndefined();
             m_jit.move(TrustedImm32(0), result.gpr());
             notMasqueradesAsUndefined = m_jit.jump();
         } else {
@@ -4958,6 +4908,10 @@ void SpeculativeJIT::compile(Node* node)
         terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
         break;
     }
+        
+    case InvalidationPoint:
+        emitInvalidationPoint(node);
+        break;
 
     case CheckWatchdogTimer:
         speculationCheck(
diff --git a/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp b/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp
new file mode 100644 (file)
index 0000000..7230197
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "DFGWatchpointCollectionPhase.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "ArrayPrototype.h"
+#include "DFGClobberize.h"
+#include "DFGGraph.h"
+#include "DFGPhase.h"
+#include "Operations.h"
+
+namespace JSC { namespace DFG {
+
+class WatchpointCollectionPhase : public Phase {
+    static const bool verbose = false;
+    
+public:
+    WatchpointCollectionPhase(Graph& graph)
+        : Phase(graph, "watchpoint collection")
+    {
+    }
+    
+    bool run()
+    {
+        for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+            BasicBlock* block = m_graph.block(blockIndex);
+            if (!block)
+                continue;
+            
+            for (unsigned nodeIndex = block->size(); nodeIndex--;) {
+                m_node = block->at(nodeIndex);
+                handle();
+            }
+        }
+        
+        return true;
+    }
+
+private:
+    void handle()
+    {
+        DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, handleEdge);
+        
+        switch (m_node->op()) {
+        case CompareEqConstant:
+        case IsUndefined:
+            handleMasqueradesAsUndefined();
+            break;
+            
+        case CompareEq:
+            if (m_node->isBinaryUseKind(ObjectUse)
+                || (m_node->child1().useKind() == ObjectUse && m_node->child2().useKind() == ObjectOrOtherUse)
+                || (m_node->child1().useKind() == ObjectOrOtherUse && m_node->child2().useKind() == ObjectUse))
+                handleMasqueradesAsUndefined();
+            break;
+            
+        case LogicalNot:
+        case Branch:
+            if (m_node->child1().useKind() == ObjectOrOtherUse)
+                handleMasqueradesAsUndefined();
+            break;
+            
+        case GetByVal:
+            if (m_node->arrayMode().type() == Array::Double
+                && m_node->arrayMode().isSaneChain()) {
+                addLazily(globalObject()->arrayPrototype()->structure()->transitionWatchpointSet());
+                addLazily(globalObject()->objectPrototype()->structure()->transitionWatchpointSet());
+            }
+            
+            if (m_node->arrayMode().type() == Array::String)
+                handleStringGetByVal();
+            break;
+            
+        case StringCharAt:
+            handleStringGetByVal();
+            break;
+            
+        case NewArray:
+        case NewArrayWithSize:
+        case NewArrayBuffer:
+            if (!globalObject()->isHavingABadTime() && !hasArrayStorage(m_node->indexingType()))
+                addLazily(globalObject()->havingABadTimeWatchpoint());
+            break;
+            
+        case AllocationProfileWatchpoint:
+            addLazily(jsCast<JSFunction*>(m_node->function())->allocationProfileWatchpointSet());
+            break;
+            
+        case StructureTransitionWatchpoint:
+            m_graph.watchpoints().addLazily(
+                m_node->codeOrigin,
+                m_node->child1()->op() == WeakJSConstant ? BadWeakConstantCacheWatchpoint : BadCacheWatchpoint,
+                m_node->structure()->transitionWatchpointSet());
+            break;
+            
+        case GlobalVarWatchpoint:
+            addLazily(
+                globalObject()->symbolTable()->get(
+                    m_graph.identifiers()[m_node->identifierNumberForCheck()]).watchpointSet());
+            break;
+            
+        case VarInjectionWatchpoint:
+            addLazily(globalObject()->varInjectionWatchpoint());
+            break;
+            
+        default:
+            break;
+        }
+    }
+    
+    void handleEdge(Node*, Edge edge)
+    {
+        switch (edge.useKind()) {
+        case StringObjectUse:
+        case StringOrStringObjectUse: {
+            Structure* stringObjectStructure = globalObject()->stringObjectStructure();
+            Structure* stringPrototypeStructure = stringObjectStructure->storedPrototype().asCell()->structure();
+            ASSERT(m_graph.watchpoints().isValidOrMixed(stringPrototypeStructure->transitionWatchpointSet()));
+            
+            m_graph.watchpoints().addLazily(
+                m_node->codeOrigin, NotStringObject,
+                stringPrototypeStructure->transitionWatchpointSet());
+            break;
+        }
+            
+        default:
+            break;
+        }
+    }
+    
+    void handleMasqueradesAsUndefined()
+    {
+        if (m_graph.masqueradesAsUndefinedWatchpointIsStillValid(m_node->codeOrigin))
+            addLazily(globalObject()->masqueradesAsUndefinedWatchpoint());
+    }
+    
+    void handleStringGetByVal()
+    {
+        if (!m_node->arrayMode().isOutOfBounds())
+            return;
+        if (!globalObject()->stringPrototypeChainIsSane())
+            return;
+        addLazily(globalObject()->stringPrototype()->structure()->transitionWatchpointSet());
+        addLazily(globalObject()->objectPrototype()->structure()->transitionWatchpointSet());
+    }
+
+    void addLazily(WatchpointSet* set)
+    {
+        m_graph.watchpoints().addLazily(set);
+    }
+    void addLazily(InlineWatchpointSet& set)
+    {
+        m_graph.watchpoints().addLazily(set);
+    }
+    
+    JSGlobalObject* globalObject()
+    {
+        return m_graph.globalObjectFor(m_node->codeOrigin);
+    }
+    
+    Node* m_node;
+};
+
+bool performWatchpointCollection(Graph& graph)
+{
+    SamplingRegion samplingRegion("DFG Watchpoint Collection Phase");
+    return runPhase<WatchpointCollectionPhase>(graph);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.h b/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.h
new file mode 100644 (file)
index 0000000..eb41522
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGWatchpointCollectionPhase_h
+#define DFGWatchpointCollectionPhase_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+class Graph;
+
+// Collects all desired watchpoints into the Graph::watchpoints() data structure.
+
+bool performWatchpointCollection(Graph&);
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGWatchpointCollectionPhase_h
+
index d84ec02..be56492 100644 (file)
@@ -95,6 +95,7 @@ inline CapabilityLevel canCompile(Node* node)
     case GetClosureVar:
     case PutClosureVar:
     case Int52ToValue:
+    case InvalidationPoint:
         // These are OK.
         break;
     case GetById:
index afea8d9..236a90b 100644 (file)
@@ -447,6 +447,9 @@ private:
         case ForceOSRExit:
             compileForceOSRExit();
             break;
+        case InvalidationPoint:
+            compileInvalidationPoint();
+            break;
         case ValueToInt32:
             compileValueToInt32();
             break;
@@ -1139,10 +1142,6 @@ private:
     void compileStructureTransitionWatchpoint()
     {
         addWeakReference(m_node->structure());
-        
-        // FIXME: Implement structure transition watchpoints.
-        // https://bugs.webkit.org/show_bug.cgi?id=113647
-        
         speculateCell(m_node->child1());
     }
     
@@ -1325,11 +1324,6 @@ private:
             
         case Array::Double: {
             if (m_node->arrayMode().isInBounds()) {
-                if (m_node->arrayMode().isSaneChain()) {
-                    // FIXME: Implement structure transition watchpoints.
-                    // https://bugs.webkit.org/show_bug.cgi?id=113647
-                }
-            
                 speculate(
                     OutOfBounds, noValue(), 0,
                     m_out.aboveOrEqual(
@@ -1695,8 +1689,8 @@ private:
     
     void compileGlobalVarWatchpoint()
     {
-        // FIXME: Implement watchpoints.
-        // https://bugs.webkit.org/show_bug.cgi?id=113647
+        // FIXME: In debug mode we could emit some assertion code here.
+        // https://bugs.webkit.org/show_bug.cgi?id=123471
     }
     
     void compileGetMyScope()
@@ -1745,7 +1739,6 @@ private:
     void compileCompareEqConstant()
     {
         ASSERT(m_graph.valueOfJSConstant(m_node->child2().node()).isNull());
-        masqueradesAsUndefinedWatchpointIfIsStillValid();
         setBoolean(
             equalNullOrUndefined(
                 m_node->child1(), AllCellsAreFalse, EqualNullOrUndefined));
@@ -1774,7 +1767,6 @@ private:
         }
         
         if (m_node->isBinaryUseKind(ObjectUse)) {
-            masqueradesAsUndefinedWatchpointIfIsStillValid();
             setBoolean(
                 m_out.equal(
                     lowNonNullObject(m_node->child1()),
@@ -1790,7 +1782,7 @@ private:
         JSValue constant = m_graph.valueOfJSConstant(m_node->child2().node());
 
         if (constant.isUndefinedOrNull()
-            && !masqueradesAsUndefinedWatchpointIfIsStillValid()) {
+            && !masqueradesAsUndefinedWatchpointIsStillValid()) {
             if (constant.isNull()) {
                 setBoolean(equalNullOrUndefined(m_node->child1(), AllCellsAreFalse, EqualNull));
                 return;
@@ -2116,6 +2108,12 @@ private:
         terminate(InadequateCoverage);
     }
     
+    void compileInvalidationPoint()
+    {
+        // FIXME: Implement invalidation points in terms of llvm.stackmap.
+        // https://bugs.webkit.org/show_bug.cgi?id=113647
+    }
+    
     LValue boolify(Edge edge)
     {
         switch (edge.useKind()) {
@@ -2155,7 +2153,7 @@ private:
         Edge edge, StringOrObjectMode cellMode, EqualNullOrUndefinedMode primitiveMode,
         OperandSpeculationMode operandMode = AutomaticOperandSpeculation)
     {
-        bool validWatchpoint = masqueradesAsUndefinedWatchpointIfIsStillValid();
+        bool validWatchpoint = masqueradesAsUndefinedWatchpointIsStillValid();
         
         LValue value = lowJSValue(edge, operandMode);
         
@@ -3077,7 +3075,7 @@ private:
         FTL_TYPE_CHECK(
             jsValueValue(cell), edge, SpecObject, 
             m_out.equal(structure, m_out.constIntPtr(vm().stringStructure.get())));
-        if (masqueradesAsUndefinedWatchpointIfIsStillValid())
+        if (masqueradesAsUndefinedWatchpointIsStillValid())
             return;
         
         speculate(
@@ -3127,16 +3125,6 @@ private:
         return m_graph.masqueradesAsUndefinedWatchpointIsStillValid(m_node->codeOrigin);
     }
     
-    bool masqueradesAsUndefinedWatchpointIfIsStillValid()
-    {
-        if (!masqueradesAsUndefinedWatchpointIsStillValid())
-            return false;
-        
-        // FIXME: Implement masquerades-as-undefined watchpoints.
-        // https://bugs.webkit.org/show_bug.cgi?id=113647
-        return true;
-    }
-    
     enum ExceptionCheckMode { NoExceptions, CheckExceptions };
     
     LValue vmCall(LValue function, ExceptionCheckMode mode = CheckExceptions)
index ff18b9f..aec61a5 100644 (file)
@@ -1105,7 +1105,7 @@ char* JIT_OPERATION operationOptimize(ExecState* exec, int32_t bytecodeIndex)
                     "Triggering reoptimization of ", *codeBlock,
                     "(", *codeBlock->replacement(), ") (in loop).\n");
             }
-            codeBlock->reoptimize();
+            codeBlock->replacement()->jettison(CountReoptimization);
             return 0;
         }
     } else {
@@ -1190,7 +1190,7 @@ char* JIT_OPERATION operationOptimize(ExecState* exec, int32_t bytecodeIndex)
                 "Triggering reoptimization of ", *codeBlock, " -> ",
                 *codeBlock->replacement(), " (after OSR fail).\n");
         }
-        codeBlock->reoptimize();
+        optimizedCodeBlock->jettison(CountReoptimization);
         return 0;
     }