FTL should have an explicit notion of bytecode liveness
https://bugs.webkit.org/show_bug.cgi?id=124181
Source/JavaScriptCore:
Reviewed by Sam Weinig.
This makes FTL OSR exit use bytecode liveness analysis to determine which variables
to include values for. The decision of how to get the values of variables is based on
forward propagation of MovHints and SetLocals.
This fixes a bunch of bugs (like https://bugs.webkit.org/show_bug.cgi?id=124138 but
also others that I noticed when I started writing more targetted tests) and allows us
to remove some sketchy code.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeBasicBlock.h:
* bytecode/BytecodeLivenessAnalysis.cpp:
(JSC::isValidRegisterForLiveness):
(JSC::setForOperand):
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
(JSC::stepOverInstruction):
(JSC::computeLocalLivenessForBytecodeOffset):
(JSC::BytecodeLivenessAnalysis::runLivenessFixpoint):
(JSC::BytecodeLivenessAnalysis::operandIsLiveAtBytecodeOffset):
(JSC::getLivenessInfo):
(JSC::BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeOffset):
(JSC::BytecodeLivenessAnalysis::computeFullLiveness):
* bytecode/BytecodeLivenessAnalysis.h:
* bytecode/BytecodeLivenessAnalysisInlines.h: Added.
(JSC::operandIsAlwaysLive):
(JSC::operandThatIsNotAlwaysLiveIsLive):
(JSC::operandIsLive):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::captureCount):
(JSC::CodeBlock::captureStart):
(JSC::CodeBlock::captureEnd):
* bytecode/CodeOrigin.cpp:
(JSC::InlineCallFrame::dumpInContext):
* bytecode/FullBytecodeLiveness.h: Added.
(JSC::FullBytecodeLiveness::FullBytecodeLiveness):
(JSC::FullBytecodeLiveness::getOut):
(JSC::FullBytecodeLiveness::operandIsLive):
(JSC::FullBytecodeLiveness::getLiveness):
* dfg/DFGAvailability.cpp: Added.
(JSC::DFG::Availability::dump):
(JSC::DFG::Availability::dumpInContext):
* dfg/DFGAvailability.h: Added.
(JSC::DFG::Availability::Availability):
(JSC::DFG::Availability::unavailable):
(JSC::DFG::Availability::withFlush):
(JSC::DFG::Availability::withNode):
(JSC::DFG::Availability::withUnavailableNode):
(JSC::DFG::Availability::nodeIsUndecided):
(JSC::DFG::Availability::nodeIsUnavailable):
(JSC::DFG::Availability::hasNode):
(JSC::DFG::Availability::node):
(JSC::DFG::Availability::flushedAt):
(JSC::DFG::Availability::operator!):
(JSC::DFG::Availability::operator==):
(JSC::DFG::Availability::merge):
(JSC::DFG::Availability::mergeNodes):
(JSC::DFG::Availability::unavailableMarker):
* dfg/DFGBasicBlock.h:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGDisassembler.cpp:
(JSC::DFG::Disassembler::Disassembler):
* dfg/DFGFlushFormat.cpp:
(WTF::printInternal):
* dfg/DFGFlushFormat.h:
(JSC::DFG::resultFor):
(JSC::DFG::useKindFor):
(JSC::DFG::dataFormatFor):
* dfg/DFGFlushedAt.cpp:
(JSC::DFG::FlushedAt::dump):
* dfg/DFGFlushedAt.h:
(JSC::DFG::FlushedAt::FlushedAt):
(JSC::DFG::FlushedAt::merge):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
(JSC::DFG::Graph::livenessFor):
(JSC::DFG::Graph::isLiveInBytecode):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::baselineCodeBlockFor):
* dfg/DFGOSRAvailabilityAnalysisPhase.cpp:
(JSC::DFG::OSRAvailabilityAnalysisPhase::run):
* dfg/DFGOSRAvailabilityAnalysisPhase.h:
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
* dfg/DFGResurrectionForValidationPhase.cpp: Added.
(JSC::DFG::ResurrectionForValidationPhase::ResurrectionForValidationPhase):
(JSC::DFG::ResurrectionForValidationPhase::run):
(JSC::DFG::performResurrectionForValidation):
* dfg/DFGResurrectionForValidationPhase.h: Added.
* dfg/DFGSSAConversionPhase.cpp:
(JSC::DFG::SSAConversionPhase::run):
* dfg/DFGValueSource.h:
(JSC::DFG::ValueSource::forFlushFormat):
* dfg/DFGVariableAccessData.h:
* ftl/FTLExitValue.cpp:
(JSC::FTL::ExitValue::dumpInContext):
* ftl/FTLInlineCacheSize.cpp:
(JSC::FTL::sizeOfGetById):
* ftl/FTLLocation.cpp:
(JSC::FTL::Location::gpr):
(JSC::FTL::Location::fpr):
(JSC::FTL::Location::directGPR):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM):
(JSC::FTL::LowerDFGToLLVM::compileBlock):
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileSetLocal):
(JSC::FTL::LowerDFGToLLVM::compileZombieHint):
(JSC::FTL::LowerDFGToLLVM::compilePutById):
(JSC::FTL::LowerDFGToLLVM::compileInvalidationPoint):
(JSC::FTL::LowerDFGToLLVM::initializeOSRExitStateForBlock):
(JSC::FTL::LowerDFGToLLVM::appendOSRExit):
(JSC::FTL::LowerDFGToLLVM::emitOSRExitCall):
(JSC::FTL::LowerDFGToLLVM::buildExitArguments):
(JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
(JSC::FTL::LowerDFGToLLVM::observeMovHint):
* ftl/FTLOutput.h:
(JSC::FTL::Output::alloca):
* ftl/FTLValueSource.cpp: Removed.
* ftl/FTLValueSource.h: Removed.
* llvm/LLVMAPIFunctions.h:
* runtime/DumpContext.cpp:
(JSC::DumpContext::DumpContext):
* runtime/DumpContext.h:
* runtime/Options.h:
* runtime/SymbolTable.h:
(JSC::SharedSymbolTable::captureStart):
(JSC::SharedSymbolTable::captureEnd):
(JSC::SharedSymbolTable::captureCount):
Tools:
Reviewed by Mark Hahnenberg.
* Scripts/run-jsc-stress-tests:
LayoutTests:
Reviewed by Mark Hahnenberg or Sam Weinig.
I totally added this test after the rest of the patch was r+'d. Under the right tier-up
modes this triggers one of the bugs that the rest of the patch is trying to avoid.
* js/regress/script-tests/weird-inlining-const-prop.js: Added.
(foo):
(bar):
(fuzz):
(testImpl):
(test):
* js/regress/weird-inlining-const-prop-expected.txt: Added.
* js/regress/weird-inlining-const-prop.html: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@159394 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 64c47cd..e622a00 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -91,6 +91,7 @@
dfg/DFGArgumentsSimplificationPhase.cpp
dfg/DFGArrayMode.cpp
dfg/DFGAtTailAbstractState.cpp
+ dfg/DFGAvailability.cpp
dfg/DFGBackwardsPropagationPhase.cpp
dfg/DFGBasicBlock.cpp
dfg/DFGBinarySwitch.cpp
@@ -158,6 +159,7 @@
dfg/DFGPlan.cpp
dfg/DFGPredictionInjectionPhase.cpp
dfg/DFGPredictionPropagationPhase.cpp
+ dfg/DFGResurrectionForValidationPhase.cpp
dfg/DFGSSAConversionPhase.cpp
dfg/DFGSpeculativeJIT.cpp
dfg/DFGSpeculativeJIT32_64.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index e2402a8..f036306 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,5 +1,145 @@
2013-11-16 Filip Pizlo <fpizlo@apple.com>
+ FTL should have an explicit notion of bytecode liveness
+ https://bugs.webkit.org/show_bug.cgi?id=124181
+
+ Reviewed by Sam Weinig.
+
+ This makes FTL OSR exit use bytecode liveness analysis to determine which variables
+ to include values for. The decision of how to get the values of variables is based on
+ forward propagation of MovHints and SetLocals.
+
+ This fixes a bunch of bugs (like https://bugs.webkit.org/show_bug.cgi?id=124138 but
+ also others that I noticed when I started writing more targetted tests) and allows us
+ to remove some sketchy code.
+
+ * CMakeLists.txt:
+ * GNUmakefile.list.am:
+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * bytecode/BytecodeBasicBlock.h:
+ * bytecode/BytecodeLivenessAnalysis.cpp:
+ (JSC::isValidRegisterForLiveness):
+ (JSC::setForOperand):
+ (JSC::computeUsesForBytecodeOffset):
+ (JSC::computeDefsForBytecodeOffset):
+ (JSC::stepOverInstruction):
+ (JSC::computeLocalLivenessForBytecodeOffset):
+ (JSC::BytecodeLivenessAnalysis::runLivenessFixpoint):
+ (JSC::BytecodeLivenessAnalysis::operandIsLiveAtBytecodeOffset):
+ (JSC::getLivenessInfo):
+ (JSC::BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeOffset):
+ (JSC::BytecodeLivenessAnalysis::computeFullLiveness):
+ * bytecode/BytecodeLivenessAnalysis.h:
+ * bytecode/BytecodeLivenessAnalysisInlines.h: Added.
+ (JSC::operandIsAlwaysLive):
+ (JSC::operandThatIsNotAlwaysLiveIsLive):
+ (JSC::operandIsLive):
+ * bytecode/CodeBlock.h:
+ (JSC::CodeBlock::captureCount):
+ (JSC::CodeBlock::captureStart):
+ (JSC::CodeBlock::captureEnd):
+ * bytecode/CodeOrigin.cpp:
+ (JSC::InlineCallFrame::dumpInContext):
+ * bytecode/FullBytecodeLiveness.h: Added.
+ (JSC::FullBytecodeLiveness::FullBytecodeLiveness):
+ (JSC::FullBytecodeLiveness::getOut):
+ (JSC::FullBytecodeLiveness::operandIsLive):
+ (JSC::FullBytecodeLiveness::getLiveness):
+ * dfg/DFGAvailability.cpp: Added.
+ (JSC::DFG::Availability::dump):
+ (JSC::DFG::Availability::dumpInContext):
+ * dfg/DFGAvailability.h: Added.
+ (JSC::DFG::Availability::Availability):
+ (JSC::DFG::Availability::unavailable):
+ (JSC::DFG::Availability::withFlush):
+ (JSC::DFG::Availability::withNode):
+ (JSC::DFG::Availability::withUnavailableNode):
+ (JSC::DFG::Availability::nodeIsUndecided):
+ (JSC::DFG::Availability::nodeIsUnavailable):
+ (JSC::DFG::Availability::hasNode):
+ (JSC::DFG::Availability::node):
+ (JSC::DFG::Availability::flushedAt):
+ (JSC::DFG::Availability::operator!):
+ (JSC::DFG::Availability::operator==):
+ (JSC::DFG::Availability::merge):
+ (JSC::DFG::Availability::mergeNodes):
+ (JSC::DFG::Availability::unavailableMarker):
+ * dfg/DFGBasicBlock.h:
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGDisassembler.cpp:
+ (JSC::DFG::Disassembler::Disassembler):
+ * dfg/DFGFlushFormat.cpp:
+ (WTF::printInternal):
+ * dfg/DFGFlushFormat.h:
+ (JSC::DFG::resultFor):
+ (JSC::DFG::useKindFor):
+ (JSC::DFG::dataFormatFor):
+ * dfg/DFGFlushedAt.cpp:
+ (JSC::DFG::FlushedAt::dump):
+ * dfg/DFGFlushedAt.h:
+ (JSC::DFG::FlushedAt::FlushedAt):
+ (JSC::DFG::FlushedAt::merge):
+ * dfg/DFGGraph.cpp:
+ (JSC::DFG::Graph::dump):
+ (JSC::DFG::Graph::livenessFor):
+ (JSC::DFG::Graph::isLiveInBytecode):
+ * dfg/DFGGraph.h:
+ (JSC::DFG::Graph::baselineCodeBlockFor):
+ * dfg/DFGOSRAvailabilityAnalysisPhase.cpp:
+ (JSC::DFG::OSRAvailabilityAnalysisPhase::run):
+ * dfg/DFGOSRAvailabilityAnalysisPhase.h:
+ * dfg/DFGPlan.cpp:
+ (JSC::DFG::Plan::compileInThreadImpl):
+ * dfg/DFGResurrectionForValidationPhase.cpp: Added.
+ (JSC::DFG::ResurrectionForValidationPhase::ResurrectionForValidationPhase):
+ (JSC::DFG::ResurrectionForValidationPhase::run):
+ (JSC::DFG::performResurrectionForValidation):
+ * dfg/DFGResurrectionForValidationPhase.h: Added.
+ * dfg/DFGSSAConversionPhase.cpp:
+ (JSC::DFG::SSAConversionPhase::run):
+ * dfg/DFGValueSource.h:
+ (JSC::DFG::ValueSource::forFlushFormat):
+ * dfg/DFGVariableAccessData.h:
+ * ftl/FTLExitValue.cpp:
+ (JSC::FTL::ExitValue::dumpInContext):
+ * ftl/FTLInlineCacheSize.cpp:
+ (JSC::FTL::sizeOfGetById):
+ * ftl/FTLLocation.cpp:
+ (JSC::FTL::Location::gpr):
+ (JSC::FTL::Location::fpr):
+ (JSC::FTL::Location::directGPR):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM):
+ (JSC::FTL::LowerDFGToLLVM::compileBlock):
+ (JSC::FTL::LowerDFGToLLVM::compileNode):
+ (JSC::FTL::LowerDFGToLLVM::compileSetLocal):
+ (JSC::FTL::LowerDFGToLLVM::compileZombieHint):
+ (JSC::FTL::LowerDFGToLLVM::compilePutById):
+ (JSC::FTL::LowerDFGToLLVM::compileInvalidationPoint):
+ (JSC::FTL::LowerDFGToLLVM::initializeOSRExitStateForBlock):
+ (JSC::FTL::LowerDFGToLLVM::appendOSRExit):
+ (JSC::FTL::LowerDFGToLLVM::emitOSRExitCall):
+ (JSC::FTL::LowerDFGToLLVM::buildExitArguments):
+ (JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
+ (JSC::FTL::LowerDFGToLLVM::observeMovHint):
+ * ftl/FTLOutput.h:
+ (JSC::FTL::Output::alloca):
+ * ftl/FTLValueSource.cpp: Removed.
+ * ftl/FTLValueSource.h: Removed.
+ * llvm/LLVMAPIFunctions.h:
+ * runtime/DumpContext.cpp:
+ (JSC::DumpContext::DumpContext):
+ * runtime/DumpContext.h:
+ * runtime/Options.h:
+ * runtime/SymbolTable.h:
+ (JSC::SharedSymbolTable::captureStart):
+ (JSC::SharedSymbolTable::captureEnd):
+ (JSC::SharedSymbolTable::captureCount):
+
+2013-11-16 Filip Pizlo <fpizlo@apple.com>
+
Fix indentation of JSActivation.h.
Rubber stamped by Mark Hahnenberg.
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index 8706e4e..b142b46 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -100,10 +100,11 @@
Source/JavaScriptCore/bytecode/ArrayProfile.cpp \
Source/JavaScriptCore/bytecode/ArrayProfile.h \
Source/JavaScriptCore/bytecode/ByValInfo.h \
- Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp \
- Source/JavaScriptCore/bytecode/BytecodeBasicBlock.h \
- Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp \
- Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.h \
+ Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp \
+ Source/JavaScriptCore/bytecode/BytecodeBasicBlock.h \
+ Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp \
+ Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.h \
+ Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysisInlines.h \
Source/JavaScriptCore/bytecode/BytecodeConventions.h \
Source/JavaScriptCore/bytecode/CallLinkInfo.cpp \
Source/JavaScriptCore/bytecode/CallLinkInfo.h \
@@ -132,6 +133,7 @@
Source/JavaScriptCore/bytecode/ExitKind.cpp \
Source/JavaScriptCore/bytecode/ExitKind.h \
Source/JavaScriptCore/bytecode/ExpressionRangeInfo.h \
+ Source/JavaScriptCore/bytecode/FullBytecodeLiveness.h \
Source/JavaScriptCore/bytecode/GetByIdStatus.cpp \
Source/JavaScriptCore/bytecode/GetByIdStatus.h \
Source/JavaScriptCore/bytecode/HandlerInfo.h \
@@ -207,6 +209,8 @@
Source/JavaScriptCore/dfg/DFGArrayifySlowPathGenerator.h \
Source/JavaScriptCore/dfg/DFGAtTailAbstractState.cpp \
Source/JavaScriptCore/dfg/DFGAtTailAbstractState.h \
+ Source/JavaScriptCore/dfg/DFGAvailability.cpp \
+ Source/JavaScriptCore/dfg/DFGAvailability.h \
Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp \
Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.h \
Source/JavaScriptCore/dfg/DFGBasicBlock.cpp \
@@ -358,6 +362,8 @@
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp \
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.h \
Source/JavaScriptCore/dfg/DFGRegisterBank.h \
+ Source/JavaScriptCore/dfg/DFGResurrectionForValidationPhase.cpp \
+ Source/JavaScriptCore/dfg/DFGResurrectionForValidationPhase.h \
Source/JavaScriptCore/dfg/DFGSafeToExecute.h \
Source/JavaScriptCore/dfg/DFGSaneStringGetByValSlowPathGenerator.h \
Source/JavaScriptCore/dfg/DFGScoreBoard.h \
@@ -469,8 +475,6 @@
Source/JavaScriptCore/ftl/FTLValueFormat.cpp \
Source/JavaScriptCore/ftl/FTLValueFormat.h \
Source/JavaScriptCore/ftl/FTLValueFromBlock.h \
- Source/JavaScriptCore/ftl/FTLValueSource.cpp \
- Source/JavaScriptCore/ftl/FTLValueSource.h \
Source/JavaScriptCore/heap/CodeBlockSet.cpp \
Source/JavaScriptCore/heap/CodeBlockSet.h \
Source/JavaScriptCore/heap/CopiedAllocator.h \
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
index 5d64585..be5945c 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
@@ -338,6 +338,7 @@
<ClCompile Include="..\dfg\DFGArgumentsSimplificationPhase.cpp" />
<ClCompile Include="..\dfg\DFGArrayMode.cpp" />
<ClCompile Include="..\dfg\DFGAtTailAbstractState.cpp" />
+ <ClCompile Include="..\dfg\DFGAvailability.cpp" />
<ClCompile Include="..\dfg\DFGBackwardsPropagationPhase.cpp" />
<ClCompile Include="..\dfg\DFGBasicBlock.cpp" />
<ClCompile Include="..\dfg\DFGBinarySwitch.cpp" />
@@ -403,6 +404,7 @@
<ClCompile Include="..\dfg\DFGPlan.cpp" />
<ClCompile Include="..\dfg\DFGPredictionInjectionPhase.cpp" />
<ClCompile Include="..\dfg\DFGPredictionPropagationPhase.cpp" />
+ <ClCompile Include="..\dfg\DFGResurrectionForValidationPhase.cpp" />
<ClCompile Include="..\dfg\DFGSpeculativeJIT.cpp" />
<ClCompile Include="..\dfg\DFGSpeculativeJIT32_64.cpp" />
<ClCompile Include="..\dfg\DFGSpeculativeJIT64.cpp" />
@@ -744,6 +746,7 @@
<ClInclude Include="..\bytecode\ByValInfo.h" />
<ClInclude Include="..\bytecode\BytecodeBasicBlock.h" />
<ClInclude Include="..\bytecode\BytecodeLivenessAnalysis.h" />
+ <ClInclude Include="..\bytecode\BytecodeLivenessAnalysisInline.h" />
<ClInclude Include="..\bytecode\CallLinkInfo.h" />
<ClInclude Include="..\bytecode\CallLinkStatus.h" />
<ClInclude Include="..\bytecode\CallReturnOffsetToBytecodeOffset.h" />
@@ -761,6 +764,7 @@
<ClInclude Include="..\bytecode\ExecutionCounter.h" />
<ClInclude Include="..\bytecode\ExitKind.h" />
<ClInclude Include="..\bytecode\ExpressionRangeInfo.h" />
+ <ClInclude Include="..\bytecode\FullBytecodeLivenss.h" />
<ClInclude Include="..\bytecode\GetByIdStatus.h" />
<ClInclude Include="..\bytecode\HandlerInfo.h" />
<ClInclude Include="..\bytecode\InlineCallFrameSet.h" />
@@ -811,6 +815,7 @@
<ClInclude Include="..\dfg\DFGArrayifySlowPathGenerator.h" />
<ClInclude Include="..\dfg\DFGArrayMode.h" />
<ClInclude Include="..\dfg\DFGAtTailAbstractState.h" />
+ <ClInclude Include="..\dfg\DFGAvailability.h" />
<ClInclude Include="..\dfg\DFGBackwardsPropagationPhase.h" />
<ClInclude Include="..\dfg\DFGBasicBlock.h" />
<ClInclude Include="..\dfg\DFGBasicBlockInlines.h" />
@@ -894,6 +899,7 @@
<ClInclude Include="..\dfg\DFGPredictionPropagationPhase.h" />
<ClInclude Include="..\dfg\DFGRegisterBank.h" />
<ClInclude Include="..\dfg\DFGRegisterSet.h" />
+ <ClInclude Include="..\dfg\DFGResurrectionForValidationPhase.h" />
<ClInclude Include="..\dfg\DFGSafeToExecute.h" />
<ClInclude Include="..\dfg\DFGSaneStringGetByValSlowPathGenerator.h" />
<ClInclude Include="..\dfg\DFGScoreBoard.h" />
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 83b50c9..2d18e4a 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -104,8 +104,6 @@
0F235BE217178E1C00690C7F /* FTLThunks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F235BCC17178E1C00690C7F /* FTLThunks.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F235BE317178E1C00690C7F /* FTLValueFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F235BCD17178E1C00690C7F /* FTLValueFormat.cpp */; };
0F235BE417178E1C00690C7F /* FTLValueFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F235BCE17178E1C00690C7F /* FTLValueFormat.h */; settings = {ATTRIBUTES = (Private, ); }; };
- 0F235BE517178E1C00690C7F /* FTLValueSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F235BCF17178E1C00690C7F /* FTLValueSource.cpp */; };
- 0F235BE617178E1C00690C7F /* FTLValueSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F235BD017178E1C00690C7F /* FTLValueSource.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F235BEB17178E7300690C7F /* DFGOSRExitBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F235BE717178E7300690C7F /* DFGOSRExitBase.cpp */; };
0F235BEC17178E7300690C7F /* DFGOSRExitBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F235BE817178E7300690C7F /* DFGOSRExitBase.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F235BED17178E7300690C7F /* DFGOSRExitPreparation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F235BE917178E7300690C7F /* DFGOSRExitPreparation.cpp */; };
@@ -260,6 +258,12 @@
0F63947815DCE34B006A597C /* DFGStructureAbstractValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63947615DCE347006A597C /* DFGStructureAbstractValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F63948415E48118006A597C /* DFGArrayMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63948115E48114006A597C /* DFGArrayMode.cpp */; };
0F63948515E4811B006A597C /* DFGArrayMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63948215E48114006A597C /* DFGArrayMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F666EC0183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F666EBE183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F666EC1183566F900D017F1 /* FullBytecodeLiveness.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F666EBF183566F900D017F1 /* FullBytecodeLiveness.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F666EC61835672B00D017F1 /* DFGAvailability.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F666EC21835672B00D017F1 /* DFGAvailability.cpp */; };
+ 0F666EC71835672B00D017F1 /* DFGAvailability.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F666EC31835672B00D017F1 /* DFGAvailability.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F666ECC1836B37E00D017F1 /* DFGResurrectionForValidationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F666ECA1836B37E00D017F1 /* DFGResurrectionForValidationPhase.cpp */; };
+ 0F666ECD1836B37E00D017F1 /* DFGResurrectionForValidationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F666ECB1836B37E00D017F1 /* DFGResurrectionForValidationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F66E16B14DF3F1600B7B2E4 /* DFGAdjacencyList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F66E16C14DF3F1600B7B2E4 /* DFGEdge.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F7025A91714B0FA00382C0E /* DFGOSRExitCompilerCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7025A71714B0F800382C0E /* DFGOSRExitCompilerCommon.cpp */; };
@@ -1393,8 +1397,6 @@
0F235BCC17178E1C00690C7F /* FTLThunks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLThunks.h; path = ftl/FTLThunks.h; sourceTree = "<group>"; };
0F235BCD17178E1C00690C7F /* FTLValueFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLValueFormat.cpp; path = ftl/FTLValueFormat.cpp; sourceTree = "<group>"; };
0F235BCE17178E1C00690C7F /* FTLValueFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLValueFormat.h; path = ftl/FTLValueFormat.h; sourceTree = "<group>"; };
- 0F235BCF17178E1C00690C7F /* FTLValueSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLValueSource.cpp; path = ftl/FTLValueSource.cpp; sourceTree = "<group>"; };
- 0F235BD017178E1C00690C7F /* FTLValueSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLValueSource.h; path = ftl/FTLValueSource.h; sourceTree = "<group>"; };
0F235BE717178E7300690C7F /* DFGOSRExitBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSRExitBase.cpp; path = dfg/DFGOSRExitBase.cpp; sourceTree = "<group>"; };
0F235BE817178E7300690C7F /* DFGOSRExitBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSRExitBase.h; path = dfg/DFGOSRExitBase.h; sourceTree = "<group>"; };
0F235BE917178E7300690C7F /* DFGOSRExitPreparation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSRExitPreparation.cpp; path = dfg/DFGOSRExitPreparation.cpp; sourceTree = "<group>"; };
@@ -1548,6 +1550,12 @@
0F63947615DCE347006A597C /* DFGStructureAbstractValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureAbstractValue.h; path = dfg/DFGStructureAbstractValue.h; sourceTree = "<group>"; };
0F63948115E48114006A597C /* DFGArrayMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGArrayMode.cpp; path = dfg/DFGArrayMode.cpp; sourceTree = "<group>"; };
0F63948215E48114006A597C /* DFGArrayMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGArrayMode.h; path = dfg/DFGArrayMode.h; sourceTree = "<group>"; };
+ 0F666EBE183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeLivenessAnalysisInlines.h; sourceTree = "<group>"; };
+ 0F666EBF183566F900D017F1 /* FullBytecodeLiveness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FullBytecodeLiveness.h; sourceTree = "<group>"; };
+ 0F666EC21835672B00D017F1 /* DFGAvailability.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGAvailability.cpp; path = dfg/DFGAvailability.cpp; sourceTree = "<group>"; };
+ 0F666EC31835672B00D017F1 /* DFGAvailability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAvailability.h; path = dfg/DFGAvailability.h; sourceTree = "<group>"; };
+ 0F666ECA1836B37E00D017F1 /* DFGResurrectionForValidationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGResurrectionForValidationPhase.cpp; path = dfg/DFGResurrectionForValidationPhase.cpp; sourceTree = "<group>"; };
+ 0F666ECB1836B37E00D017F1 /* DFGResurrectionForValidationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGResurrectionForValidationPhase.h; path = dfg/DFGResurrectionForValidationPhase.h; sourceTree = "<group>"; };
0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAdjacencyList.h; path = dfg/DFGAdjacencyList.h; sourceTree = "<group>"; };
0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGEdge.h; path = dfg/DFGEdge.h; sourceTree = "<group>"; };
0F7025A71714B0F800382C0E /* DFGOSRExitCompilerCommon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSRExitCompilerCommon.cpp; path = dfg/DFGOSRExitCompilerCommon.cpp; sourceTree = "<group>"; };
@@ -2840,8 +2848,6 @@
0F235BCD17178E1C00690C7F /* FTLValueFormat.cpp */,
0F235BCE17178E1C00690C7F /* FTLValueFormat.h */,
0FDB2CC8173DA51E007B3C1B /* FTLValueFromBlock.h */,
- 0F235BCF17178E1C00690C7F /* FTLValueSource.cpp */,
- 0F235BD017178E1C00690C7F /* FTLValueSource.h */,
);
name = ftl;
sourceTree = "<group>";
@@ -3738,6 +3744,8 @@
0F63948215E48114006A597C /* DFGArrayMode.h */,
A7D9A28F17A0BC7400EE2618 /* DFGAtTailAbstractState.cpp */,
A7D9A29017A0BC7400EE2618 /* DFGAtTailAbstractState.h */,
+ 0F666EC21835672B00D017F1 /* DFGAvailability.cpp */,
+ 0F666EC31835672B00D017F1 /* DFGAvailability.h */,
0F714CA116EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.cpp */,
0F714CA216EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.h */,
A7D89CE317A0B8CC00773AD8 /* DFGBasicBlock.cpp */,
@@ -3888,6 +3896,8 @@
0FFFC95114EF909500C72532 /* DFGPredictionPropagationPhase.cpp */,
0FFFC95214EF909500C72532 /* DFGPredictionPropagationPhase.h */,
86EC9DC11328DF82002B2AD7 /* DFGRegisterBank.h */,
+ 0F666ECA1836B37E00D017F1 /* DFGResurrectionForValidationPhase.cpp */,
+ 0F666ECB1836B37E00D017F1 /* DFGResurrectionForValidationPhase.h */,
A77A423C17A0BBFD00A8DB81 /* DFGSafeToExecute.h */,
A741017E179DAF80002EB8BA /* DFGSaneStringGetByValSlowPathGenerator.h */,
86ECA3F9132DF25A002B2AD7 /* DFGScoreBoard.h */,
@@ -4030,15 +4040,16 @@
969A078F0ED1D3AE00F1F681 /* bytecode */ = {
isa = PBXGroup;
children = (
- C2FCAE0C17A9C24E0034C735 /* BytecodeBasicBlock.cpp */,
- C2FCAE0D17A9C24E0034C735 /* BytecodeBasicBlock.h */,
- C2FCAE0E17A9C24E0034C735 /* BytecodeLivenessAnalysis.cpp */,
- C2FCAE0F17A9C24E0034C735 /* BytecodeLivenessAnalysis.h */,
0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */,
0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */,
0F63945115D07051006A597C /* ArrayProfile.cpp */,
0F63945215D07051006A597C /* ArrayProfile.h */,
+ C2FCAE0C17A9C24E0034C735 /* BytecodeBasicBlock.cpp */,
+ C2FCAE0D17A9C24E0034C735 /* BytecodeBasicBlock.h */,
0F21C27E14BEAA8000ADC64B /* BytecodeConventions.h */,
+ C2FCAE0E17A9C24E0034C735 /* BytecodeLivenessAnalysis.cpp */,
+ C2FCAE0F17A9C24E0034C735 /* BytecodeLivenessAnalysis.h */,
+ 0F666EBE183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h */,
0F8023E91613832300A0BA45 /* ByValInfo.h */,
0F0B83AE14BCF71400885B4F /* CallLinkInfo.cpp */,
0F0B83AF14BCF71400885B4F /* CallLinkInfo.h */,
@@ -4067,6 +4078,7 @@
0FB105821675480C00F8AB6E /* ExitKind.cpp */,
0FB105831675480C00F8AB6E /* ExitKind.h */,
0F0B83AA14BCF5B900885B4F /* ExpressionRangeInfo.h */,
+ 0F666EBF183566F900D017F1 /* FullBytecodeLiveness.h */,
0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */,
0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */,
0F0B83A814BCF55E00885B4F /* HandlerInfo.h */,
@@ -4425,7 +4437,6 @@
0FEA0A201708B00700BB722C /* FTLTypedPointer.h in Headers */,
0F235BE417178E1C00690C7F /* FTLValueFormat.h in Headers */,
0FDB2CCA173DA523007B3C1B /* FTLValueFromBlock.h in Headers */,
- 0F235BE617178E1C00690C7F /* FTLValueSource.h in Headers */,
BC18C4040E16F5CD00B34460 /* FunctionConstructor.h in Headers */,
0FF0F1A016B72A1A005DF95B /* FunctionExecutableDump.h in Headers */,
BC18C4050E16F5CD00B34460 /* FunctionPrototype.h in Headers */,
@@ -4455,6 +4466,7 @@
2A6F462617E959CE00C45C98 /* HeapOperation.h in Headers */,
14F97447138C853E00DA1C67 /* HeapRootVisitor.h in Headers */,
C24D31E3161CD695002AA4DB /* HeapStatistics.h in Headers */,
+ 0F666EC1183566F900D017F1 /* FullBytecodeLiveness.h in Headers */,
C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */,
0F4680D514BBD24B00BFE272 /* HostCallReturnValue.h in Headers */,
BC18C40F0E16F5CD00B34460 /* Identifier.h in Headers */,
@@ -4697,6 +4709,7 @@
95CD45770E1C4FDD0085358E /* ProfileGenerator.h in Headers */,
BC18C4510E16F5CD00B34460 /* ProfileNode.h in Headers */,
0FF729A5166AD351000F5BA3 /* ProfilerBytecode.h in Headers */,
+ 0F666EC0183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h in Headers */,
0FF729B9166AD360000F5BA3 /* ProfilerBytecodes.h in Headers */,
0F13912A16771C36009CCB07 /* ProfilerBytecodeSequence.h in Headers */,
0FF729BA166AD360000F5BA3 /* ProfilerCompilation.h in Headers */,
@@ -4807,6 +4820,7 @@
A7A8AF3F17ADB5F3005AB174 /* Uint8Array.h in Headers */,
A7A8AF4017ADB5F3005AB174 /* Uint8ClampedArray.h in Headers */,
0F5F08CF146C7633000472A9 /* UnconditionalFinalizer.h in Headers */,
+ 0F666EC71835672B00D017F1 /* DFGAvailability.h in Headers */,
A7B601821639FD2A00372BA3 /* UnlinkedCodeBlock.h in Headers */,
0F2E892C16D028AD009E4FD2 /* UnusedPointer.h in Headers */,
0F963B3813FC6FE90002D9B2 /* ValueProfile.h in Headers */,
@@ -4836,6 +4850,7 @@
0FC8150A14043BF500CFA603 /* WriteBarrierSupport.h in Headers */,
9688CB160ED12B4E001D649F /* X86Assembler.h in Headers */,
451539B912DC994500EF7AC4 /* Yarr.h in Headers */,
+ 0F666ECD1836B37E00D017F1 /* DFGResurrectionForValidationPhase.h in Headers */,
86704B8512DBA33700A9FE7B /* YarrInterpreter.h in Headers */,
86704B8712DBA33700A9FE7B /* YarrJIT.h in Headers */,
86704B8812DBA33700A9FE7B /* YarrParser.h in Headers */,
@@ -5444,7 +5459,6 @@
0FEA0A161706BB9000BB722C /* FTLState.cpp in Sources */,
0F235BE117178E1C00690C7F /* FTLThunks.cpp in Sources */,
0F235BE317178E1C00690C7F /* FTLValueFormat.cpp in Sources */,
- 0F235BE517178E1C00690C7F /* FTLValueSource.cpp in Sources */,
147F39CB107EC37600427A48 /* FunctionConstructor.cpp in Sources */,
0FF0F19F16B72A17005DF95B /* FunctionExecutableDump.cpp in Sources */,
147F39CC107EC37600427A48 /* FunctionPrototype.cpp in Sources */,
@@ -5623,6 +5637,7 @@
0FF729B3166AD35C000F5BA3 /* ProfilerOrigin.cpp in Sources */,
0FF729B4166AD35C000F5BA3 /* ProfilerOriginStack.cpp in Sources */,
C2FCAE1017A9C24E0034C735 /* BytecodeBasicBlock.cpp in Sources */,
+ 0F666ECC1836B37E00D017F1 /* DFGResurrectionForValidationPhase.cpp in Sources */,
0FB1058B1675483100F8AB6E /* ProfilerOSRExit.cpp in Sources */,
0FB1058D1675483700F8AB6E /* ProfilerOSRExitSite.cpp in Sources */,
0F13912B16771C3A009CCB07 /* ProfilerProfiledBytecodes.cpp in Sources */,
@@ -5690,6 +5705,7 @@
FE4A331F15BD2E07006F54F3 /* VMInspector.cpp in Sources */,
FED94F2E171E3E2300BE77A4 /* Watchdog.cpp in Sources */,
FED94F30171E3E2300BE77A4 /* WatchdogMac.cpp in Sources */,
+ 0F666EC61835672B00D017F1 /* DFGAvailability.cpp in Sources */,
0F919D2515853CE0004A4E7D /* Watchpoint.cpp in Sources */,
1ACF7377171CA6FB00C9BB1E /* Weak.cpp in Sources */,
14E84F9E14EE1ACC00D6D5D4 /* WeakBlock.cpp in Sources */,
diff --git a/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.h b/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.h
index 83bf847..736ba85 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.h
+++ b/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.h
@@ -36,8 +36,6 @@
class CodeBlock;
-typedef HashMap<unsigned, FastBitVector, WTF::IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned> > BytecodeToBitmapMap;
-
class BytecodeBasicBlock : public RefCounted<BytecodeBasicBlock> {
public:
enum SpecialBlockType { EntryBlock, ExitBlock };
diff --git a/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp b/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp
index a313477..28ffd10 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp
+++ b/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp
@@ -26,7 +26,9 @@
#include "config.h"
#include "BytecodeLivenessAnalysis.h"
+#include "BytecodeLivenessAnalysisInlines.h"
#include "CodeBlock.h"
+#include "FullBytecodeLiveness.h"
#include "PreciseJumpTargets.h"
namespace JSC {
@@ -38,44 +40,23 @@
compute();
}
-static int numberOfCapturedVariables(CodeBlock* codeBlock)
-{
- if (!codeBlock->symbolTable())
- return 0;
- return codeBlock->symbolTable()->captureCount();
-}
-
-static int captureStart(CodeBlock* codeBlock)
-{
- if (!codeBlock->symbolTable())
- return 0;
- return codeBlock->symbolTable()->captureStart();
-}
-
-static int captureEnd(CodeBlock* codeBlock)
-{
- if (!codeBlock->symbolTable())
- return 0;
- return codeBlock->symbolTable()->captureEnd();
-}
-
static bool isValidRegisterForLiveness(CodeBlock* codeBlock, int operand)
{
VirtualRegister virtualReg(operand);
return !codeBlock->isConstantRegisterIndex(operand) // Don't care about constants.
&& virtualReg.isLocal() // Don't care about arguments.
- && (!numberOfCapturedVariables(codeBlock) // If we have no captured variables, we're good to go.
- || (virtualReg.offset() > captureStart(codeBlock) || (virtualReg.offset() <= captureEnd(codeBlock))));
+ && (!codeBlock->captureCount() // If we have no captured variables, we're good to go.
+ || (virtualReg.offset() > codeBlock->captureStart() || (virtualReg.offset() <= codeBlock->captureEnd())));
}
static void setForOperand(CodeBlock* codeBlock, FastBitVector& bits, int operand)
{
ASSERT(isValidRegisterForLiveness(codeBlock, operand));
VirtualRegister virtualReg(operand);
- if (virtualReg.offset() > captureStart(codeBlock))
+ if (virtualReg.offset() > codeBlock->captureStart())
bits.set(virtualReg.toLocal());
else
- bits.set(virtualReg.toLocal() - numberOfCapturedVariables(codeBlock));
+ bits.set(virtualReg.toLocal() - codeBlock->captureCount());
}
static void computeUsesForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset, FastBitVector& uses)
@@ -303,8 +284,8 @@
int base = instruction[2].u.operand;
int count = instruction[3].u.operand;
for (int i = 0; i < count; i++) {
- if (isValidRegisterForLiveness(codeBlock, base + i))
- setForOperand(codeBlock, uses, base + i);
+ if (isValidRegisterForLiveness(codeBlock, base - i))
+ setForOperand(codeBlock, uses, base - i);
}
return;
}
@@ -315,11 +296,11 @@
if (isValidRegisterForLiveness(codeBlock, instruction[2].u.operand))
setForOperand(codeBlock, uses, instruction[2].u.operand);
int argCount = instruction[3].u.operand;
- int registerOffset = instruction[4].u.operand;
+ int registerOffset = -instruction[4].u.operand;
int lastArg = registerOffset + CallFrame::thisArgumentOffset();
- for (int i = 0; i < argCount; i++) {
- if (isValidRegisterForLiveness(codeBlock, lastArg - i))
- setForOperand(codeBlock, uses, lastArg - i);
+ for (int i = opcodeID == op_construct ? 1 : 0; i < argCount; i++) {
+ if (isValidRegisterForLiveness(codeBlock, lastArg + i))
+ setForOperand(codeBlock, uses, lastArg + i);
}
return;
}
@@ -333,10 +314,9 @@
setForOperand(codeBlock, uses, instruction[2].u.operand);
return;
}
-#define LLINT_HELPER_OPCODES(opcode, length) case opcode:
- FOR_EACH_LLINT_OPCODE_EXTENSION(LLINT_HELPER_OPCODES)
- return;
-#undef LLINT_HELPER_OPCODES
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
}
}
@@ -492,8 +472,7 @@
case op_enter: {
defs.setAll();
return;
- }
- }
+ } }
}
static unsigned getLeaderOffsetForBasicBlock(RefPtr<BytecodeBasicBlock>* basicBlock)
@@ -540,13 +519,32 @@
return basicBlock[1].get();
}
+static void stepOverInstruction(CodeBlock* codeBlock, Vector<RefPtr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, FastBitVector& uses, FastBitVector& defs, FastBitVector& out)
+{
+ uses.clearAll();
+ defs.clearAll();
+
+ computeUsesForBytecodeOffset(codeBlock, bytecodeOffset, uses);
+ computeDefsForBytecodeOffset(codeBlock, bytecodeOffset, defs);
+
+ out.exclude(defs);
+ out.merge(uses);
+
+ // If we have an exception handler, we want the live-in variables of the
+ // exception handler block to be included in the live-in of this particular bytecode.
+ if (HandlerInfo* handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset)) {
+ BytecodeBasicBlock* handlerBlock = findBasicBlockWithLeaderOffset(basicBlocks, handler->target);
+ ASSERT(handlerBlock);
+ out.merge(handlerBlock->in());
+ }
+}
+
static void computeLocalLivenessForBytecodeOffset(CodeBlock* codeBlock, BytecodeBasicBlock* block, Vector<RefPtr<BytecodeBasicBlock> >& basicBlocks, unsigned targetOffset, FastBitVector& result)
{
ASSERT(!block->isExitBlock());
ASSERT(!block->isEntryBlock());
FastBitVector out = block->out();
- HandlerInfo* handler = 0;
FastBitVector uses;
FastBitVector defs;
@@ -557,23 +555,8 @@
unsigned bytecodeOffset = block->bytecodeOffsets()[i];
if (targetOffset > bytecodeOffset)
break;
-
- uses.clearAll();
- defs.clearAll();
-
- computeUsesForBytecodeOffset(codeBlock, bytecodeOffset, uses);
- computeDefsForBytecodeOffset(codeBlock, bytecodeOffset, defs);
-
- out.exclude(defs);
- out.merge(uses);
-
- // If we have an exception handler, we want the live-in variables of the
- // exception handler block to be included in the live-in of this particular bytecode.
- if ((handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
- BytecodeBasicBlock* handlerBlock = findBasicBlockWithLeaderOffset(basicBlocks, handler->target);
- ASSERT(handlerBlock);
- out.merge(handlerBlock->in());
- }
+
+ stepOverInstruction(codeBlock, basicBlocks, bytecodeOffset, uses, defs, out);
}
result.set(out);
@@ -590,7 +573,7 @@
{
UnlinkedCodeBlock* unlinkedCodeBlock = m_codeBlock->unlinkedCodeBlock();
unsigned numberOfVariables = unlinkedCodeBlock->m_numVars +
- unlinkedCodeBlock->m_numCalleeRegisters - numberOfCapturedVariables(m_codeBlock);
+ unlinkedCodeBlock->m_numCalleeRegisters - m_codeBlock->captureCount();
for (unsigned i = 0; i < m_basicBlocks.size(); i++) {
BytecodeBasicBlock* block = m_basicBlocks[i].get();
@@ -629,36 +612,30 @@
bool BytecodeLivenessAnalysis::operandIsLiveAtBytecodeOffset(int operand, unsigned bytecodeOffset)
{
- int numCapturedVars = numberOfCapturedVariables(m_codeBlock);
- if (VirtualRegister(operand).isArgument())
- return true;
- if (operand <= captureStart(m_codeBlock) && operand > captureEnd(m_codeBlock))
+ if (operandIsAlwaysLive(m_codeBlock, operand))
return true;
FastBitVector result;
getLivenessInfoForNonCapturedVarsAtBytecodeOffset(bytecodeOffset, result);
- return result.get(operand - numCapturedVars);
+ return operandThatIsNotAlwaysLiveIsLive(m_codeBlock, result, operand);
}
-FastBitVector BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeOffset(unsigned bytecodeOffset)
+FastBitVector getLivenessInfo(CodeBlock* codeBlock, const FastBitVector& out)
{
- FastBitVector temp;
FastBitVector result;
- getLivenessInfoForNonCapturedVarsAtBytecodeOffset(bytecodeOffset, temp);
-
- unsigned numCapturedVars = numberOfCapturedVariables(m_codeBlock);
+ unsigned numCapturedVars = codeBlock->captureCount();
if (numCapturedVars) {
- int firstCapturedLocal = VirtualRegister(captureStart(m_codeBlock)).toLocal();
- result.resize(temp.numBits() + numCapturedVars);
+ int firstCapturedLocal = VirtualRegister(codeBlock->captureStart()).toLocal();
+ result.resize(out.numBits() + numCapturedVars);
for (unsigned i = 0; i < numCapturedVars; ++i)
result.set(firstCapturedLocal + i);
} else
- result.resize(temp.numBits());
+ result.resize(out.numBits());
- int tempLength = temp.numBits();
- ASSERT(tempLength >= 0);
- for (int i = 0; i < tempLength; i++) {
- if (!temp.get(i))
+ int outLength = out.numBits();
+ ASSERT(outLength >= 0);
+ for (int i = 0; i < outLength; i++) {
+ if (!out.get(i))
continue;
if (!numCapturedVars) {
@@ -666,7 +643,7 @@
continue;
}
- if (virtualRegisterForLocal(i).offset() > captureStart(m_codeBlock))
+ if (virtualRegisterForLocal(i).offset() > codeBlock->captureStart())
result.set(i);
else
result.set(numCapturedVars + i);
@@ -674,6 +651,39 @@
return result;
}
+FastBitVector BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeOffset(unsigned bytecodeOffset)
+{
+ FastBitVector out;
+ getLivenessInfoForNonCapturedVarsAtBytecodeOffset(bytecodeOffset, out);
+ return getLivenessInfo(m_codeBlock, out);
+}
+
+void BytecodeLivenessAnalysis::computeFullLiveness(FullBytecodeLiveness& result)
+{
+ FastBitVector out;
+ FastBitVector uses;
+ FastBitVector defs;
+
+ result.m_codeBlock = m_codeBlock;
+ result.m_map.clear();
+
+ for (unsigned i = m_basicBlocks.size(); i--;) {
+ BytecodeBasicBlock* block = m_basicBlocks[i].get();
+ if (block->isEntryBlock() || block->isExitBlock())
+ continue;
+
+ out = block->out();
+ uses.resize(out.numBits());
+ defs.resize(out.numBits());
+
+ for (unsigned i = block->bytecodeOffsets().size(); i--;) {
+ unsigned bytecodeOffset = block->bytecodeOffsets()[i];
+ stepOverInstruction(m_codeBlock, m_basicBlocks, bytecodeOffset, uses, defs, out);
+ result.m_map.add(bytecodeOffset, out);
+ }
+ }
+}
+
void BytecodeLivenessAnalysis::dumpResults()
{
Interpreter* interpreter = m_codeBlock->vm()->interpreter;
diff --git a/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.h b/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.h
index b18d597..3499121 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.h
+++ b/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.h
@@ -34,13 +34,16 @@
namespace JSC {
class CodeBlock;
+class FullBytecodeLiveness;
class BytecodeLivenessAnalysis {
public:
BytecodeLivenessAnalysis(CodeBlock*);
-
+
bool operandIsLiveAtBytecodeOffset(int operand, unsigned bytecodeOffset);
FastBitVector getLivenessInfoAtBytecodeOffset(unsigned bytecodeOffset);
+
+ void computeFullLiveness(FullBytecodeLiveness& result);
private:
void compute();
@@ -53,6 +56,12 @@
Vector<RefPtr<BytecodeBasicBlock> > m_basicBlocks;
};
+inline bool operandIsAlwaysLive(CodeBlock*, int operand);
+inline bool operandThatIsNotAlwaysLiveIsLive(CodeBlock*, const FastBitVector& out, int operand);
+inline bool operandIsLive(CodeBlock*, const FastBitVector& out, int operand);
+
+FastBitVector getLivenessInfo(CodeBlock*, const FastBitVector& out);
+
} // namespace JSC
#endif // BytecodeLivenessAnalysis_h
diff --git a/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysisInlines.h b/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysisInlines.h
new file mode 100644
index 0000000..8824bd8
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysisInlines.h
@@ -0,0 +1,60 @@
+/*
+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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 BytecodeLivenessAnalysisInlines_h
+#define BytecodeLivenessAnalysisInlines_h
+
+#include "BytecodeLivenessAnalysis.h"
+#include "CodeBlock.h"
+
+namespace JSC {
+
+inline bool operandIsAlwaysLive(CodeBlock* codeBlock, int operand)
+{
+ if (VirtualRegister(operand).isArgument())
+ return true;
+ return operand <= codeBlock->captureStart() && operand > codeBlock->captureEnd();
+}
+
+inline bool operandThatIsNotAlwaysLiveIsLive(CodeBlock* codeBlock, const FastBitVector& out, int operand)
+{
+ VirtualRegister virtualReg(operand);
+ if (virtualReg.offset() > codeBlock->captureStart())
+ return out.get(virtualReg.toLocal());
+ size_t index = virtualReg.toLocal() - codeBlock->captureCount();
+ if (index >= out.numBits())
+ return false;
+ return out.get(index);
+}
+
+inline bool operandIsLive(CodeBlock* codeBlock, const FastBitVector& out, int operand)
+{
+ return operandIsAlwaysLive(codeBlock, operand) || operandThatIsNotAlwaysLiveIsLive(codeBlock, out, operand);
+}
+
+} // namespace JSC
+
+#endif // BytecodeLivenessAnalysisInlines_h
+
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index 07cc13d..991923b 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -354,6 +354,27 @@
{
return m_needsActivation;
}
+
+ unsigned captureCount() const
+ {
+ if (!symbolTable())
+ return 0;
+ return symbolTable()->captureCount();
+ }
+
+ int captureStart() const
+ {
+ if (!symbolTable())
+ return 0;
+ return symbolTable()->captureStart();
+ }
+
+ int captureEnd() const
+ {
+ if (!symbolTable())
+ return 0;
+ return symbolTable()->captureEnd();
+ }
bool isCaptured(VirtualRegister operand, InlineCallFrame* = 0) const;
diff --git a/Source/JavaScriptCore/bytecode/CodeOrigin.cpp b/Source/JavaScriptCore/bytecode/CodeOrigin.cpp
index e5428c6..a5bb103 100644
--- a/Source/JavaScriptCore/bytecode/CodeOrigin.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeOrigin.cpp
@@ -116,7 +116,7 @@
else
out.print(", known callee: ", inContext(calleeRecovery.constant(), context));
out.print(", numArgs+this = ", arguments.size());
- out.print(", stack >= r", stackOffset);
+ out.print(", stack < loc", VirtualRegister(stackOffset).toLocal());
out.print(">");
}
diff --git a/Source/JavaScriptCore/bytecode/FullBytecodeLiveness.h b/Source/JavaScriptCore/bytecode/FullBytecodeLiveness.h
new file mode 100644
index 0000000..d343921
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/FullBytecodeLiveness.h
@@ -0,0 +1,70 @@
+/*
+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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 FullBytecodeLiveness_h
+#define FullBytecodeLiveness_h
+
+#include <wtf/FastBitVector.h>
+
+namespace JSC {
+
+class BytecodeLivenessAnalysis;
+
+typedef HashMap<unsigned, FastBitVector, WTF::IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> BytecodeToBitmapMap;
+
+class FullBytecodeLiveness {
+public:
+ FullBytecodeLiveness() : m_codeBlock(0) { }
+
+ // We say "out" to refer to the bitvector that contains raw results for a bytecode
+ // instruction.
+ const FastBitVector& getOut(unsigned bytecodeIndex) const
+ {
+ BytecodeToBitmapMap::const_iterator iter = m_map.find(bytecodeIndex);
+ ASSERT(iter != m_map.end());
+ return iter->value;
+ }
+
+ bool operandIsLive(int operand, unsigned bytecodeIndex) const
+ {
+ return operandIsAlwaysLive(m_codeBlock, operand) || operandThatIsNotAlwaysLiveIsLive(m_codeBlock, getOut(bytecodeIndex), operand);
+ }
+
+ FastBitVector getLiveness(unsigned bytecodeIndex) const
+ {
+ return getLivenessInfo(m_codeBlock, getOut(bytecodeIndex));
+ }
+
+private:
+ friend class BytecodeLivenessAnalysis;
+
+ CodeBlock* m_codeBlock;
+ BytecodeToBitmapMap m_map;
+};
+
+} // namespace JSC
+
+#endif // FullBytecodeLiveness_h
+
diff --git a/Source/JavaScriptCore/ftl/FTLValueSource.cpp b/Source/JavaScriptCore/dfg/DFGAvailability.cpp
similarity index 61%
rename from Source/JavaScriptCore/ftl/FTLValueSource.cpp
rename to Source/JavaScriptCore/dfg/DFGAvailability.cpp
index cc9ac6d..669c2b4 100644
--- a/Source/JavaScriptCore/ftl/FTLValueSource.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAvailability.cpp
@@ -24,47 +24,37 @@
*/
#include "config.h"
-#include "FTLValueSource.h"
+#include "DFGAvailability.h"
-#if ENABLE(FTL_JIT)
+#if ENABLE(DFG_JIT)
-namespace JSC { namespace FTL {
+#include "DFGNode.h"
-void ValueSource::dump(PrintStream& out) const
+namespace JSC { namespace DFG {
+
+void Availability::dump(PrintStream& out) const
{
- switch (kind()) {
- case SourceNotSet:
- out.print("SourceNotSet");
- return;
- case ValueInJSStack:
- out.print("ValueInJSStack:", virtualRegister());
- return;
- case Int32InJSStack:
- out.print("Int32InJSStack:", virtualRegister());
- return;
- case Int52InJSStack:
- out.print("Int52InJSStack:", virtualRegister());
- return;
- case DoubleInJSStack:
- out.print("DoubleInJSStack:", virtualRegister());
- return;
- case SourceIsDead:
- out.print("SourceIsDead");
- return;
- case HaveNode:
- out.print("Node(", node(), ")");
+ out.print(m_flushedAt, "/");
+
+ if (nodeIsUndecided()) {
+ out.print("Undecided");
return;
}
- RELEASE_ASSERT_NOT_REACHED();
+ if (nodeIsUnavailable()) {
+ out.print("Unavailable");
+ return;
+ }
+
+ out.print(node());
}
-void ValueSource::dumpInContext(PrintStream& out, DumpContext*) const
+void Availability::dumpInContext(PrintStream& out, DumpContext*) const
{
dump(out);
}
-} } // namespace JSC::FTL
+} } // namespace JSC::DFG
-#endif // ENABLE(FTL_JIT)
+#endif // ENABLE(DFG_JIT)
diff --git a/Source/JavaScriptCore/dfg/DFGAvailability.h b/Source/JavaScriptCore/dfg/DFGAvailability.h
new file mode 100644
index 0000000..fd9bf65
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGAvailability.h
@@ -0,0 +1,142 @@
+/*
+ * 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 DFGAvailability_h
+#define DFGAvailability_h
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGFlushedAt.h"
+#include "DFGVariableAccessData.h"
+
+namespace JSC { namespace DFG {
+
+struct Node;
+
+class Availability {
+public:
+ Availability()
+ : m_node(0)
+ , m_flushedAt(DeadFlush)
+ {
+ }
+
+ explicit Availability(Node* node)
+ : m_node(node)
+ , m_flushedAt(ConflictingFlush)
+ {
+ }
+
+ explicit Availability(FlushedAt flushedAt)
+ : m_node(unavailableMarker())
+ , m_flushedAt(flushedAt)
+ {
+ }
+
+ Availability(Node* node, FlushedAt flushedAt)
+ : m_node(node)
+ , m_flushedAt(flushedAt)
+ {
+ }
+
+ static Availability unavailable()
+ {
+ return Availability(unavailableMarker(), FlushedAt(ConflictingFlush));
+ }
+
+ Availability withFlush(FlushedAt flush) const
+ {
+ return Availability(m_node, flush);
+ }
+
+ Availability withNode(Node* node) const
+ {
+ return Availability(node, m_flushedAt);
+ }
+
+ Availability withUnavailableNode() const
+ {
+ return withNode(unavailableMarker());
+ }
+
+ bool nodeIsUndecided() const { return !m_node; }
+ bool nodeIsUnavailable() const { return m_node == unavailableMarker(); }
+
+ bool hasNode() const { return !nodeIsUndecided() && !nodeIsUnavailable(); }
+
+ Node* node() const
+ {
+ ASSERT(!nodeIsUndecided());
+ ASSERT(!nodeIsUnavailable());
+ return m_node;
+ }
+
+ FlushedAt flushedAt() const { return m_flushedAt; }
+
+ bool operator!() const { return nodeIsUnavailable() && flushedAt().format() == ConflictingFlush; }
+
+ bool operator==(const Availability& other) const
+ {
+ return m_node == other.m_node
+ && m_flushedAt == other.m_flushedAt;
+ }
+
+ Availability merge(const Availability& other) const
+ {
+ return Availability(
+ mergeNodes(m_node, other.m_node),
+ m_flushedAt.merge(other.m_flushedAt));
+ }
+
+ void dump(PrintStream&) const;
+ void dumpInContext(PrintStream&, DumpContext*) const;
+
+private:
+ static Node* mergeNodes(Node* a, Node* b)
+ {
+ if (!a)
+ return b;
+ if (!b)
+ return a;
+ if (a == b)
+ return a;
+ return unavailableMarker();
+ }
+
+ static Node* unavailableMarker()
+ {
+ return bitwise_cast<Node*>(static_cast<intptr_t>(1));
+ }
+
+ Node* m_node;
+ FlushedAt m_flushedAt;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGAvailability_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGBasicBlock.h b/Source/JavaScriptCore/dfg/DFGBasicBlock.h
index 7549410..a3a8012 100644
--- a/Source/JavaScriptCore/dfg/DFGBasicBlock.h
+++ b/Source/JavaScriptCore/dfg/DFGBasicBlock.h
@@ -29,6 +29,7 @@
#if ENABLE(DFG_JIT)
#include "DFGAbstractValue.h"
+#include "DFGAvailability.h"
#include "DFGBranchDirection.h"
#include "DFGFlushedAt.h"
#include "DFGNode.h"
@@ -140,8 +141,8 @@
struct SSAData {
Operands<FlushedAt> flushAtHead;
Operands<FlushedAt> flushAtTail;
- Operands<Node*> availabilityAtHead;
- Operands<Node*> availabilityAtTail;
+ Operands<Availability> availabilityAtHead;
+ Operands<Availability> availabilityAtTail;
HashSet<Node*> liveAtHead;
HashSet<Node*> liveAtTail;
HashMap<Node*, AbstractValue> valuesAtHead;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index ca61430..224d3d3 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -697,6 +697,15 @@
bool canFold(Node* node)
{
+ if (Options::validateFTLOSRExitLiveness()) {
+ // The static folding that the bytecode parser does results in the DFG
+ // being able to do some DCE that the bytecode liveness analysis would
+ // miss. Hence, we disable the static folding if we're validating FTL OSR
+ // exit liveness. This may be brutish, but this validator is powerful
+ // enough that it's worth it.
+ return false;
+ }
+
return node->isStronglyProvedConstantIn(inlineCallFrame());
}
@@ -3073,6 +3082,7 @@
break;
}
Node* base = cellConstantWithStructureCheck(globalObject, status.structureSet().singletonStructure());
+ addToGraph(Phantom, get(VirtualRegister(scope)));
if (JSValue specificValue = status.specificValue())
set(VirtualRegister(dst), cellConstant(specificValue.asCell()));
else
@@ -3081,6 +3091,7 @@
}
case GlobalVar:
case GlobalVarWithVarInjectionChecks: {
+ addToGraph(Phantom, get(VirtualRegister(scope)));
SymbolTableEntry entry = globalObject->symbolTable()->get(uid);
if (!entry.couldBeWatched() || !m_graph.watchpoints().isStillValid(entry.watchpointSet())) {
set(VirtualRegister(dst), addToGraph(GetGlobalVar, OpInfo(operand), OpInfo(prediction)));
@@ -3131,6 +3142,7 @@
break;
}
Node* base = cellConstantWithStructureCheck(globalObject, status.oldStructure());
+ addToGraph(Phantom, get(VirtualRegister(scope)));
handlePutByOffset(base, identifierNumber, static_cast<PropertyOffset>(operand), get(VirtualRegister(value)));
// Keep scope alive until after put.
addToGraph(Phantom, get(VirtualRegister(scope)));
@@ -3138,6 +3150,7 @@
}
case GlobalVar:
case GlobalVarWithVarInjectionChecks: {
+ addToGraph(Phantom, get(VirtualRegister(scope)));
SymbolTableEntry entry = globalObject->symbolTable()->get(uid);
ASSERT(!entry.couldBeWatched() || !m_graph.watchpoints().isStillValid(entry.watchpointSet()));
addToGraph(PutGlobalVar, OpInfo(operand), get(VirtualRegister(value)));
diff --git a/Source/JavaScriptCore/dfg/DFGDisassembler.cpp b/Source/JavaScriptCore/dfg/DFGDisassembler.cpp
index b8d0c6b..8fea10b 100644
--- a/Source/JavaScriptCore/dfg/DFGDisassembler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDisassembler.cpp
@@ -38,6 +38,7 @@
Disassembler::Disassembler(Graph& graph)
: m_graph(graph)
{
+ m_dumpContext.graph = &m_graph;
m_labelForBlockIndex.resize(graph.numBlocks());
}
diff --git a/Source/JavaScriptCore/dfg/DFGFlushFormat.cpp b/Source/JavaScriptCore/dfg/DFGFlushFormat.cpp
index 8e3f26b..073500e 100644
--- a/Source/JavaScriptCore/dfg/DFGFlushFormat.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFlushFormat.cpp
@@ -56,6 +56,9 @@
case FlushedJSValue:
out.print("FlushedJSValue");
return;
+ case ConflictingFlush:
+ out.print("ConflictingFlush");
+ return;
}
RELEASE_ASSERT_NOT_REACHED();
}
diff --git a/Source/JavaScriptCore/dfg/DFGFlushFormat.h b/Source/JavaScriptCore/dfg/DFGFlushFormat.h
index be3f943..53fb5a9 100644
--- a/Source/JavaScriptCore/dfg/DFGFlushFormat.h
+++ b/Source/JavaScriptCore/dfg/DFGFlushFormat.h
@@ -45,7 +45,8 @@
FlushedDouble,
FlushedCell,
FlushedBoolean,
- FlushedJSValue
+ FlushedJSValue,
+ ConflictingFlush
};
inline NodeFlags resultFor(FlushFormat format)
@@ -54,6 +55,7 @@
case DeadFlush:
case FlushedJSValue:
case FlushedCell:
+ case ConflictingFlush:
return NodeResultJS;
case FlushedInt32:
return NodeResultInt32;
@@ -73,6 +75,7 @@
switch (format) {
case DeadFlush:
case FlushedJSValue:
+ case ConflictingFlush:
return UntypedUse;
case FlushedCell:
return CellUse;
@@ -93,6 +96,7 @@
{
switch (format) {
case DeadFlush:
+ case ConflictingFlush:
return DataFormatDead;
case FlushedJSValue:
return DataFormatJS;
diff --git a/Source/JavaScriptCore/dfg/DFGFlushedAt.cpp b/Source/JavaScriptCore/dfg/DFGFlushedAt.cpp
index d2e27d82..ce95f45 100644
--- a/Source/JavaScriptCore/dfg/DFGFlushedAt.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFlushedAt.cpp
@@ -32,7 +32,7 @@
void FlushedAt::dump(PrintStream& out) const
{
- if (m_format == DeadFlush)
+ if (m_format == DeadFlush || m_format == ConflictingFlush)
out.print(m_format);
else
out.print("r", m_virtualRegister, ":", m_format);
diff --git a/Source/JavaScriptCore/dfg/DFGFlushedAt.h b/Source/JavaScriptCore/dfg/DFGFlushedAt.h
index cd8a53d..6dfe716 100644
--- a/Source/JavaScriptCore/dfg/DFGFlushedAt.h
+++ b/Source/JavaScriptCore/dfg/DFGFlushedAt.h
@@ -42,6 +42,12 @@
{
}
+ explicit FlushedAt(FlushFormat format)
+ : m_format(format)
+ {
+ ASSERT(format == DeadFlush || format == ConflictingFlush);
+ }
+
FlushedAt(FlushFormat format, VirtualRegister virtualRegister)
: m_format(format)
, m_virtualRegister(virtualRegister)
@@ -65,6 +71,17 @@
bool operator!=(const FlushedAt& other) const { return !(*this == other); }
+ FlushedAt merge(const FlushedAt& other) const
+ {
+ if (!*this)
+ return other;
+ if (!other)
+ return *this;
+ if (*this == other)
+ return *this;
+ return FlushedAt(ConflictingFlush);
+ }
+
void dump(PrintStream&) const;
void dumpInContext(PrintStream&, DumpContext*) const;
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index b0e993f..91a847a 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -26,11 +26,13 @@
#include "config.h"
#include "DFGGraph.h"
+#include "BytecodeLivenessAnalysisInlines.h"
#include "CodeBlock.h"
#include "CodeBlockWithJITType.h"
#include "DFGClobberSet.h"
#include "DFGJITCode.h"
#include "DFGVariableAccessDataDump.h"
+#include "FullBytecodeLiveness.h"
#include "FunctionExecutableDump.h"
#include "OperandsInlines.h"
#include "Operations.h"
@@ -393,6 +395,7 @@
void Graph::dump(PrintStream& out, DumpContext* context)
{
DumpContext myContext;
+ myContext.graph = this;
if (!context)
context = &myContext;
@@ -643,6 +646,58 @@
block->at(nodeIndex)->misc.owner = block;
}
}
+
+FullBytecodeLiveness& Graph::livenessFor(CodeBlock* codeBlock)
+{
+ HashMap<CodeBlock*, std::unique_ptr<FullBytecodeLiveness>>::iterator iter = m_bytecodeLiveness.find(codeBlock);
+ if (iter != m_bytecodeLiveness.end())
+ return *iter->value;
+
+ std::unique_ptr<FullBytecodeLiveness> liveness = std::make_unique<FullBytecodeLiveness>();
+ codeBlock->livenessAnalysis().computeFullLiveness(*liveness);
+ FullBytecodeLiveness& result = *liveness;
+ m_bytecodeLiveness.add(codeBlock, std::move(liveness));
+ return result;
+}
+
+FullBytecodeLiveness& Graph::livenessFor(InlineCallFrame* inlineCallFrame)
+{
+ return livenessFor(baselineCodeBlockFor(inlineCallFrame));
+}
+
+bool Graph::isLiveInBytecode(VirtualRegister operand, CodeOrigin codeOrigin)
+{
+ for (;;) {
+ if (operand.offset() < codeOrigin.stackOffset() + JSStack::CallFrameHeaderSize) {
+ VirtualRegister reg = VirtualRegister(
+ operand.offset() - codeOrigin.stackOffset());
+
+ if (reg.isArgument()) {
+ RELEASE_ASSERT(reg.offset() < JSStack::CallFrameHeaderSize);
+
+ if (!codeOrigin.inlineCallFrame->isClosureCall)
+ return false;
+
+ if (reg.offset() == JSStack::Callee)
+ return true;
+ if (reg.offset() == JSStack::ScopeChain)
+ return true;
+
+ return false;
+ }
+
+ return livenessFor(codeOrigin.inlineCallFrame).operandIsLive(
+ reg.offset(), codeOrigin.bytecodeIndex);
+ }
+
+ if (!codeOrigin.inlineCallFrame)
+ break;
+
+ codeOrigin = codeOrigin.inlineCallFrame->caller;
+ }
+
+ return true;
+}
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 6a73377..4723f95 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -416,6 +416,13 @@
return executableFor(codeOrigin.inlineCallFrame);
}
+ CodeBlock* baselineCodeBlockFor(InlineCallFrame* inlineCallFrame)
+ {
+ if (!inlineCallFrame)
+ return m_profiledBlock;
+ return baselineCodeBlockForInlineCallFrame(inlineCallFrame);
+ }
+
CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin)
{
return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock);
@@ -776,6 +783,10 @@
DesiredWatchpoints& watchpoints() { return m_plan.watchpoints; }
DesiredStructureChains& chains() { return m_plan.chains; }
+ FullBytecodeLiveness& livenessFor(CodeBlock*);
+ FullBytecodeLiveness& livenessFor(InlineCallFrame*);
+ bool isLiveInBytecode(VirtualRegister, CodeOrigin);
+
VM& m_vm;
Plan& m_plan;
CodeBlock* m_codeBlock;
@@ -797,6 +808,7 @@
SegmentedVector<SwitchData, 4> m_switchData;
Vector<InlineVariableData, 4> m_inlineVariableData;
OwnPtr<InlineCallFrameSet> m_inlineCallFrames;
+ HashMap<CodeBlock*, std::unique_ptr<FullBytecodeLiveness>> m_bytecodeLiveness;
bool m_hasArguments;
HashSet<ExecutableBase*> m_executablesWhoseArgumentsEscaped;
BitVector m_lazyVars;
diff --git a/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp b/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp
index 5227b80..705408e 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp
@@ -47,78 +47,97 @@
{
ASSERT(m_graph.m_form == SSA);
- Vector<BasicBlock*> depthFirst;
- m_graph.getBlocksInDepthFirstOrder(depthFirst);
-
- for (unsigned i = 0; i < depthFirst.size(); ++i) {
- BasicBlock* block = depthFirst[i];
- block->ssa->availabilityAtHead.fill(0);
- block->ssa->availabilityAtTail.fill(0);
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ block->ssa->availabilityAtHead.fill(Availability());
+ block->ssa->availabilityAtTail.fill(Availability());
}
- for (unsigned i = 0; i < depthFirst.size(); ++i) {
- BasicBlock* block = depthFirst[i];
-
- // We edit availabilityAtTail in-place, but first initialize it to
- // availabilityAtHead.
- Operands<Node*>& availability = block->ssa->availabilityAtTail;
- availability = block->ssa->availabilityAtHead;
-
- for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
- Node* node = block->at(nodeIndex);
- switch (node->op()) {
- case SetLocal:
- case MovHint:
- case MovHintAndCheck: {
- availability.operand(node->local()) = node->child1().node();
- break;
- }
-
- case ZombieHint: {
- availability.operand(node->local()) = 0;
- break;
- }
-
- case GetArgument: {
- availability.operand(node->local()) = node;
- break;
- }
-
- default:
- break;
- }
- }
-
- for (unsigned j = block->numSuccessors(); j--;) {
- BasicBlock* successor = block->successor(j);
- Operands<Node*>& successorAvailability = successor->ssa->availabilityAtHead;
- for (unsigned k = availability.size(); k--;) {
- Node* myNode = availability[k];
- if (!myNode)
- continue;
-
- if (!successor->ssa->liveAtHead.contains(myNode))
- continue;
-
- // Note that this may overwrite availability with a bogus node
- // at merge points. This is fine, since merge points have
- // MovHint(Phi)'s to work around this. The outcome of this is
- // you might have a program in which a node happens to remain
- // live into some block B, and separately (due to copy
- // propagation) just one of the predecessors of B issued a
- // MovHint putting that node into some local. Then in B we might
- // think that that node is a valid value for that local. Of
- // course if that local was actually live in B, B would have a
- // Phi for it. So essentially we'll have OSR exit dropping this
- // node's value into the local when we otherwise (in the DFG)
- // would have dropped undefined into the local. This seems
- // harmless.
-
- successorAvailability[k] = myNode;
- }
+ BasicBlock* root = m_graph.block(0);
+ for (unsigned argument = root->ssa->availabilityAtHead.numberOfArguments(); argument--;) {
+ root->ssa->availabilityAtHead.argument(argument) =
+ Availability::unavailable().withFlush(
+ FlushedAt(FlushedJSValue, virtualRegisterForArgument(argument)));
+ }
+ for (unsigned local = root->ssa->availabilityAtHead.numberOfLocals(); local--;)
+ root->ssa->availabilityAtHead.local(local) = Availability::unavailable();
+
+ if (m_graph.m_plan.mode == FTLForOSREntryMode) {
+ for (unsigned local = m_graph.m_profiledBlock->m_numCalleeRegisters; local--;) {
+ root->ssa->availabilityAtHead.local(local) =
+ Availability::unavailable().withFlush(
+ FlushedAt(FlushedJSValue, virtualRegisterForLocal(local)));
}
}
+ // This could be made more efficient by processing blocks in reverse postorder.
+ Operands<Availability> availability;
+ bool changed;
+ do {
+ changed = false;
+
+ for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+
+ availability = block->ssa->availabilityAtHead;
+
+ for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
+ Node* node = block->at(nodeIndex);
+
+ switch (node->op()) {
+ case SetLocal: {
+ VariableAccessData* variable = node->variableAccessData();
+ availability.operand(variable->local()) =
+ Availability(node->child1().node(), variable->flushedAt());
+ break;
+ }
+
+ case GetArgument: {
+ VariableAccessData* variable = node->variableAccessData();
+ availability.operand(variable->local()) =
+ Availability(node, variable->flushedAt());
+ break;
+ }
+
+ case MovHint:
+ case MovHintAndCheck: {
+ VariableAccessData* variable = node->variableAccessData();
+ availability.operand(variable->local()) =
+ Availability(node->child1().node());
+ break;
+ }
+
+ case ZombieHint: {
+ VariableAccessData* variable = node->variableAccessData();
+ availability.operand(variable->local()) = Availability::unavailable();
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ if (availability == block->ssa->availabilityAtTail)
+ continue;
+
+ block->ssa->availabilityAtTail = availability;
+ changed = true;
+
+ for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) {
+ BasicBlock* successor = block->successor(successorIndex);
+ for (unsigned i = availability.size(); i--;) {
+ successor->ssa->availabilityAtHead[i] = availability[i].merge(
+ successor->ssa->availabilityAtHead[i]);
+ }
+ }
+ }
+ } while (changed);
+
return true;
}
};
diff --git a/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.h b/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.h
index 6c37a9d..28bf505 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.h
+++ b/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.h
@@ -36,9 +36,8 @@
class Graph;
-// Computes BasicBlock::ssa->availabiltiyAtHead/Tail. This relies on liveness
-// analysis phase having been run and the graph not having been transformed
-// after that.
+// Computes BasicBlock::ssa->availabiltiyAtHead/Tail. This is a forward flow type inference
+// over MovHints and SetLocals.
bool performOSRAvailabilityAnalysis(Graph&);
diff --git a/Source/JavaScriptCore/dfg/DFGPlan.cpp b/Source/JavaScriptCore/dfg/DFGPlan.cpp
index 365ec74..09926af 100644
--- a/Source/JavaScriptCore/dfg/DFGPlan.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPlan.cpp
@@ -50,6 +50,7 @@
#include "DFGOSREntrypointCreationPhase.h"
#include "DFGPredictionInjectionPhase.h"
#include "DFGPredictionPropagationPhase.h"
+#include "DFGResurrectionForValidationPhase.h"
#include "DFGSSAConversionPhase.h"
#include "DFGStackLayoutPhase.h"
#include "DFGTierUpCheckInjectionPhase.h"
@@ -268,6 +269,8 @@
performLICM(dfg);
performLivenessAnalysis(dfg);
performCFA(dfg);
+ if (Options::validateFTLOSRExitLiveness())
+ performResurrectionForValidation(dfg);
performDCE(dfg); // We rely on this to convert dead SetLocals into the appropriate hint, and to kill dead code that won't be recognized as dead by LLVM.
performStackLayout(dfg);
performLivenessAnalysis(dfg);
diff --git a/Source/JavaScriptCore/dfg/DFGResurrectionForValidationPhase.cpp b/Source/JavaScriptCore/dfg/DFGResurrectionForValidationPhase.cpp
new file mode 100644
index 0000000..4c5f694
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGResurrectionForValidationPhase.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "DFGResurrectionForValidationPhase.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGBasicBlockInlines.h"
+#include "DFGGraph.h"
+#include "DFGInsertionSet.h"
+#include "DFGPhase.h"
+#include "Operations.h"
+
+namespace JSC { namespace DFG {
+
+class ResurrectionForValidationPhase : public Phase {
+public:
+ ResurrectionForValidationPhase(Graph& graph)
+ : Phase(graph, "resurrection for validation")
+ {
+ }
+
+ bool run()
+ {
+ InsertionSet insertionSet(m_graph);
+
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+
+ for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
+ Node* node = block->at(nodeIndex);
+ if (!node->hasResult())
+ continue;
+ insertionSet.insertNode(
+ nodeIndex + 1, SpecNone, Phantom, node->codeOrigin, Edge(node));
+ }
+
+ insertionSet.execute(block);
+ }
+
+ return true;
+ }
+};
+
+bool performResurrectionForValidation(Graph& graph)
+{
+ SamplingRegion samplingRegion("DFG Resurrection For Validation Phase");
+ return runPhase<ResurrectionForValidationPhase>(graph);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGResurrectionForValidationPhase.h b/Source/JavaScriptCore/dfg/DFGResurrectionForValidationPhase.h
new file mode 100644
index 0000000..98378ec
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGResurrectionForValidationPhase.h
@@ -0,0 +1,52 @@
+/*
+ * 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 DFGResurrectionForValidationPhase_h
+#define DFGResurrectionForValidationPhase_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGCommon.h"
+
+namespace JSC { namespace DFG {
+
+class Graph;
+
+// Places a Phantom after every value-producing node, thereby disabling DCE from killing it.
+// This is useful for validating our OSR exit machinery by instituting the requirement that
+// any live-in-bytecode variable should be OSR-available. Without this phase, it's impossible
+// to make such an assertion because our DCE is more aggressive than the bytecode liveness
+// analysis.
+
+bool performResurrectionForValidation(Graph&);
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGResurrectionForValidationPhase_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp b/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp
index fd68983..46689a2 100644
--- a/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp
@@ -158,13 +158,35 @@
for (unsigned j = block->predecessors.size(); j--;) {
BasicBlock* predecessor = block->predecessors[j];
predecessor->appendNonTerminal(
- m_graph, SpecNone, Upsilon, block->last()->codeOrigin,
+ m_graph, SpecNone, Upsilon, predecessor->last()->codeOrigin,
OpInfo(node), Edge(predecessor->variablesAtTail[i], useKind));
}
- m_insertionSet.insertNode(
- 0, SpecNone, MovHint, node->codeOrigin, OpInfo(variable),
- Edge(node));
+ if (m_flushedLocalOps.contains(node)) {
+ // Do nothing. For multiple reasons.
+
+ // Reason #1: If the local is flushed then we don't need to bother
+ // with a MovHint since every path to this point in the code will
+ // have flushed the bytecode variable using a SetLocal and hence
+ // the Availability::flushedAt() will agree, and that will be
+ // sufficient for figuring out how to recover the variable's value.
+
+ // Reason #2: If we had inserted a MovHint and the Phi function had
+ // died (because the only user of the value was the "flush" - i.e.
+ // some asynchronous runtime thingy) then the MovHint would turn
+ // into a ZombieHint, which would fool us into thinking that the
+ // variable is dead.
+
+ // Reason #3: If we had inserted a MovHint then even if the Phi
+ // stayed alive, we would still end up generating inefficient code
+ // since we would be telling the OSR exit compiler to use some SSA
+ // value for the bytecode variable rather than just telling it that
+ // the value was already on the stack.
+ } else {
+ m_insertionSet.insertNode(
+ 0, SpecNone, MovHint, node->codeOrigin, OpInfo(variable),
+ Edge(node));
+ }
}
}
diff --git a/Source/JavaScriptCore/dfg/DFGValueSource.h b/Source/JavaScriptCore/dfg/DFGValueSource.h
index 796c4d6..ff10892 100644
--- a/Source/JavaScriptCore/dfg/DFGValueSource.h
+++ b/Source/JavaScriptCore/dfg/DFGValueSource.h
@@ -145,6 +145,7 @@
{
switch (format) {
case DeadFlush:
+ case ConflictingFlush:
return ValueSource(SourceIsDead);
case FlushedJSValue:
return ValueSource(ValueInJSStack, where);
diff --git a/Source/JavaScriptCore/dfg/DFGVariableAccessData.h b/Source/JavaScriptCore/dfg/DFGVariableAccessData.h
index c9ba0c4..f9f4436 100644
--- a/Source/JavaScriptCore/dfg/DFGVariableAccessData.h
+++ b/Source/JavaScriptCore/dfg/DFGVariableAccessData.h
@@ -26,6 +26,7 @@
#ifndef DFGVariableAccessData_h
#define DFGVariableAccessData_h
+#include "DFGCommon.h"
#include "DFGDoubleFormatState.h"
#include "DFGFlushFormat.h"
#include "DFGFlushedAt.h"
@@ -39,6 +40,8 @@
namespace JSC { namespace DFG {
+struct Node;
+
enum DoubleBallot { VoteValue, VoteDouble };
class VariableAccessData : public UnionFind<VariableAccessData> {
diff --git a/Source/JavaScriptCore/ftl/FTLCompile.cpp b/Source/JavaScriptCore/ftl/FTLCompile.cpp
index 1fb9696..7ba1726 100644
--- a/Source/JavaScriptCore/ftl/FTLCompile.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCompile.cpp
@@ -160,6 +160,10 @@
for (unsigned i = 0; i < state.jitCode->osrExit.size(); ++i) {
OSRExitCompilationInfo& info = state.finalizer->osrExit[i];
OSRExit& exit = jitCode->osrExit[i];
+
+ if (Options::verboseCompilation())
+ dataLog("Handling OSR stackmap #", exit.m_stackmapID, "\n");
+
StackMaps::RecordMap::iterator iter = recordMap.find(exit.m_stackmapID);
if (iter == recordMap.end()) {
// It was optimized out.
@@ -180,6 +184,9 @@
for (unsigned i = state.getByIds.size(); i--;) {
GetByIdDescriptor& getById = state.getByIds[i];
+ if (Options::verboseCompilation())
+ dataLog("Handling GetById stackmap #", getById.stackmapID(), "\n");
+
StackMaps::RecordMap::iterator iter = recordMap.find(getById.stackmapID());
if (iter == recordMap.end()) {
// It was optimized out.
@@ -214,6 +221,9 @@
for (unsigned i = state.putByIds.size(); i--;) {
PutByIdDescriptor& putById = state.putByIds[i];
+ if (Options::verboseCompilation())
+ dataLog("Handling PutById stackmap #", putById.stackmapID(), "\n");
+
StackMaps::RecordMap::iterator iter = recordMap.find(putById.stackmapID());
if (iter == recordMap.end()) {
// It was optimized out.
diff --git a/Source/JavaScriptCore/ftl/FTLExitValue.cpp b/Source/JavaScriptCore/ftl/FTLExitValue.cpp
index 95dc82c..a987c60 100644
--- a/Source/JavaScriptCore/ftl/FTLExitValue.cpp
+++ b/Source/JavaScriptCore/ftl/FTLExitValue.cpp
@@ -48,16 +48,16 @@
out.print("Constant(", inContext(constant(), context), ")");
return;
case ExitValueInJSStack:
- out.print("InJSStack");
+ out.print("InJSStack:r", virtualRegister());
return;
case ExitValueInJSStackAsInt32:
- out.print("InJSStackAsInt32");
+ out.print("InJSStackAsInt32:r", virtualRegister());
return;
case ExitValueInJSStackAsInt52:
- out.print("InJSStackAsInt52");
+ out.print("InJSStackAsInt52:r", virtualRegister());
return;
case ExitValueInJSStackAsDouble:
- out.print("InJSStackAsDouble");
+ out.print("InJSStackAsDouble:r", virtualRegister());
return;
}
diff --git a/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp b/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp
index f023da7..82d4be5 100644
--- a/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp
+++ b/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp
@@ -39,7 +39,7 @@
size_t sizeOfGetById()
{
- return 29;
+ return 30;
}
size_t sizeOfPutById()
diff --git a/Source/JavaScriptCore/ftl/FTLLocation.cpp b/Source/JavaScriptCore/ftl/FTLLocation.cpp
index 3f7ab7d..a8ed642e 100644
--- a/Source/JavaScriptCore/ftl/FTLLocation.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLocation.cpp
@@ -92,7 +92,7 @@
// for example, the architecture encodes CX as 1 and DX as 2 while Dwarf does the
// opposite. Hence we need the switch.
- ASSERT(involvesGPR());
+ RELEASE_ASSERT(involvesGPR());
switch (dwarfRegNum()) {
case 0:
@@ -125,7 +125,7 @@
FPRReg Location::fpr() const
{
- ASSERT(isFPR());
+ RELEASE_ASSERT(isFPR());
return static_cast<FPRReg>(dwarfRegNum() - 17);
}
@@ -200,7 +200,7 @@
GPRReg Location::directGPR() const
{
- ASSERT(!addend());
+ RELEASE_ASSERT(!addend());
return gpr();
}
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index 7f68da7..3519725 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -38,7 +38,6 @@
#include "FTLLoweredNodeValue.h"
#include "FTLOutput.h"
#include "FTLThunks.h"
-#include "FTLValueSource.h"
#include "LinkBuffer.h"
#include "OperandsInlines.h"
#include "Operations.h"
@@ -70,7 +69,7 @@
, m_ftlState(state)
, m_heaps(state.context)
, m_out(state.context)
- , m_valueSources(OperandsLike, state.graph.block(0)->variablesAtHead)
+ , m_availability(OperandsLike, state.graph.block(0)->variablesAtHead)
, m_state(state.graph)
, m_interpreter(state.graph, m_state)
, m_stackmapIDs(0)
@@ -204,8 +203,6 @@
initializeOSRExitStateForBlock();
- m_live = block->ssa->liveAtHead;
-
m_state.reset();
m_state.beginBasicBlock(m_highBlock);
@@ -475,12 +472,6 @@
break;
}
- if (m_node->shouldGenerate())
- DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, use);
-
- if (m_node->adjustedRefCount())
- m_live.add(m_node);
-
if (shouldExecuteEffects)
m_interpreter.executeEffects(nodeIndex);
@@ -619,36 +610,31 @@
case FlushedJSValue: {
LValue value = lowJSValue(m_node->child1());
m_out.store64(value, addressFor(variable->machineLocal()));
- m_valueSources.operand(variable->local()) = ValueSource(ValueInJSStack, variable->machineLocal());
- return;
+ break;
}
case FlushedDouble: {
LValue value = lowDouble(m_node->child1());
m_out.storeDouble(value, addressFor(variable->machineLocal()));
- m_valueSources.operand(variable->local()) = ValueSource(DoubleInJSStack, variable->machineLocal());
- return;
+ break;
}
case FlushedInt32: {
LValue value = lowInt32(m_node->child1());
m_out.store32(value, payloadFor(variable->machineLocal()));
- m_valueSources.operand(variable->local()) = ValueSource(Int32InJSStack, variable->machineLocal());
- return;
+ break;
}
case FlushedInt52: {
LValue value = lowInt52(m_node->child1());
m_out.store64(value, addressFor(variable->machineLocal()));
- m_valueSources.operand(variable->local()) = ValueSource(Int52InJSStack, variable->machineLocal());
- return;
+ break;
}
case FlushedCell: {
LValue value = lowCell(m_node->child1());
m_out.store64(value, addressFor(variable->machineLocal()));
- m_valueSources.operand(variable->local()) = ValueSource(ValueInJSStack, variable->machineLocal());
- return;
+ break;
}
case FlushedBoolean: {
@@ -656,15 +642,15 @@
m_out.store64(
lowJSValue(m_node->child1(), ManualOperandSpeculation),
addressFor(variable->machineLocal()));
- m_valueSources.operand(variable->local()) = ValueSource(ValueInJSStack, variable->machineLocal());
- return;
+ break;
}
- case DeadFlush:
+ default:
RELEASE_ASSERT_NOT_REACHED();
+ break;
}
- RELEASE_ASSERT_NOT_REACHED();
+ m_availability.operand(variable->local()) = Availability(variable->flushedAt());
}
void compileMovHint()
@@ -675,7 +661,7 @@
void compileZombieHint()
{
VariableAccessData* data = m_node->variableAccessData();
- m_valueSources.operand(data->local()) = ValueSource(SourceIsDead);
+ m_availability.operand(data->local()) = Availability::unavailable();
}
void compileMovHintAndCheck()
@@ -1273,6 +1259,10 @@
// Arguments: id, bytes, target, numArgs, args...
unsigned stackmapID = m_stackmapIDs++;
+
+ if (Options::verboseCompilation())
+ dataLog(" Emitting GetById patchpoint with stackmap #", stackmapID, "\n");
+
LValue call = m_out.call(
m_out.patchpointInt64Intrinsic(),
m_out.constInt32(stackmapID), m_out.constInt32(sizeOfGetById()),
@@ -1287,13 +1277,17 @@
{
// See above; CellUse is easier so we do only that for now.
ASSERT(m_node->child1().useKind() == CellUse);
-
+
LValue base = lowCell(m_node->child1());
LValue value = lowJSValue(m_node->child2());
StringImpl* uid = m_graph.identifiers()[m_node->identifierNumber()];
// Arguments: id, bytes, target, numArgs, args...
unsigned stackmapID = m_stackmapIDs++;
+
+ if (Options::verboseCompilation())
+ dataLog(" Emitting PutById patchpoint with stackmap #", stackmapID, "\n");
+
LValue call = m_out.call(
m_out.patchpointVoidIntrinsic(),
m_out.constInt32(stackmapID), m_out.constInt32(sizeOfPutById()),
@@ -2544,12 +2538,12 @@
void compileInvalidationPoint()
{
if (verboseCompilationEnabled())
- dataLog(" Invalidation point with value sources: ", m_valueSources, "\n");
+ dataLog(" Invalidation point with availability: ", m_availability, "\n");
m_ftlState.jitCode->osrExit.append(OSRExit(
UncountableInvalidation, InvalidValueFormat, MethodOfGettingAValueProfile(),
m_codeOriginForExitTarget, m_codeOriginForExitProfile,
- m_valueSources.numberOfArguments(), m_valueSources.numberOfLocals()));
+ m_availability.numberOfArguments(), m_availability.numberOfLocals()));
m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo());
OSRExit& exit = m_ftlState.jitCode->osrExit.last();
@@ -2557,7 +2551,7 @@
ExitArgumentList arguments;
- buildExitArguments(exit, arguments, FormattedValue());
+ buildExitArguments(exit, arguments, FormattedValue(), exit.m_codeOrigin);
callStackmap(exit, arguments);
info.m_isInvalidationPoint = true;
@@ -3822,25 +3816,6 @@
m_out.appendTo(continuation, lastNext);
}
- bool isLive(Node* node)
- {
- return m_live.contains(node);
- }
-
- void use(Edge edge)
- {
- ASSERT(edge->hasResult());
- if (!edge.doesKill())
- return;
- m_live.remove(edge.node());
- }
-
- // Wrapper used only for DFG_NODE_DO_TO_CHILDREN
- void use(Node*, Edge edge)
- {
- use(edge);
- }
-
LBasicBlock lowBlock(BasicBlock* block)
{
return m_blocks.get(block);
@@ -3848,40 +3823,7 @@
void initializeOSRExitStateForBlock()
{
- for (unsigned i = m_valueSources.size(); i--;) {
- FlushedAt flush = m_highBlock->ssa->flushAtHead[i];
- switch (flush.format()) {
- case DeadFlush: {
- // Must consider available nodes instead.
- Node* node = m_highBlock->ssa->availabilityAtHead[i];
- if (!node) {
- m_valueSources[i] = ValueSource(SourceIsDead);
- break;
- }
-
- m_valueSources[i] = ValueSource(node);
- break;
- }
-
- case FlushedInt32:
- m_valueSources[i] = ValueSource(Int32InJSStack, flush.virtualRegister());
- break;
-
- case FlushedInt52:
- m_valueSources[i] = ValueSource(Int52InJSStack, flush.virtualRegister());
- break;
-
- case FlushedDouble:
- m_valueSources[i] = ValueSource(DoubleInJSStack, flush.virtualRegister());
- break;
-
- case FlushedCell:
- case FlushedBoolean:
- case FlushedJSValue:
- m_valueSources[i] = ValueSource(ValueInJSStack, flush.virtualRegister());
- break;
- }
- }
+ m_availability = m_highBlock->ssa->availabilityAtHead;
}
void appendOSRExit(
@@ -3889,14 +3831,14 @@
SpeculationDirection direction, FormattedValue recovery)
{
if (verboseCompilationEnabled())
- dataLog(" OSR exit with value sources: ", m_valueSources, "\n");
-
+ dataLog(" OSR exit #", m_ftlState.jitCode->osrExit.size(), " with availability: ", m_availability, "\n");
+
ASSERT(m_ftlState.jitCode->osrExit.size() == m_ftlState.finalizer->osrExit.size());
m_ftlState.jitCode->osrExit.append(OSRExit(
kind, lowValue.format(), m_graph.methodOfGettingAValueProfileFor(highValue),
m_codeOriginForExitTarget, m_codeOriginForExitProfile,
- m_valueSources.numberOfArguments(), m_valueSources.numberOfLocals()));
+ m_availability.numberOfArguments(), m_availability.numberOfLocals()));
m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo());
OSRExit& exit = m_ftlState.jitCode->osrExit.last();
@@ -3924,10 +3866,23 @@
{
ExitArgumentList arguments;
- buildExitArguments(exit, arguments, lowValue);
+ CodeOrigin codeOrigin = exit.m_codeOrigin;
- if (direction == ForwardSpeculation) {
- ASSERT(m_node);
+ if (direction == BackwardSpeculation)
+ buildExitArguments(exit, arguments, lowValue, codeOrigin);
+ else {
+ ASSERT(direction == ForwardSpeculation);
+ if (!recovery) {
+ for (unsigned nodeIndex = m_nodeIndex; nodeIndex < m_highBlock->size(); ++nodeIndex) {
+ Node* node = m_highBlock->at(nodeIndex);
+ if (node->codeOriginForExitTarget == codeOrigin)
+ continue;
+ codeOrigin = node->codeOriginForExitTarget;
+ break;
+ }
+ }
+
+ buildExitArguments(exit, arguments, lowValue, codeOrigin);
exit.convertToForward(m_highBlock, m_node, m_nodeIndex, recovery, arguments);
}
@@ -3935,36 +3890,59 @@
}
void buildExitArguments(
- OSRExit& exit, ExitArgumentList& arguments, FormattedValue lowValue)
+ OSRExit& exit, ExitArgumentList& arguments, FormattedValue lowValue,
+ CodeOrigin codeOrigin)
{
arguments.append(m_callFrame);
if (!!lowValue)
arguments.append(lowValue.value());
for (unsigned i = 0; i < exit.m_values.size(); ++i) {
- ValueSource source = m_valueSources[i];
+ int operand = exit.m_values.operandForIndex(i);
+ bool isLive = m_graph.isLiveInBytecode(VirtualRegister(operand), codeOrigin);
+ if (!isLive) {
+ exit.m_values[i] = ExitValue::dead();
+ continue;
+ }
- switch (source.kind()) {
- case ValueInJSStack:
- exit.m_values[i] = ExitValue::inJSStack(source.virtualRegister());
- break;
- case Int32InJSStack:
- exit.m_values[i] = ExitValue::inJSStackAsInt32(source.virtualRegister());
- break;
- case Int52InJSStack:
- exit.m_values[i] = ExitValue::inJSStackAsInt52(source.virtualRegister());
- break;
- case DoubleInJSStack:
- exit.m_values[i] = ExitValue::inJSStackAsDouble(source.virtualRegister());
- break;
- case SourceIsDead:
+ Availability availability = m_availability[i];
+ FlushedAt flush = availability.flushedAt();
+ switch (flush.format()) {
+ case DeadFlush:
+ case ConflictingFlush:
+ if (availability.hasNode()) {
+ addExitArgumentForNode(exit, arguments, i, availability.node());
+ break;
+ }
+
+ if (Options::validateFTLOSRExitLiveness()) {
+ dataLog("Expected r", operand, " to be available but it wasn't.\n");
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
+ // This means that the DFG's DCE proved that the value is dead in bytecode
+ // even though the bytecode liveness analysis thinks it's live. This is
+ // acceptable since the DFG's DCE is by design more aggressive while still
+ // being sound.
exit.m_values[i] = ExitValue::dead();
break;
- case HaveNode:
- addExitArgumentForNode(exit, arguments, i, source.node());
+
+ case FlushedJSValue:
+ case FlushedCell:
+ case FlushedBoolean:
+ exit.m_values[i] = ExitValue::inJSStack(flush.virtualRegister());
break;
- default:
- RELEASE_ASSERT_NOT_REACHED();
+
+ case FlushedInt32:
+ exit.m_values[i] = ExitValue::inJSStackAsInt32(flush.virtualRegister());
+ break;
+
+ case FlushedInt52:
+ exit.m_values[i] = ExitValue::inJSStackAsInt52(flush.virtualRegister());
+ break;
+
+ case FlushedDouble:
+ exit.m_values[i] = ExitValue::inJSStackAsDouble(flush.virtualRegister());
break;
}
}
@@ -3991,53 +3969,6 @@
if (tryToSetConstantExitArgument(exit, index, node))
return;
- if (!isLive(node)) {
- bool found = false;
-
- if (permitsOSRBackwardRewiring(node->op())) {
- node = node->child1().node();
- if (tryToSetConstantExitArgument(exit, index, node))
- return;
- if (isLive(node))
- found = true;
- }
-
- if (!found) {
- Node* bestNode = 0;
- unsigned bestScore = 0;
-
- HashSet<Node*>::iterator iter = m_live.begin();
- HashSet<Node*>::iterator end = m_live.end();
- for (; iter != end; ++iter) {
- Node* candidate = *iter;
- if (candidate->flags() & NodeHasVarArgs)
- continue;
- if (!candidate->child1())
- continue;
- if (candidate->child1() != node)
- continue;
- unsigned myScore = forwardRewiringSelectionScore(candidate->op());
- if (myScore <= bestScore)
- continue;
- bestNode = candidate;
- bestScore = myScore;
- }
-
- if (bestNode) {
- ASSERT(isLive(bestNode));
- node = bestNode;
- found = true;
- }
- }
-
- if (!found) {
- exit.m_values[index] = ExitValue::dead();
- return;
- }
- }
-
- ASSERT(isLive(node));
-
LoweredNodeValue value = m_int32Values.get(node);
if (isValid(value)) {
addExitArgument(exit, arguments, index, ValueFormatInt32, value.value());
@@ -4114,7 +4045,7 @@
VirtualRegister operand = node->local();
- m_valueSources.operand(operand) = ValueSource(node->child1().node());
+ m_availability.operand(operand) = Availability(node->child1().node());
}
void setInt32(Node* node, LValue value)
@@ -4272,11 +4203,10 @@
HashMap<Node*, LoweredNodeValue> m_booleanValues;
HashMap<Node*, LoweredNodeValue> m_storageValues;
HashMap<Node*, LoweredNodeValue> m_doubleValues;
- HashSet<Node*> m_live;
HashMap<Node*, LValue> m_phis;
- Operands<ValueSource> m_valueSources;
+ Operands<Availability> m_availability;
InPlaceAbstractState m_state;
AbstractInterpreter<InPlaceAbstractState> m_interpreter;
diff --git a/Source/JavaScriptCore/ftl/FTLOutput.h b/Source/JavaScriptCore/ftl/FTLOutput.h
index 6ccb31d..17eaa5d19 100644
--- a/Source/JavaScriptCore/ftl/FTLOutput.h
+++ b/Source/JavaScriptCore/ftl/FTLOutput.h
@@ -199,6 +199,7 @@
LValue intToPtr(LValue value, LType type) { return buildIntToPtr(m_builder, value, type); }
LValue bitCast(LValue value, LType type) { return buildBitCast(m_builder, value, type); }
+ LValue alloca(LType type) { return buildAlloca(m_builder, type); }
LValue get(LValue reference) { return buildLoad(m_builder, reference); }
LValue set(LValue value, LValue reference) { return buildStore(m_builder, value, reference); }
diff --git a/Source/JavaScriptCore/ftl/FTLValueSource.h b/Source/JavaScriptCore/ftl/FTLValueSource.h
deleted file mode 100644
index 3a4a55b..0000000
--- a/Source/JavaScriptCore/ftl/FTLValueSource.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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 FTLValueSource_h
-#define FTLValueSource_h
-
-#include <wtf/Platform.h>
-
-#if ENABLE(FTL_JIT)
-
-#include "DFGNode.h"
-#include <wtf/PrintStream.h>
-#include <wtf/StdLibExtras.h>
-
-namespace JSC { namespace FTL {
-
-enum ValueSourceKind {
- SourceNotSet,
- ValueInJSStack,
- Int32InJSStack,
- Int52InJSStack,
- DoubleInJSStack,
- SourceIsDead,
- HaveNode
-};
-
-class ValueSource {
-public:
- ValueSource()
- : m_kind(SourceNotSet)
- {
- }
-
- explicit ValueSource(ValueSourceKind kind)
- : m_kind(kind)
- {
- ASSERT(m_kind == SourceIsDead);
- }
-
- explicit ValueSource(DFG::Node* node)
- : m_kind(HaveNode)
- {
- m_value.node = node;
- }
-
- ValueSource(ValueSourceKind kind, VirtualRegister reg)
- : m_kind(kind)
- {
- ASSERT(m_kind == ValueInJSStack || m_kind == Int32InJSStack || m_kind == Int52InJSStack || m_kind == DoubleInJSStack);
- m_value.virtualRegister = reg.offset();
- }
-
- ValueSourceKind kind() const
- {
- return m_kind;
- }
-
- bool operator!() const { return kind() == SourceNotSet; }
-
- DFG::Node* node() const
- {
- ASSERT(kind() == HaveNode);
- return m_value.node;
- }
-
- VirtualRegister virtualRegister() const
- {
- ASSERT(kind() == ValueInJSStack || kind() == Int32InJSStack || kind() == Int52InJSStack || kind() == DoubleInJSStack);
- return VirtualRegister(m_value.virtualRegister);
- }
-
- void dump(PrintStream&) const;
- void dumpInContext(PrintStream&, DumpContext*) const;
-
-private:
- ValueSourceKind m_kind;
- union {
- DFG::Node* node;
- int virtualRegister;
- } m_value;
-};
-
-} } // namespace JSC::FTL
-
-#endif // ENABLE(FTL_JIT)
-
-#endif // FTLValueSource_h
-
diff --git a/Source/JavaScriptCore/llvm/LLVMAPIFunctions.h b/Source/JavaScriptCore/llvm/LLVMAPIFunctions.h
index bc44b7a..1a09660 100644
--- a/Source/JavaScriptCore/llvm/LLVMAPIFunctions.h
+++ b/Source/JavaScriptCore/llvm/LLVMAPIFunctions.h
@@ -535,7 +535,6 @@
macro(LLVMBool, TargetHasJIT, (LLVMTargetRef T)) \
macro(LLVMBool, TargetHasTargetMachine, (LLVMTargetRef T)) \
macro(LLVMBool, TargetHasAsmBackend, (LLVMTargetRef T)) \
- macro(LLVMTargetMachineRef, CreateTargetMachine, (LLVMTargetRef T, char *Triple, char *CPU, char *Features, LLVMCodeGenOptLevel Level, LLVMRelocMode Reloc, LLVMCodeModel CodeModel)) \
macro(void, DisposeTargetMachine, (LLVMTargetMachineRef T)) \
macro(LLVMTargetRef, GetTargetMachineTarget, (LLVMTargetMachineRef T)) \
macro(char *, GetTargetMachineTriple, (LLVMTargetMachineRef T)) \
diff --git a/Source/JavaScriptCore/runtime/DumpContext.cpp b/Source/JavaScriptCore/runtime/DumpContext.cpp
index 84c80bb..0546f4c 100644
--- a/Source/JavaScriptCore/runtime/DumpContext.cpp
+++ b/Source/JavaScriptCore/runtime/DumpContext.cpp
@@ -28,7 +28,11 @@
namespace JSC {
-DumpContext::DumpContext() { }
+DumpContext::DumpContext()
+ : graph(0)
+{
+}
+
DumpContext::~DumpContext() { }
bool DumpContext::isEmpty() const
diff --git a/Source/JavaScriptCore/runtime/DumpContext.h b/Source/JavaScriptCore/runtime/DumpContext.h
index e24ced0..9ec9313 100644
--- a/Source/JavaScriptCore/runtime/DumpContext.h
+++ b/Source/JavaScriptCore/runtime/DumpContext.h
@@ -32,6 +32,8 @@
namespace JSC {
+namespace DFG { class Graph; }
+
struct DumpContext {
DumpContext();
~DumpContext();
@@ -41,6 +43,7 @@
void dump(PrintStream&, const char* prefix = "") const;
StringHashDumpContext<Structure> structures;
+ DFG::Graph* graph;
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h
index 3bfc677..62f3f3e 100644
--- a/Source/JavaScriptCore/runtime/Options.h
+++ b/Source/JavaScriptCore/runtime/Options.h
@@ -126,6 +126,7 @@
v(bool, enableLLVMFastISel, false) \
v(bool, useLLVMSmallCodeModel, false) \
v(bool, dumpLLVMIR, false) \
+ v(bool, validateFTLOSRExitLiveness, false) \
v(bool, llvmAlwaysFailsBeforeCompile, false) \
v(bool, llvmAlwaysFailsBeforeLink, false) \
v(bool, llvmSimpleOpt, true) \
diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h
index c958324..27e09a9 100644
--- a/Source/JavaScriptCore/runtime/SymbolTable.h
+++ b/Source/JavaScriptCore/runtime/SymbolTable.h
@@ -469,13 +469,13 @@
bool usesNonStrictEval() { return m_usesNonStrictEval; }
void setUsesNonStrictEval(bool usesNonStrictEval) { m_usesNonStrictEval = usesNonStrictEval; }
- int captureStart() { return m_captureStart; }
+ int captureStart() const { return m_captureStart; }
void setCaptureStart(int captureStart) { m_captureStart = captureStart; }
- int captureEnd() { return m_captureEnd; }
+ int captureEnd() const { return m_captureEnd; }
void setCaptureEnd(int captureEnd) { m_captureEnd = captureEnd; }
- int captureCount() { return -(m_captureEnd - m_captureStart); }
+ int captureCount() const { return -(m_captureEnd - m_captureStart); }
int parameterCount() { return m_parameterCountIncludingThis - 1; }
int parameterCountIncludingThis() { return m_parameterCountIncludingThis; }