Commit d84425d1 authored by fpizlo@apple.com's avatar 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.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@158304 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 259217da
......@@ -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
......
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
......
......@@ -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 \
......
......@@ -300,6 +300,7 @@
<ClCompile Include="..\bytecode\CallLinkStatus.cpp" />
<ClCompile Include="..\bytecode\CodeBlock.cpp" />
<ClCompile Include="..\bytecode\CodeBlockHash.cpp" />
<ClCompile Include="..\bytecode\CodeBlockJettisoningWatchpoint.cpp" />
<ClCompile Include="..\bytecode\CodeOrigin.cpp" />
<ClCompile Include="..\bytecode\CodeType.cpp" />
<ClCompile Include="..\bytecode\DeferredCompilationCallback.cpp" />
......@@ -313,6 +314,7 @@
<ClCompile Include="..\bytecode\MethodOfGettingAValueProfile.cpp" />
<ClCompile Include="..\bytecode\Opcode.cpp" />
<ClCompile Include="..\bytecode\PolymorphicPutByIdList.cpp" />
<ClCompile Include="..\bytecode\ProfiledCodeBlockJettisoningWatchpoint.cpp" />
<ClCompile Include="..\bytecode\PreciseJumpTargets.cpp" />
<ClCompile Include="..\bytecode\PutByIdStatus.cpp" />
<ClCompile Include="..\bytecode\ReduceWhitespace.cpp" />
......@@ -476,7 +478,6 @@
<ClCompile Include="..\jit\JITStubs.cpp" />
<ClCompile Include="..\jit\JITThunks.cpp" />
<ClCompile Include="..\jit\JITToDFGDeferredCompilationCallback.cpp" />
<ClCompile Include="..\jit\JumpReplacementWatchpoint.cpp" />
<ClCompile Include="..\jit\Repatch.cpp" />
<ClCompile Include="..\jit\ThunkGenerators.cpp" />
<ClCompile Include="..\llint\LLIntCLoop.cpp" />
......@@ -736,6 +737,7 @@
<ClInclude Include="..\bytecode\CallReturnOffsetToBytecodeOffset.h" />
<ClInclude Include="..\bytecode\CodeBlock.h" />
<ClInclude Include="..\bytecode\CodeBlockHash.h" />
<ClInclude Include="..\bytecode\CodeBlockJettisoningWatchpoint.h" />
<ClInclude Include="..\bytecode\CodeBlockWithJITType.h" />
<ClInclude Include="..\bytecode\CodeOrigin.h" />
<ClInclude Include="..\bytecode\CodeType.h" />
......@@ -759,6 +761,7 @@
<ClInclude Include="..\bytecode\Opcode.h" />
<ClInclude Include="..\bytecode\Operands.h" />
<ClInclude Include="..\bytecode\PolymorphicPutByIdList.h" />
<ClInclude Include="..\bytecode\ProfiledCodeBlockJettisoningWatchpoint.h" />
<ClInclude Include="..\bytecode\PreciseJumpTargets.h" />
<ClInclude Include="..\bytecode\PutByIdStatus.h" />
<ClInclude Include="..\bytecode\PutKind.h" />
......@@ -1000,7 +1003,6 @@
<ClInclude Include="..\jit\JITToDFGDeferredCompilationCallback.h" />
<ClInclude Include="..\jit\JITWriteBarrier.h" />
<ClInclude Include="..\jit\JSInterfaceJIT.h" />
<ClInclude Include="..\jit\JumpReplacementWatchpoint.h" />
<ClCompile Include="..\jit\RegisterSet.cpp" />
<ClInclude Include="..\jit\RegisterSet.h" />
<ClInclude Include="..\jit\Repatch.h" />
......
......@@ -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;
......
......@@ -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
......
......@@ -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
......
/*
* 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
/*
* 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
......@@ -23,58 +23,35 @@
* 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
......@@ -76,6 +76,8 @@ const char* exitKindToString(ExitKind kind)
return "Uncountable";
case UncountableWatchpoint:
return "UncountableWatchpoint";
case UncountableInvalidation:
return "UncountableInvalidation";
case WatchdogTimerFired:
return "WatchdogTimerFired";
}
......
......@@ -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.
};
......
/*
* 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
/*
* 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: