From 8618e4ba3ba8510026f6ee57076c35a232f08e83 Mon Sep 17 00:00:00 2001 From: "fpizlo@apple.com" Date: Tue, 3 Jul 2012 01:27:16 +0000 Subject: [PATCH] DFG OSR exit value recoveries should be computed lazily https://bugs.webkit.org/show_bug.cgi?id=82155 Reviewed by Gavin Barraclough. This change aims to reduce one aspect of DFG compile times: the fact that we currently compute the value recoveries for each local and argument on every speculation check. We compile many speculation checks, so this can add up quick. The strategy that this change takes is to have the DFG save just enough information about how the compiler is choosing to represent state, that the DFG::OSRExitCompiler can reify the value recoveries lazily. This appears to be an 0.3% SunSpider speed-up and is neutral elsewhere. I also took the opportunity to fix the sampling regions profiler (it was missing an export macro) and to put in more sampling regions in the DFG (which are disabled so long as ENABLE(SAMPLING_REGIONS) is false). * CMakeLists.txt: * GNUmakefile.list.am: * JavaScriptCore.xcodeproj/project.pbxproj: * Target.pri: * bytecode/CodeBlock.cpp: (JSC): (JSC::CodeBlock::shrinkDFGDataToFit): * bytecode/CodeBlock.h: (CodeBlock): (JSC::CodeBlock::minifiedDFG): (JSC::CodeBlock::variableEventStream): (DFGData): * bytecode/Operands.h: (JSC::Operands::hasOperand): (Operands): (JSC::Operands::size): (JSC::Operands::at): (JSC::Operands::operator[]): (JSC::Operands::isArgument): (JSC::Operands::isVariable): (JSC::Operands::argumentForIndex): (JSC::Operands::variableForIndex): (JSC::Operands::operandForIndex): (JSC): (JSC::dumpOperands): * bytecode/SamplingTool.h: (SamplingRegion): * dfg/DFGByteCodeParser.cpp: (JSC::DFG::parse): * dfg/DFGCFAPhase.cpp: (JSC::DFG::performCFA): * dfg/DFGCSEPhase.cpp: (JSC::DFG::performCSE): * dfg/DFGFixupPhase.cpp: (JSC::DFG::performFixup): * dfg/DFGGenerationInfo.h: (JSC::DFG::GenerationInfo::GenerationInfo): (JSC::DFG::GenerationInfo::initConstant): (JSC::DFG::GenerationInfo::initInteger): (JSC::DFG::GenerationInfo::initJSValue): (JSC::DFG::GenerationInfo::initCell): (JSC::DFG::GenerationInfo::initBoolean): (JSC::DFG::GenerationInfo::initDouble): (JSC::DFG::GenerationInfo::initStorage): (GenerationInfo): (JSC::DFG::GenerationInfo::noticeOSRBirth): (JSC::DFG::GenerationInfo::use): (JSC::DFG::GenerationInfo::spill): (JSC::DFG::GenerationInfo::setSpilled): (JSC::DFG::GenerationInfo::fillJSValue): (JSC::DFG::GenerationInfo::fillCell): (JSC::DFG::GenerationInfo::fillInteger): (JSC::DFG::GenerationInfo::fillBoolean): (JSC::DFG::GenerationInfo::fillDouble): (JSC::DFG::GenerationInfo::fillStorage): (JSC::DFG::GenerationInfo::appendFill): (JSC::DFG::GenerationInfo::appendSpill): * dfg/DFGJITCompiler.cpp: (JSC::DFG::JITCompiler::link): (JSC::DFG::JITCompiler::compile): (JSC::DFG::JITCompiler::compileFunction): * dfg/DFGMinifiedGraph.h: Added. (DFG): (MinifiedGraph): (JSC::DFG::MinifiedGraph::MinifiedGraph): (JSC::DFG::MinifiedGraph::at): (JSC::DFG::MinifiedGraph::append): (JSC::DFG::MinifiedGraph::prepareAndShrink): (JSC::DFG::MinifiedGraph::setOriginalGraphSize): (JSC::DFG::MinifiedGraph::originalGraphSize): * dfg/DFGMinifiedNode.cpp: Added. (DFG): (JSC::DFG::MinifiedNode::fromNode): * dfg/DFGMinifiedNode.h: Added. (DFG): (JSC::DFG::belongsInMinifiedGraph): (MinifiedNode): (JSC::DFG::MinifiedNode::MinifiedNode): (JSC::DFG::MinifiedNode::index): (JSC::DFG::MinifiedNode::op): (JSC::DFG::MinifiedNode::hasChild1): (JSC::DFG::MinifiedNode::child1): (JSC::DFG::MinifiedNode::hasConstant): (JSC::DFG::MinifiedNode::hasConstantNumber): (JSC::DFG::MinifiedNode::constantNumber): (JSC::DFG::MinifiedNode::hasWeakConstant): (JSC::DFG::MinifiedNode::weakConstant): (JSC::DFG::MinifiedNode::getIndex): (JSC::DFG::MinifiedNode::compareByNodeIndex): (JSC::DFG::MinifiedNode::hasChild): * dfg/DFGNode.h: (Node): * dfg/DFGOSRExit.cpp: (JSC::DFG::OSRExit::OSRExit): * dfg/DFGOSRExit.h: (OSRExit): * dfg/DFGOSRExitCompiler.cpp: * dfg/DFGOSRExitCompiler.h: (OSRExitCompiler): * dfg/DFGOSRExitCompiler32_64.cpp: (JSC::DFG::OSRExitCompiler::compileExit): * dfg/DFGOSRExitCompiler64.cpp: (JSC::DFG::OSRExitCompiler::compileExit): * dfg/DFGPredictionPropagationPhase.cpp: (JSC::DFG::performPredictionPropagation): * dfg/DFGRedundantPhiEliminationPhase.cpp: (JSC::DFG::performRedundantPhiElimination): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::SpeculativeJIT): (DFG): (JSC::DFG::SpeculativeJIT::fillStorage): (JSC::DFG::SpeculativeJIT::noticeOSRBirth): (JSC::DFG::SpeculativeJIT::compileMovHint): (JSC::DFG::SpeculativeJIT::compile): (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor): * dfg/DFGSpeculativeJIT.h: (DFG): (JSC::DFG::SpeculativeJIT::use): (SpeculativeJIT): (JSC::DFG::SpeculativeJIT::spill): (JSC::DFG::SpeculativeJIT::speculationCheck): (JSC::DFG::SpeculativeJIT::forwardSpeculationCheck): (JSC::DFG::SpeculativeJIT::recordSetLocal): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::fillInteger): (JSC::DFG::SpeculativeJIT::fillDouble): (JSC::DFG::SpeculativeJIT::fillJSValue): (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal): (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): (JSC::DFG::SpeculativeJIT::fillSpeculateCell): (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::fillInteger): (JSC::DFG::SpeculativeJIT::fillDouble): (JSC::DFG::SpeculativeJIT::fillJSValue): (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal): (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): (JSC::DFG::SpeculativeJIT::fillSpeculateCell): (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGValueRecoveryOverride.h: Added. (DFG): (ValueRecoveryOverride): (JSC::DFG::ValueRecoveryOverride::ValueRecoveryOverride): * dfg/DFGValueSource.cpp: Added. (DFG): (JSC::DFG::ValueSource::dump): * dfg/DFGValueSource.h: Added. (DFG): (JSC::DFG::dataFormatToValueSourceKind): (JSC::DFG::valueSourceKindToDataFormat): (JSC::DFG::isInRegisterFile): (ValueSource): (JSC::DFG::ValueSource::ValueSource): (JSC::DFG::ValueSource::forPrediction): (JSC::DFG::ValueSource::forDataFormat): (JSC::DFG::ValueSource::isSet): (JSC::DFG::ValueSource::kind): (JSC::DFG::ValueSource::isInRegisterFile): (JSC::DFG::ValueSource::dataFormat): (JSC::DFG::ValueSource::valueRecovery): (JSC::DFG::ValueSource::nodeIndex): (JSC::DFG::ValueSource::nodeIndexFromKind): (JSC::DFG::ValueSource::kindFromNodeIndex): * dfg/DFGVariableEvent.cpp: Added. (DFG): (JSC::DFG::VariableEvent::dump): (JSC::DFG::VariableEvent::dumpFillInfo): (JSC::DFG::VariableEvent::dumpSpillInfo): * dfg/DFGVariableEvent.h: Added. (DFG): (VariableEvent): (JSC::DFG::VariableEvent::VariableEvent): (JSC::DFG::VariableEvent::reset): (JSC::DFG::VariableEvent::fillGPR): (JSC::DFG::VariableEvent::fillPair): (JSC::DFG::VariableEvent::fillFPR): (JSC::DFG::VariableEvent::spill): (JSC::DFG::VariableEvent::death): (JSC::DFG::VariableEvent::setLocal): (JSC::DFG::VariableEvent::movHint): (JSC::DFG::VariableEvent::kind): (JSC::DFG::VariableEvent::nodeIndex): (JSC::DFG::VariableEvent::dataFormat): (JSC::DFG::VariableEvent::gpr): (JSC::DFG::VariableEvent::tagGPR): (JSC::DFG::VariableEvent::payloadGPR): (JSC::DFG::VariableEvent::fpr): (JSC::DFG::VariableEvent::virtualRegister): (JSC::DFG::VariableEvent::operand): (JSC::DFG::VariableEvent::variableRepresentation): * dfg/DFGVariableEventStream.cpp: Added. (DFG): (JSC::DFG::VariableEventStream::logEvent): (MinifiedGenerationInfo): (JSC::DFG::MinifiedGenerationInfo::MinifiedGenerationInfo): (JSC::DFG::MinifiedGenerationInfo::update): (JSC::DFG::VariableEventStream::reconstruct): * dfg/DFGVariableEventStream.h: Added. (DFG): (VariableEventStream): (JSC::DFG::VariableEventStream::appendAndLog): * dfg/DFGVirtualRegisterAllocationPhase.cpp: (JSC::DFG::performVirtualRegisterAllocation): git-svn-id: http://svn.webkit.org/repository/webkit/trunk@121717 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- Source/JavaScriptCore/CMakeLists.txt | 4 + Source/JavaScriptCore/ChangeLog | 228 ++++++++++++++++ Source/JavaScriptCore/GNUmakefile.list.am | 10 + .../JavaScriptCore.xcodeproj/project.pbxproj | 40 +++ Source/JavaScriptCore/Target.pri | 4 + Source/JavaScriptCore/bytecode/CodeBlock.cpp | 4 +- Source/JavaScriptCore/bytecode/CodeBlock.h | 16 ++ Source/JavaScriptCore/bytecode/DataFormat.h | 9 +- Source/JavaScriptCore/bytecode/Operands.h | 50 ++++ .../dfg/DFGArgumentsSimplificationPhase.cpp | 1 + Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp | 1 + Source/JavaScriptCore/dfg/DFGCFAPhase.cpp | 1 + .../dfg/DFGCFGSimplificationPhase.cpp | 1 + Source/JavaScriptCore/dfg/DFGCSEPhase.cpp | 1 + .../JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp | 1 + Source/JavaScriptCore/dfg/DFGFixupPhase.cpp | 1 + Source/JavaScriptCore/dfg/DFGGenerationInfo.h | 107 +++++++- Source/JavaScriptCore/dfg/DFGJITCompiler.cpp | 5 + Source/JavaScriptCore/dfg/DFGMinifiedGraph.h | 81 ++++++ Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp | 57 ++++ Source/JavaScriptCore/dfg/DFGMinifiedNode.h | 129 ++++++++++ Source/JavaScriptCore/dfg/DFGNode.h | 3 +- Source/JavaScriptCore/dfg/DFGOSRExit.cpp | 28 +- Source/JavaScriptCore/dfg/DFGOSRExit.h | 42 +-- Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp | 16 +- Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h | 2 +- .../JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp | 117 ++++----- Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp | 93 +++---- .../dfg/DFGPredictionPropagationPhase.cpp | 1 + .../dfg/DFGRedundantPhiEliminationPhase.cpp | 1 + Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp | 280 ++++++-------------- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h | 124 +++------ .../JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp | 111 ++++---- Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp | 133 +++++----- .../JavaScriptCore/dfg/DFGValueRecoveryOverride.h | 57 ++++ Source/JavaScriptCore/dfg/DFGValueSource.cpp | 69 +++++ Source/JavaScriptCore/dfg/DFGValueSource.h | 225 ++++++++++++++++ Source/JavaScriptCore/dfg/DFGVariableEvent.cpp | 91 +++++++ Source/JavaScriptCore/dfg/DFGVariableEvent.h | 270 +++++++++++++++++++ .../JavaScriptCore/dfg/DFGVariableEventStream.cpp | 286 +++++++++++++++++++++ Source/JavaScriptCore/dfg/DFGVariableEventStream.h | 64 +++++ .../dfg/DFGVirtualRegisterAllocationPhase.cpp | 1 + 42 files changed, 2162 insertions(+), 603 deletions(-) create mode 100644 Source/JavaScriptCore/dfg/DFGMinifiedGraph.h create mode 100644 Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp create mode 100644 Source/JavaScriptCore/dfg/DFGMinifiedNode.h create mode 100644 Source/JavaScriptCore/dfg/DFGValueRecoveryOverride.h create mode 100644 Source/JavaScriptCore/dfg/DFGValueSource.cpp create mode 100644 Source/JavaScriptCore/dfg/DFGValueSource.h create mode 100644 Source/JavaScriptCore/dfg/DFGVariableEvent.cpp create mode 100644 Source/JavaScriptCore/dfg/DFGVariableEvent.h create mode 100644 Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp create mode 100644 Source/JavaScriptCore/dfg/DFGVariableEventStream.h diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index 06139a4..a5a6ed8 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -78,6 +78,7 @@ SET(JavaScriptCore_SOURCES dfg/DFGFixupPhase.cpp dfg/DFGGraph.cpp dfg/DFGJITCompiler.cpp + dfg/DFGMinifiedNode.cpp dfg/DFGNodeFlags.cpp dfg/DFGOSREntry.cpp dfg/DFGOSRExit.cpp @@ -93,6 +94,9 @@ SET(JavaScriptCore_SOURCES dfg/DFGSpeculativeJIT32_64.cpp dfg/DFGSpeculativeJIT64.cpp dfg/DFGThunks.cpp + dfg/DFGValueSource.cpp + dfg/DFGVariableEvent.cpp + dfg/DFGVariableEventStream.cpp dfg/DFGValidate.cpp dfg/DFGVirtualRegisterAllocationPhase.cpp diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 40b4b7e..2ad874d 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,5 +1,233 @@ 2012-07-02 Filip Pizlo + DFG OSR exit value recoveries should be computed lazily + https://bugs.webkit.org/show_bug.cgi?id=82155 + + Reviewed by Gavin Barraclough. + + This change aims to reduce one aspect of DFG compile times: the fact + that we currently compute the value recoveries for each local and + argument on every speculation check. We compile many speculation checks, + so this can add up quick. The strategy that this change takes is to + have the DFG save just enough information about how the compiler is + choosing to represent state, that the DFG::OSRExitCompiler can reify + the value recoveries lazily. + + This appears to be an 0.3% SunSpider speed-up and is neutral elsewhere. + + I also took the opportunity to fix the sampling regions profiler (it + was missing an export macro) and to put in more sampling regions in + the DFG (which are disabled so long as ENABLE(SAMPLING_REGIONS) is + false). + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * bytecode/CodeBlock.cpp: + (JSC): + (JSC::CodeBlock::shrinkDFGDataToFit): + * bytecode/CodeBlock.h: + (CodeBlock): + (JSC::CodeBlock::minifiedDFG): + (JSC::CodeBlock::variableEventStream): + (DFGData): + * bytecode/Operands.h: + (JSC::Operands::hasOperand): + (Operands): + (JSC::Operands::size): + (JSC::Operands::at): + (JSC::Operands::operator[]): + (JSC::Operands::isArgument): + (JSC::Operands::isVariable): + (JSC::Operands::argumentForIndex): + (JSC::Operands::variableForIndex): + (JSC::Operands::operandForIndex): + (JSC): + (JSC::dumpOperands): + * bytecode/SamplingTool.h: + (SamplingRegion): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::parse): + * dfg/DFGCFAPhase.cpp: + (JSC::DFG::performCFA): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::performCSE): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::performFixup): + * dfg/DFGGenerationInfo.h: + (JSC::DFG::GenerationInfo::GenerationInfo): + (JSC::DFG::GenerationInfo::initConstant): + (JSC::DFG::GenerationInfo::initInteger): + (JSC::DFG::GenerationInfo::initJSValue): + (JSC::DFG::GenerationInfo::initCell): + (JSC::DFG::GenerationInfo::initBoolean): + (JSC::DFG::GenerationInfo::initDouble): + (JSC::DFG::GenerationInfo::initStorage): + (GenerationInfo): + (JSC::DFG::GenerationInfo::noticeOSRBirth): + (JSC::DFG::GenerationInfo::use): + (JSC::DFG::GenerationInfo::spill): + (JSC::DFG::GenerationInfo::setSpilled): + (JSC::DFG::GenerationInfo::fillJSValue): + (JSC::DFG::GenerationInfo::fillCell): + (JSC::DFG::GenerationInfo::fillInteger): + (JSC::DFG::GenerationInfo::fillBoolean): + (JSC::DFG::GenerationInfo::fillDouble): + (JSC::DFG::GenerationInfo::fillStorage): + (JSC::DFG::GenerationInfo::appendFill): + (JSC::DFG::GenerationInfo::appendSpill): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + (JSC::DFG::JITCompiler::compile): + (JSC::DFG::JITCompiler::compileFunction): + * dfg/DFGMinifiedGraph.h: Added. + (DFG): + (MinifiedGraph): + (JSC::DFG::MinifiedGraph::MinifiedGraph): + (JSC::DFG::MinifiedGraph::at): + (JSC::DFG::MinifiedGraph::append): + (JSC::DFG::MinifiedGraph::prepareAndShrink): + (JSC::DFG::MinifiedGraph::setOriginalGraphSize): + (JSC::DFG::MinifiedGraph::originalGraphSize): + * dfg/DFGMinifiedNode.cpp: Added. + (DFG): + (JSC::DFG::MinifiedNode::fromNode): + * dfg/DFGMinifiedNode.h: Added. + (DFG): + (JSC::DFG::belongsInMinifiedGraph): + (MinifiedNode): + (JSC::DFG::MinifiedNode::MinifiedNode): + (JSC::DFG::MinifiedNode::index): + (JSC::DFG::MinifiedNode::op): + (JSC::DFG::MinifiedNode::hasChild1): + (JSC::DFG::MinifiedNode::child1): + (JSC::DFG::MinifiedNode::hasConstant): + (JSC::DFG::MinifiedNode::hasConstantNumber): + (JSC::DFG::MinifiedNode::constantNumber): + (JSC::DFG::MinifiedNode::hasWeakConstant): + (JSC::DFG::MinifiedNode::weakConstant): + (JSC::DFG::MinifiedNode::getIndex): + (JSC::DFG::MinifiedNode::compareByNodeIndex): + (JSC::DFG::MinifiedNode::hasChild): + * dfg/DFGNode.h: + (Node): + * dfg/DFGOSRExit.cpp: + (JSC::DFG::OSRExit::OSRExit): + * dfg/DFGOSRExit.h: + (OSRExit): + * dfg/DFGOSRExitCompiler.cpp: + * dfg/DFGOSRExitCompiler.h: + (OSRExitCompiler): + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::performPredictionPropagation): + * dfg/DFGRedundantPhiEliminationPhase.cpp: + (JSC::DFG::performRedundantPhiElimination): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::SpeculativeJIT): + (DFG): + (JSC::DFG::SpeculativeJIT::fillStorage): + (JSC::DFG::SpeculativeJIT::noticeOSRBirth): + (JSC::DFG::SpeculativeJIT::compileMovHint): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor): + * dfg/DFGSpeculativeJIT.h: + (DFG): + (JSC::DFG::SpeculativeJIT::use): + (SpeculativeJIT): + (JSC::DFG::SpeculativeJIT::spill): + (JSC::DFG::SpeculativeJIT::speculationCheck): + (JSC::DFG::SpeculativeJIT::forwardSpeculationCheck): + (JSC::DFG::SpeculativeJIT::recordSetLocal): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillInteger): + (JSC::DFG::SpeculativeJIT::fillDouble): + (JSC::DFG::SpeculativeJIT::fillJSValue): + (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal): + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::fillInteger): + (JSC::DFG::SpeculativeJIT::fillDouble): + (JSC::DFG::SpeculativeJIT::fillJSValue): + (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal): + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGValueRecoveryOverride.h: Added. + (DFG): + (ValueRecoveryOverride): + (JSC::DFG::ValueRecoveryOverride::ValueRecoveryOverride): + * dfg/DFGValueSource.cpp: Added. + (DFG): + (JSC::DFG::ValueSource::dump): + * dfg/DFGValueSource.h: Added. + (DFG): + (JSC::DFG::dataFormatToValueSourceKind): + (JSC::DFG::valueSourceKindToDataFormat): + (JSC::DFG::isInRegisterFile): + (ValueSource): + (JSC::DFG::ValueSource::ValueSource): + (JSC::DFG::ValueSource::forPrediction): + (JSC::DFG::ValueSource::forDataFormat): + (JSC::DFG::ValueSource::isSet): + (JSC::DFG::ValueSource::kind): + (JSC::DFG::ValueSource::isInRegisterFile): + (JSC::DFG::ValueSource::dataFormat): + (JSC::DFG::ValueSource::valueRecovery): + (JSC::DFG::ValueSource::nodeIndex): + (JSC::DFG::ValueSource::nodeIndexFromKind): + (JSC::DFG::ValueSource::kindFromNodeIndex): + * dfg/DFGVariableEvent.cpp: Added. + (DFG): + (JSC::DFG::VariableEvent::dump): + (JSC::DFG::VariableEvent::dumpFillInfo): + (JSC::DFG::VariableEvent::dumpSpillInfo): + * dfg/DFGVariableEvent.h: Added. + (DFG): + (VariableEvent): + (JSC::DFG::VariableEvent::VariableEvent): + (JSC::DFG::VariableEvent::reset): + (JSC::DFG::VariableEvent::fillGPR): + (JSC::DFG::VariableEvent::fillPair): + (JSC::DFG::VariableEvent::fillFPR): + (JSC::DFG::VariableEvent::spill): + (JSC::DFG::VariableEvent::death): + (JSC::DFG::VariableEvent::setLocal): + (JSC::DFG::VariableEvent::movHint): + (JSC::DFG::VariableEvent::kind): + (JSC::DFG::VariableEvent::nodeIndex): + (JSC::DFG::VariableEvent::dataFormat): + (JSC::DFG::VariableEvent::gpr): + (JSC::DFG::VariableEvent::tagGPR): + (JSC::DFG::VariableEvent::payloadGPR): + (JSC::DFG::VariableEvent::fpr): + (JSC::DFG::VariableEvent::virtualRegister): + (JSC::DFG::VariableEvent::operand): + (JSC::DFG::VariableEvent::variableRepresentation): + * dfg/DFGVariableEventStream.cpp: Added. + (DFG): + (JSC::DFG::VariableEventStream::logEvent): + (MinifiedGenerationInfo): + (JSC::DFG::MinifiedGenerationInfo::MinifiedGenerationInfo): + (JSC::DFG::MinifiedGenerationInfo::update): + (JSC::DFG::VariableEventStream::reconstruct): + * dfg/DFGVariableEventStream.h: Added. + (DFG): + (VariableEventStream): + (JSC::DFG::VariableEventStream::appendAndLog): + * dfg/DFGVirtualRegisterAllocationPhase.cpp: + (JSC::DFG::performVirtualRegisterAllocation): + +2012-07-02 Filip Pizlo + DFG::ArgumentsSimplificationPhase should assert that the PhantomArguments nodes it creates are not shouldGenerate() https://bugs.webkit.org/show_bug.cgi?id=90407 diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am index 606c1d3..26dc79e 100644 --- a/Source/JavaScriptCore/GNUmakefile.list.am +++ b/Source/JavaScriptCore/GNUmakefile.list.am @@ -188,6 +188,9 @@ javascriptcore_sources += \ Source/JavaScriptCore/dfg/DFGInsertionSet.h \ Source/JavaScriptCore/dfg/DFGJITCompiler.cpp \ Source/JavaScriptCore/dfg/DFGJITCompiler.h \ + Source/JavaScriptCore/dfg/DFGMinifiedGraph.h \ + Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp \ + Source/JavaScriptCore/dfg/DFGMinifiedNode.h \ Source/JavaScriptCore/dfg/DFGNode.h \ Source/JavaScriptCore/dfg/DFGNodeFlags.cpp \ Source/JavaScriptCore/dfg/DFGNodeFlags.h \ @@ -222,6 +225,13 @@ javascriptcore_sources += \ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h \ Source/JavaScriptCore/dfg/DFGThunks.cpp \ Source/JavaScriptCore/dfg/DFGThunks.h \ + Source/JavaScriptCore/dfg/DFGValueRecoveryOverride.h \ + Source/JavaScriptCore/dfg/DFGValueSource.cpp \ + Source/JavaScriptCore/dfg/DFGValueSource.h \ + Source/JavaScriptCore/dfg/DFGVariableEvent.cpp \ + Source/JavaScriptCore/dfg/DFGVariableEvent.h \ + Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp \ + Source/JavaScriptCore/dfg/DFGVariableEventStream.h \ Source/JavaScriptCore/dfg/DFGValidate.cpp \ Source/JavaScriptCore/dfg/DFGValidate.h \ Source/JavaScriptCore/dfg/DFGVariableAccessData.h \ diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index f2edf8e..7b3454c 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -92,6 +92,16 @@ 0F2BDC16151C5D4F00CD8910 /* DFGFixupPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC13151C5D4A00CD8910 /* DFGFixupPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2BDC21151E803B00CD8910 /* DFGInsertionSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC1F151E803800CD8910 /* DFGInsertionSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2BDC2C151FDE9100CD8910 /* Operands.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC2B151FDE8B00CD8910 /* Operands.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2BDC451522801B00CD8910 /* DFGMinifiedGraph.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC3D1522801700CD8910 /* DFGMinifiedGraph.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2BDC461522802000CD8910 /* DFGMinifiedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC3E1522801700CD8910 /* DFGMinifiedNode.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2BDC471522802500CD8910 /* DFGValueRecoveryOverride.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC3F1522801700CD8910 /* DFGValueRecoveryOverride.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2BDC481522802900CD8910 /* DFGValueSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC401522801700CD8910 /* DFGValueSource.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2BDC491522809600CD8910 /* DFGVariableEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC411522801700CD8910 /* DFGVariableEvent.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2BDC4A1522809A00CD8910 /* DFGVariableEventStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC421522801700CD8910 /* DFGVariableEventStream.cpp */; }; + 0F2BDC4B1522809D00CD8910 /* DFGVariableEventStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC431522801700CD8910 /* DFGVariableEventStream.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2BDC4D1522818600CD8910 /* DFGMinifiedNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC4C1522818300CD8910 /* DFGMinifiedNode.cpp */; }; + 0F2BDC4F15228BF300CD8910 /* DFGValueSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */; }; + 0F2BDC5115228FFD00CD8910 /* DFGVariableEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */; }; 0F2C556F14738F3100121E4F /* DFGCodeBlocks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2C557014738F3500121E4F /* DFGCodeBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */; }; 0F3B3A1A153E68F2003ED0FF /* DFGConstantFoldingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3B3A17153E68EF003ED0FF /* DFGConstantFoldingPhase.cpp */; }; @@ -814,6 +824,16 @@ 0F2BDC13151C5D4A00CD8910 /* DFGFixupPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGFixupPhase.h; path = dfg/DFGFixupPhase.h; sourceTree = ""; }; 0F2BDC1F151E803800CD8910 /* DFGInsertionSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGInsertionSet.h; path = dfg/DFGInsertionSet.h; sourceTree = ""; }; 0F2BDC2B151FDE8B00CD8910 /* Operands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Operands.h; sourceTree = ""; }; + 0F2BDC3D1522801700CD8910 /* DFGMinifiedGraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGMinifiedGraph.h; path = dfg/DFGMinifiedGraph.h; sourceTree = ""; }; + 0F2BDC3E1522801700CD8910 /* DFGMinifiedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGMinifiedNode.h; path = dfg/DFGMinifiedNode.h; sourceTree = ""; }; + 0F2BDC3F1522801700CD8910 /* DFGValueRecoveryOverride.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGValueRecoveryOverride.h; path = dfg/DFGValueRecoveryOverride.h; sourceTree = ""; }; + 0F2BDC401522801700CD8910 /* DFGValueSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGValueSource.h; path = dfg/DFGValueSource.h; sourceTree = ""; }; + 0F2BDC411522801700CD8910 /* DFGVariableEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableEvent.h; path = dfg/DFGVariableEvent.h; sourceTree = ""; }; + 0F2BDC421522801700CD8910 /* DFGVariableEventStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableEventStream.cpp; path = dfg/DFGVariableEventStream.cpp; sourceTree = ""; }; + 0F2BDC431522801700CD8910 /* DFGVariableEventStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableEventStream.h; path = dfg/DFGVariableEventStream.h; sourceTree = ""; }; + 0F2BDC4C1522818300CD8910 /* DFGMinifiedNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGMinifiedNode.cpp; path = dfg/DFGMinifiedNode.cpp; sourceTree = ""; }; + 0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGValueSource.cpp; path = dfg/DFGValueSource.cpp; sourceTree = ""; }; + 0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableEvent.cpp; path = dfg/DFGVariableEvent.cpp; sourceTree = ""; }; 0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DFGCodeBlocks.cpp; sourceTree = ""; }; 0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFGCodeBlocks.h; sourceTree = ""; }; 0F3B3A17153E68EF003ED0FF /* DFGConstantFoldingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGConstantFoldingPhase.cpp; path = dfg/DFGConstantFoldingPhase.cpp; sourceTree = ""; }; @@ -2227,6 +2247,9 @@ 0F2BDC1F151E803800CD8910 /* DFGInsertionSet.h */, 86EC9DBB1328DF82002B2AD7 /* DFGJITCompiler.cpp */, 86EC9DBC1328DF82002B2AD7 /* DFGJITCompiler.h */, + 0F2BDC3D1522801700CD8910 /* DFGMinifiedGraph.h */, + 0F2BDC4C1522818300CD8910 /* DFGMinifiedNode.cpp */, + 0F2BDC3E1522801700CD8910 /* DFGMinifiedNode.h */, 86ECA3E9132DEF1C002B2AD7 /* DFGNode.h */, 0FA581B7150E952A00B9A2D9 /* DFGNodeFlags.cpp */, 0FA581B8150E952A00B9A2D9 /* DFGNodeFlags.h */, @@ -2261,9 +2284,16 @@ 86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */, 0FC0979F146B28C700CF2442 /* DFGThunks.cpp */, 0FC097A0146B28C700CF2442 /* DFGThunks.h */, + 0F2BDC3F1522801700CD8910 /* DFGValueRecoveryOverride.h */, + 0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */, + 0F2BDC401522801700CD8910 /* DFGValueSource.h */, 0F3B3A2915474FF4003ED0FF /* DFGValidate.cpp */, 0F3B3A2A15474FF4003ED0FF /* DFGValidate.h */, 0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */, + 0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */, + 0F2BDC411522801700CD8910 /* DFGVariableEvent.h */, + 0F2BDC421522801700CD8910 /* DFGVariableEventStream.cpp */, + 0F2BDC431522801700CD8910 /* DFGVariableEventStream.h */, 0FFFC95314EF909500C72532 /* DFGVirtualRegisterAllocationPhase.cpp */, 0FFFC95414EF909500C72532 /* DFGVirtualRegisterAllocationPhase.h */, ); @@ -2747,6 +2777,12 @@ 0F2BDC16151C5D4F00CD8910 /* DFGFixupPhase.h in Headers */, 0F2BDC21151E803B00CD8910 /* DFGInsertionSet.h in Headers */, 0F2BDC2C151FDE9100CD8910 /* Operands.h in Headers */, + 0F2BDC451522801B00CD8910 /* DFGMinifiedGraph.h in Headers */, + 0F2BDC461522802000CD8910 /* DFGMinifiedNode.h in Headers */, + 0F2BDC471522802500CD8910 /* DFGValueRecoveryOverride.h in Headers */, + 0F2BDC481522802900CD8910 /* DFGValueSource.h in Headers */, + 0F2BDC491522809600CD8910 /* DFGVariableEvent.h in Headers */, + 0F2BDC4B1522809D00CD8910 /* DFGVariableEventStream.h in Headers */, 8612E4CD152389EC00C836BE /* MatchResult.h in Headers */, 0F1E3A461534CBAF000F9456 /* DFGArgumentPosition.h in Headers */, 0F3B3A1B153E68F4003ED0FF /* DFGConstantFoldingPhase.h in Headers */, @@ -3336,6 +3372,10 @@ 8642C510151C06A90046D4EF /* RegExpCachedResult.cpp in Sources */, 8642C512151C083D0046D4EF /* RegExpMatchesArray.cpp in Sources */, 863C6D9C1521111A00585E4E /* YarrCanonicalizeUCS2.cpp in Sources */, + 0F2BDC4A1522809A00CD8910 /* DFGVariableEventStream.cpp in Sources */, + 0F2BDC4D1522818600CD8910 /* DFGMinifiedNode.cpp in Sources */, + 0F2BDC4F15228BF300CD8910 /* DFGValueSource.cpp in Sources */, + 0F2BDC5115228FFD00CD8910 /* DFGVariableEvent.cpp in Sources */, 14816E1B154CC56C00B8054C /* BlockAllocator.cpp in Sources */, 86EBF2FF1560F06A008E9222 /* NameConstructor.cpp in Sources */, 86EBF3011560F06A008E9222 /* NameInstance.cpp in Sources */, diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri index ee86bf5..81a1a79 100644 --- a/Source/JavaScriptCore/Target.pri +++ b/Source/JavaScriptCore/Target.pri @@ -109,6 +109,7 @@ SOURCES += \ dfg/DFGFixupPhase.cpp \ dfg/DFGGraph.cpp \ dfg/DFGJITCompiler.cpp \ + dfg/DFGMinifiedNode.cpp \ dfg/DFGNodeFlags.cpp \ dfg/DFGOperations.cpp \ dfg/DFGOSREntry.cpp \ @@ -124,6 +125,9 @@ SOURCES += \ dfg/DFGSpeculativeJIT32_64.cpp \ dfg/DFGSpeculativeJIT64.cpp \ dfg/DFGThunks.cpp \ + dfg/DFGValueSource.cpp \ + dfg/DFGVariableEvent.cpp \ + dfg/DFGVariableEventStream.cpp \ dfg/DFGValidate.cpp \ dfg/DFGVirtualRegisterAllocationPhase.cpp \ interpreter/AbstractPC.cpp \ diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index d59341c..295e965 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -2478,6 +2478,8 @@ void CodeBlock::shrinkToFit(ShrinkMode shrinkMode) m_dfgData->speculationRecovery.shrinkToFit(); m_dfgData->weakReferences.shrinkToFit(); m_dfgData->transitions.shrinkToFit(); + m_dfgData->minifiedDFG.prepareAndShrink(); + m_dfgData->variableEventStream.shrinkToFit(); } #endif } @@ -2845,7 +2847,7 @@ void CodeBlock::dumpValueProfiles() dataLog(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter); } } -#endif +#endif // ENABLE(VERBOSE_VALUE_PROFILE) size_t CodeBlock::predictedMachineCodeSize() { diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index 45999b4..e867344 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -40,8 +40,10 @@ #include "DFGCodeBlocks.h" #include "DFGCommon.h" #include "DFGExitProfile.h" +#include "DFGMinifiedGraph.h" #include "DFGOSREntry.h" #include "DFGOSRExit.h" +#include "DFGVariableEventStream.h" #include "EvalCodeCache.h" #include "ExecutionCounter.h" #include "ExpressionRangeInfo.h" @@ -382,6 +384,18 @@ namespace JSC { m_dfgData->transitions.append( WeakReferenceTransition(*globalData(), ownerExecutable(), codeOrigin, from, to)); } + + DFG::MinifiedGraph& minifiedDFG() + { + createDFGDataIfNecessary(); + return m_dfgData->minifiedDFG; + } + + DFG::VariableEventStream& variableEventStream() + { + createDFGDataIfNecessary(); + return m_dfgData->variableEventStream; + } #endif unsigned bytecodeOffset(Instruction* returnAddress) @@ -1280,6 +1294,8 @@ namespace JSC { SegmentedVector watchpoints; Vector transitions; Vector > weakReferences; + DFG::VariableEventStream variableEventStream; + DFG::MinifiedGraph minifiedDFG; bool mayBeExecuting; bool isJettisoned; bool livenessHasBeenProved; // Initialized and used on every GC. diff --git a/Source/JavaScriptCore/bytecode/DataFormat.h b/Source/JavaScriptCore/bytecode/DataFormat.h index 4f01548..51c8afb 100644 --- a/Source/JavaScriptCore/bytecode/DataFormat.h +++ b/Source/JavaScriptCore/bytecode/DataFormat.h @@ -47,7 +47,14 @@ enum DataFormat { DataFormatJSInteger = DataFormatJS | DataFormatInteger, DataFormatJSDouble = DataFormatJS | DataFormatDouble, DataFormatJSCell = DataFormatJS | DataFormatCell, - DataFormatJSBoolean = DataFormatJS | DataFormatBoolean + DataFormatJSBoolean = DataFormatJS | DataFormatBoolean, + + // Marker deliminating ordinary data formats and OSR-only data formats. + DataFormatOSRMarker = 32, + + // Special data formats used only for OSR. + DataFormatDead = 33, // Implies jsUndefined(). + DataFormatArguments = 34 // Implies that the arguments object must be reified. }; inline const char* dataFormatToString(DataFormat dataFormat) diff --git a/Source/JavaScriptCore/bytecode/Operands.h b/Source/JavaScriptCore/bytecode/Operands.h index 05a24d0..8ea3e5b 100644 --- a/Source/JavaScriptCore/bytecode/Operands.h +++ b/Source/JavaScriptCore/bytecode/Operands.h @@ -115,6 +115,13 @@ public: const T& operand(int operand) const { return const_cast(const_cast(this)->operand(operand)); } + bool hasOperand(int operand) const + { + if (operandIsArgument(operand)) + return true; + return static_cast(operand) < numberOfLocals(); + } + void setOperand(int operand, const T& value) { if (operandIsArgument(operand)) { @@ -126,6 +133,39 @@ public: setLocal(operand, value); } + size_t size() const { return numberOfArguments() + numberOfLocals(); } + const T& at(size_t index) const + { + if (index < numberOfArguments()) + return m_arguments[index]; + return m_locals[index - numberOfArguments()]; + } + T& at(size_t index) + { + if (index < numberOfArguments()) + return m_arguments[index]; + return m_locals[index - numberOfArguments()]; + } + const T& operator[](size_t index) const { return at(index); } + T& operator[](size_t index) { return at(index); } + + bool isArgument(size_t index) const { return index < numberOfArguments(); } + bool isVariable(size_t index) const { return !isArgument(index); } + int argumentForIndex(size_t index) const + { + return index; + } + int variableForIndex(size_t index) const + { + return index - m_arguments.size(); + } + int operandForIndex(size_t index) const + { + if (index < numberOfArguments()) + return argumentToOperand(index); + return index - numberOfArguments(); + } + void setOperandFirstTime(int operand, const T& value) { if (operandIsArgument(operand)) { @@ -165,6 +205,16 @@ void dumpOperands(Operands& operands, FILE* out) } } +template +void dumpOperands(const Operands& operands, FILE* out) +{ + // Use const-cast because: + // 1) I don't feel like writing this code twice, and + // 2) Some dump() methods may not be const, and I don't really care if that's + // the case. + dumpOperands(*const_cast*>(&operands), out); +} + } // namespace JSC #endif // Operands_h diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp index 82c081b..9208cde 100644 --- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp @@ -834,6 +834,7 @@ private: bool performArgumentsSimplification(Graph& graph) { + SamplingRegion samplingRegion("DFG Arguments Simplification Phase"); return runPhase(graph); } diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index cdb0b63..0a241fb 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -3341,6 +3341,7 @@ bool ByteCodeParser::parse() bool parse(ExecState* exec, Graph& graph) { + SamplingRegion samplingRegion("DFG Parsing"); #if DFG_DEBUG_LOCAL_DISBALE UNUSED_PARAM(exec); UNUSED_PARAM(graph); diff --git a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp index c604244..c523496 100644 --- a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp @@ -132,6 +132,7 @@ private: bool performCFA(Graph& graph) { + SamplingRegion samplingRegion("DFG CFA Phase"); return runPhase(graph); } diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp index 07d2f50..c234e6e 100644 --- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp @@ -745,6 +745,7 @@ private: bool performCFGSimplification(Graph& graph) { + SamplingRegion samplingRegion("DFG CFG Simplification Phase"); return runPhase(graph); } diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp index be0012f..108cf19 100644 --- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp @@ -1172,6 +1172,7 @@ private: bool performCSE(Graph& graph, OptimizationFixpointState fixpointState) { + SamplingRegion samplingRegion("DFG CSE Phase"); return runPhase(graph, fixpointState); } diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp index 9e6720c..d3029b3 100644 --- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp @@ -159,6 +159,7 @@ public: bool performConstantFolding(Graph& graph) { + SamplingRegion samplingRegion("DFG Constant Folding Phase"); return runPhase(graph); } diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp index f6e3c0a..2e7389f 100644 --- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp @@ -402,6 +402,7 @@ private: bool performFixup(Graph& graph) { + SamplingRegion samplingRegion("DFG Fixup Phase"); return runPhase(graph); } diff --git a/Source/JavaScriptCore/dfg/DFGGenerationInfo.h b/Source/JavaScriptCore/dfg/DFGGenerationInfo.h index 125a5a4..905c5c5 100644 --- a/Source/JavaScriptCore/dfg/DFGGenerationInfo.h +++ b/Source/JavaScriptCore/dfg/DFGGenerationInfo.h @@ -29,8 +29,10 @@ #if ENABLE(DFG_JIT) +#include "DFGJITCompiler.h" +#include "DFGVariableEvent.h" +#include "DFGVariableEventStream.h" #include "DataFormat.h" -#include namespace JSC { namespace DFG { @@ -51,6 +53,7 @@ public: , m_registerFormat(DataFormatNone) , m_spillFormat(DataFormatNone) , m_canFill(false) + , m_bornForOSR(false) { } @@ -61,6 +64,7 @@ public: m_registerFormat = DataFormatNone; m_spillFormat = DataFormatNone; m_canFill = true; + m_bornForOSR = false; ASSERT(m_useCount); } void initInteger(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr) @@ -71,6 +75,7 @@ public: m_spillFormat = DataFormatNone; m_canFill = false; u.gpr = gpr; + m_bornForOSR = false; ASSERT(m_useCount); } #if USE(JSVALUE64) @@ -84,6 +89,7 @@ public: m_spillFormat = DataFormatNone; m_canFill = false; u.gpr = gpr; + m_bornForOSR = false; ASSERT(m_useCount); } #elif USE(JSVALUE32_64) @@ -98,6 +104,7 @@ public: m_canFill = false; u.v.tagGPR = tagGPR; u.v.payloadGPR = payloadGPR; + m_bornForOSR = false; ASSERT(m_useCount); } #endif @@ -109,6 +116,7 @@ public: m_spillFormat = DataFormatNone; m_canFill = false; u.gpr = gpr; + m_bornForOSR = false; ASSERT(m_useCount); } void initBoolean(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr) @@ -119,6 +127,7 @@ public: m_spillFormat = DataFormatNone; m_canFill = false; u.gpr = gpr; + m_bornForOSR = false; ASSERT(m_useCount); } void initDouble(NodeIndex nodeIndex, uint32_t useCount, FPRReg fpr) @@ -130,6 +139,7 @@ public: m_spillFormat = DataFormatNone; m_canFill = false; u.fpr = fpr; + m_bornForOSR = false; ASSERT(m_useCount); } void initStorage(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr) @@ -140,19 +150,44 @@ public: m_spillFormat = DataFormatNone; m_canFill = false; u.gpr = gpr; + m_bornForOSR = false; ASSERT(m_useCount); } // Get the index of the node that produced this value. NodeIndex nodeIndex() { return m_nodeIndex; } + + void noticeOSRBirth(VariableEventStream& stream, NodeIndex nodeIndex, VirtualRegister virtualRegister) + { + if (m_nodeIndex != nodeIndex) + return; + if (!alive()) + return; + if (m_bornForOSR) + return; + + m_bornForOSR = true; + + if (m_registerFormat != DataFormatNone) + appendFill(BirthToFill, stream); + else if (m_spillFormat != DataFormatNone) + appendSpill(BirthToSpill, stream, virtualRegister); + } // Mark the value as having been used (decrement the useCount). // Returns true if this was the last use of the value, and any // associated machine registers may be freed. - bool use() + bool use(VariableEventStream& stream) { ASSERT(m_useCount); - return !--m_useCount; + bool result = !--m_useCount; + + if (result && m_bornForOSR) { + ASSERT(m_nodeIndex != NoNode); + stream.appendAndLog(VariableEvent::death(m_nodeIndex)); + } + + return result; } // Used to check the operands of operations to see if they are on @@ -225,7 +260,7 @@ public: } // Called when a VirtualRegister is being spilled to the RegisterFile for the first time. - void spill(DataFormat spillFormat) + void spill(VariableEventStream& stream, VirtualRegister virtualRegister, DataFormat spillFormat) { // We shouldn't be spill values that don't need spilling. ASSERT(!m_canFill); @@ -236,15 +271,21 @@ public: m_registerFormat = DataFormatNone; m_spillFormat = spillFormat; m_canFill = true; + + if (m_bornForOSR) + appendSpill(Spill, stream, virtualRegister); } // Called on values that don't need spilling (constants and values that have // already been spilled), to mark them as no longer being in machine registers. - void setSpilled() + void setSpilled(VariableEventStream& stream, VirtualRegister virtualRegister) { // Should only be called on values that don't need spilling, and are currently in registers. ASSERT(m_canFill && m_registerFormat != DataFormatNone); m_registerFormat = DataFormatNone; + + if (m_bornForOSR) + appendSpill(Spill, stream, virtualRegister); } void killSpilled() @@ -256,46 +297,67 @@ public: // Record that this value is filled into machine registers, // tracking which registers, and what format the value has. #if USE(JSVALUE64) - void fillJSValue(GPRReg gpr, DataFormat format = DataFormatJS) + void fillJSValue(VariableEventStream& stream, GPRReg gpr, DataFormat format = DataFormatJS) { ASSERT(format & DataFormatJS); m_registerFormat = format; u.gpr = gpr; + + if (m_bornForOSR) + appendFill(Fill, stream); } #elif USE(JSVALUE32_64) - void fillJSValue(GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS) + void fillJSValue(VariableEventStream& stream, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS) { ASSERT(format & DataFormatJS); m_registerFormat = format; u.v.tagGPR = tagGPR; // FIXME: for JSValues with known type (boolean, integer, cell etc.) no tagGPR is needed? u.v.payloadGPR = payloadGPR; + + if (m_bornForOSR) + appendFill(Fill, stream); } - void fillCell(GPRReg gpr) + void fillCell(VariableEventStream& stream, GPRReg gpr) { m_registerFormat = DataFormatCell; u.gpr = gpr; + + if (m_bornForOSR) + appendFill(Fill, stream); } #endif - void fillInteger(GPRReg gpr) + void fillInteger(VariableEventStream& stream, GPRReg gpr) { m_registerFormat = DataFormatInteger; u.gpr = gpr; + + if (m_bornForOSR) + appendFill(Fill, stream); } - void fillBoolean(GPRReg gpr) + void fillBoolean(VariableEventStream& stream, GPRReg gpr) { m_registerFormat = DataFormatBoolean; u.gpr = gpr; + + if (m_bornForOSR) + appendFill(Fill, stream); } - void fillDouble(FPRReg fpr) + void fillDouble(VariableEventStream& stream, FPRReg fpr) { ASSERT(fpr != InvalidFPRReg); m_registerFormat = DataFormatDouble; u.fpr = fpr; + + if (m_bornForOSR) + appendFill(Fill, stream); } - void fillStorage(GPRReg gpr) + void fillStorage(VariableEventStream& stream, GPRReg gpr) { m_registerFormat = DataFormatStorage; u.gpr = gpr; + + if (m_bornForOSR) + appendFill(Fill, stream); } bool alive() @@ -304,12 +366,33 @@ public: } private: + void appendFill(VariableEventKind kind, VariableEventStream& stream) + { + if (m_registerFormat == DataFormatDouble) { + stream.appendAndLog(VariableEvent::fillFPR(kind, m_nodeIndex, u.fpr)); + return; + } +#if USE(JSVALUE32_64) + if (m_registerFormat & DataFormatJS) { + stream.appendAndLog(VariableEvent::fillPair(kind, m_nodeIndex, u.v.tagGPR, u.v.payloadGPR)); + return; + } +#endif + stream.appendAndLog(VariableEvent::fillGPR(kind, m_nodeIndex, u.gpr, m_registerFormat)); + } + + void appendSpill(VariableEventKind kind, VariableEventStream& stream, VirtualRegister virtualRegister) + { + stream.appendAndLog(VariableEvent::spill(kind, m_nodeIndex, virtualRegister, m_spillFormat)); + } + // The index of the node whose result is stored in this virtual register. NodeIndex m_nodeIndex; uint32_t m_useCount; DataFormat m_registerFormat; DataFormat m_spillFormat; bool m_canFill; + bool m_bornForOSR; union { GPRReg gpr; FPRReg fpr; diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp index 95c3cba..9cd60c5 100644 --- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp +++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp @@ -203,11 +203,14 @@ void JITCompiler::link(LinkBuffer& linkBuffer) codeBlock()->watchpoint(exit.m_watchpointIndex).correctLabels(linkBuffer); } + codeBlock()->minifiedDFG().setOriginalGraphSize(m_graph.size()); codeBlock()->shrinkToFit(CodeBlock::LateShrink); } bool JITCompiler::compile(JITCode& entry) { + SamplingRegion samplingRegion("DFG Backend"); + setStartOfCode(); compileEntry(); SpeculativeJIT speculative(*this); @@ -241,6 +244,8 @@ bool JITCompiler::compile(JITCode& entry) bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck) { + SamplingRegion samplingRegion("DFG Backend"); + setStartOfCode(); compileEntry(); diff --git a/Source/JavaScriptCore/dfg/DFGMinifiedGraph.h b/Source/JavaScriptCore/dfg/DFGMinifiedGraph.h new file mode 100644 index 0000000..b38ef07 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGMinifiedGraph.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 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 DFGMinifiedGraph_h +#define DFGMinifiedGraph_h + +#include + +#if ENABLE(DFG_JIT) + +#include "DFGMinifiedNode.h" +#include +#include +#include + +namespace JSC { namespace DFG { + +class MinifiedGraph { +public: + MinifiedGraph() { } + + MinifiedNode* at(NodeIndex nodeIndex) + { + if (!m_list.size()) + return 0; + MinifiedNode* entry = + binarySearch( + m_list.begin(), m_list.size(), nodeIndex, WTF::KeyMustNotBePresentInArray); + if (entry->index() != nodeIndex) + return 0; + return entry; + } + + void append(const MinifiedNode& node) + { + m_list.append(node); + } + + void prepareAndShrink() + { + std::sort(m_list.begin(), m_list.end(), MinifiedNode::compareByNodeIndex); + m_list.shrinkToFit(); + } + + void setOriginalGraphSize(size_t size) { m_size = size; } + + size_t originalGraphSize() const { return m_size; } + +private: + Vector m_list; + size_t m_size; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGMinifiedGraph_h + diff --git a/Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp b/Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp new file mode 100644 index 0000000..6362344 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 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 "DFGMinifiedNode.h" + +#if ENABLE(DFG_JIT) + +#include "DFGNode.h" + +namespace JSC { namespace DFG { + +MinifiedNode MinifiedNode::fromNode(NodeIndex nodeIndex, Node& node) +{ + ASSERT(belongsInMinifiedGraph(node.op())); + MinifiedNode result; + result.m_index = nodeIndex; + result.m_op = node.op(); + if (hasChild(node.op())) + result.m_childOrInfo = node.child1().index(); + else if (hasConstantNumber(node.op())) + result.m_childOrInfo = node.constantNumber(); + else if (hasWeakConstant(node.op())) + result.m_childOrInfo = bitwise_cast(node.weakConstant()); + else { + ASSERT(node.op() == PhantomArguments); + result.m_childOrInfo = 0; + } + return result; +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/Source/JavaScriptCore/dfg/DFGMinifiedNode.h b/Source/JavaScriptCore/dfg/DFGMinifiedNode.h new file mode 100644 index 0000000..b80cbd7 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGMinifiedNode.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2012 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 DFGMinifiedNode_h +#define DFGMinifiedNode_h + +#include + +#if ENABLE(DFG_JIT) + +#include "DFGCommon.h" +#include "DFGNodeType.h" + +namespace JSC { namespace DFG { + +struct Node; + +inline bool belongsInMinifiedGraph(NodeType type) +{ + switch (type) { + case JSConstant: + case WeakJSConstant: + case ValueToInt32: + case Int32ToDouble: + case UInt32ToNumber: + case DoubleAsInt32: + case PhantomArguments: + return true; + default: + return false; + } +} + +class MinifiedNode { +public: + MinifiedNode() { } + + static MinifiedNode fromNode(NodeIndex, Node&); + + NodeIndex index() const { return m_index; } + NodeType op() const { return m_op; } + + bool hasChild1() const { return hasChild(m_op); } + + NodeIndex child1() const + { + ASSERT(hasChild(m_op)); + return m_childOrInfo; + } + + bool hasConstant() const { return hasConstantNumber() || hasWeakConstant(); } + + bool hasConstantNumber() const { return hasConstantNumber(m_op); } + + unsigned constantNumber() const + { + ASSERT(hasConstantNumber(m_op)); + return m_childOrInfo; + } + + bool hasWeakConstant() const { return hasWeakConstant(m_op); } + + JSCell* weakConstant() const + { + ASSERT(hasWeakConstant(m_op)); + return bitwise_cast(m_childOrInfo); + } + + static NodeIndex getIndex(MinifiedNode* node) { return node->index(); } + static bool compareByNodeIndex(const MinifiedNode& a, const MinifiedNode& b) + { + return a.m_index < b.m_index; + } + +private: + static bool hasChild(NodeType type) + { + switch (type) { + case ValueToInt32: + case Int32ToDouble: + case UInt32ToNumber: + case DoubleAsInt32: + return true; + default: + return false; + } + } + static bool hasConstantNumber(NodeType type) + { + return type == JSConstant; + } + static bool hasWeakConstant(NodeType type) + { + return type == WeakJSConstant; + } + + NodeIndex m_index; + NodeType m_op; + uintptr_t m_childOrInfo; // Nodes in the minified graph have only one child each. +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGMinifiedNode_h + diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index b1c5d28..ae07d55 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -40,6 +40,7 @@ #include "JSValue.h" #include "Operands.h" #include "SpeculatedType.h" +#include "StructureSet.h" #include "ValueProfile.h" namespace JSC { namespace DFG { @@ -707,7 +708,7 @@ struct Node { ASSERT(m_virtualRegister != InvalidVirtualRegister); return m_virtualRegister; } - + void setVirtualRegister(VirtualRegister virtualRegister) { ASSERT(hasResult()); diff --git a/Source/JavaScriptCore/dfg/DFGOSRExit.cpp b/Source/JavaScriptCore/dfg/DFGOSRExit.cpp index 115c823..e542f2f 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExit.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExit.cpp @@ -33,17 +33,7 @@ namespace JSC { namespace DFG { -static unsigned computeNumVariablesForCodeOrigin( - CodeBlock* codeBlock, const CodeOrigin& codeOrigin) -{ - if (!codeOrigin.inlineCallFrame) - return codeBlock->m_numCalleeRegisters; - return - codeOrigin.inlineCallFrame->stackOffset + - baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame)->m_numCalleeRegisters; -} - -OSRExit::OSRExit(ExitKind kind, JSValueSource jsValueSource, MethodOfGettingAValueProfile valueProfile, MacroAssembler::Jump check, SpeculativeJIT* jit, unsigned recoveryIndex) +OSRExit::OSRExit(ExitKind kind, JSValueSource jsValueSource, MethodOfGettingAValueProfile valueProfile, MacroAssembler::Jump check, SpeculativeJIT* jit, unsigned streamIndex, unsigned recoveryIndex) : m_jsValueSource(jsValueSource) , m_valueProfile(valueProfile) , m_check(check) @@ -54,24 +44,10 @@ OSRExit::OSRExit(ExitKind kind, JSValueSource jsValueSource, MethodOfGettingAVal , m_watchpointIndex(std::numeric_limits::max()) , m_kind(kind) , m_count(0) - , m_arguments(jit->m_arguments.size()) - , m_variables(computeNumVariablesForCodeOrigin(jit->m_jit.graph().m_profiledBlock, jit->m_codeOriginForOSR)) + , m_streamIndex(streamIndex) , m_lastSetOperand(jit->m_lastSetOperand) { ASSERT(m_codeOrigin.isSet()); - for (unsigned argument = 0; argument < m_arguments.size(); ++argument) - m_arguments[argument] = jit->computeValueRecoveryFor(jit->m_arguments[argument]); - for (unsigned variable = 0; variable < m_variables.size(); ++variable) - m_variables[variable] = jit->computeValueRecoveryFor(jit->m_variables[variable]); -} - -void OSRExit::dump(FILE* out) const -{ - for (unsigned argument = 0; argument < m_arguments.size(); ++argument) - m_arguments[argument].dump(out); - fprintf(out, " : "); - for (unsigned variable = 0; variable < m_variables.size(); ++variable) - m_variables[variable].dump(out); } bool OSRExit::considerAddingAsFrequentExitSiteSlow(CodeBlock* dfgCodeBlock, CodeBlock* profiledCodeBlock) diff --git a/Source/JavaScriptCore/dfg/DFGOSRExit.h b/Source/JavaScriptCore/dfg/DFGOSRExit.h index 683f260..cd2434c 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExit.h +++ b/Source/JavaScriptCore/dfg/DFGOSRExit.h @@ -35,6 +35,7 @@ #include "DFGCorrectableJumpPoint.h" #include "DFGExitProfile.h" #include "DFGGPRInfo.h" +#include "DFGValueRecoveryOverride.h" #include "MacroAssembler.h" #include "MethodOfGettingAValueProfile.h" #include "Operands.h" @@ -83,7 +84,7 @@ private: // This structure describes how to exit the speculative path by // going into baseline code. struct OSRExit { - OSRExit(ExitKind, JSValueSource, MethodOfGettingAValueProfile, MacroAssembler::Jump, SpeculativeJIT*, unsigned recoveryIndex = 0); + OSRExit(ExitKind, JSValueSource, MethodOfGettingAValueProfile, MacroAssembler::Jump, SpeculativeJIT*, unsigned streamIndex, unsigned recoveryIndex = 0); MacroAssemblerCodeRef m_code; @@ -101,38 +102,6 @@ struct OSRExit { ExitKind m_kind; uint32_t m_count; - // Convenient way of iterating over ValueRecoveries while being - // generic over argument versus variable. - int numberOfRecoveries() const { return m_arguments.size() + m_variables.size(); } - const ValueRecovery& valueRecovery(int index) const - { - if (index < (int)m_arguments.size()) - return m_arguments[index]; - return m_variables[index - m_arguments.size()]; - } - ValueRecovery& valueRecoveryForOperand(int operand) - { - if (operandIsArgument(operand)) - return m_arguments[operandToArgument(operand)]; - return m_variables[operand]; - } - bool isArgument(int index) const { return index < (int)m_arguments.size(); } - bool isVariable(int index) const { return !isArgument(index); } - int argumentForIndex(int index) const - { - return index; - } - int variableForIndex(int index) const - { - return index - m_arguments.size(); - } - int operandForIndex(int index) const - { - if (index < (int)m_arguments.size()) - return operandToArgument(index); - return index - m_arguments.size(); - } - bool considerAddingAsFrequentExitSite(CodeBlock* dfgCodeBlock, CodeBlock* profiledCodeBlock) { if (!m_count || !exitKindIsCountable(m_kind)) @@ -140,11 +109,10 @@ struct OSRExit { return considerAddingAsFrequentExitSiteSlow(dfgCodeBlock, profiledCodeBlock); } - void dump(FILE* out) const; - - Vector m_arguments; - Vector m_variables; + unsigned m_streamIndex; int m_lastSetOperand; + + RefPtr m_valueRecoveryOverride; private: bool considerAddingAsFrequentExitSiteSlow(CodeBlock* dfgCodeBlock, CodeBlock* profiledCodeBlock); diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp index 378ee52..2ce1c88 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp @@ -39,6 +39,8 @@ extern "C" { void compileOSRExit(ExecState* exec) { + SamplingRegion samplingRegion("DFG OSR Exit Compilation"); + CodeBlock* codeBlock = exec->codeBlock(); ASSERT(codeBlock); @@ -64,12 +66,22 @@ void compileOSRExit(ExecState* exec) ->jitCompile(exec); } + // Compute the value recoveries. + Operands operands; + codeBlock->variableEventStream().reconstruct(codeBlock, exit.m_codeOrigin, codeBlock->minifiedDFG(), exit.m_streamIndex, operands); + + // There may be an override, for forward speculations. + if (!!exit.m_valueRecoveryOverride) { + operands.setOperand( + exit.m_valueRecoveryOverride->operand, exit.m_valueRecoveryOverride->recovery); + } + SpeculationRecovery* recovery = 0; if (exit.m_recoveryIndex) recovery = &codeBlock->speculationRecovery(exit.m_recoveryIndex - 1); #if DFG_ENABLE(DEBUG_VERBOSE) - dataLog("Generating OSR exit #%u (bc#%u, @%u, %s) for code block %p.\n", exitIndex, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, exitKindToString(exit.m_kind), codeBlock); + dataLog("Generating OSR exit #%u (seq#%u, bc#%u, @%u, %s) for code block %p.\n", exitIndex, exit.m_streamIndex, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, exitKindToString(exit.m_kind), codeBlock); #endif { @@ -77,7 +89,7 @@ void compileOSRExit(ExecState* exec) OSRExitCompiler exitCompiler(jit); jit.jitAssertHasValidCallFrame(); - exitCompiler.compileExit(exit, recovery); + exitCompiler.compileExit(exit, operands, recovery); LinkBuffer patchBuffer(*globalData, &jit, codeBlock); exit.m_code = FINALIZE_CODE_IF( diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h index ae29a92..a2be5b8 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h @@ -48,7 +48,7 @@ public: { } - void compileExit(const OSRExit&, SpeculationRecovery*); + void compileExit(const OSRExit&, const Operands&, SpeculationRecovery*); private: #if !ASSERT_DISABLED diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp index 09912b3..6bc136d 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp @@ -29,10 +29,11 @@ #if ENABLE(DFG_JIT) && USE(JSVALUE32_64) #include "DFGOperations.h" +#include namespace JSC { namespace DFG { -void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* recovery) +void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands& operands, SpeculationRecovery* recovery) { // 1) Pro-forma stuff. #if DFG_ENABLE(DEBUG_VERBOSE) @@ -44,7 +45,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco dataLog(" -> %p ", codeOrigin.inlineCallFrame->executable.get()); } dataLog(") at JIT offset 0x%x ", m_jit.debugOffset()); - exit.dump(WTF::dataFile()); + dumpOperands(operands, WTF::dataFile()); #endif #if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE) SpeculationFailureDebugInfo* debugInfo = new SpeculationFailureDebugInfo; @@ -113,7 +114,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // GPRInfo::numberOfRegisters of them. Also see if there are any constants, // any undefined slots, any FPR slots, and any unboxed ints. - Vector poisonedVirtualRegisters(exit.m_variables.size()); + Vector poisonedVirtualRegisters(operands.numberOfLocals()); for (unsigned i = 0; i < poisonedVirtualRegisters.size(); ++i) poisonedVirtualRegisters[i] = false; @@ -133,8 +134,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco bool haveUndefined = false; bool haveArguments = false; - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; switch (recovery.technique()) { case DisplacedInRegisterFile: case Int32DisplacedInRegisterFile: @@ -150,8 +151,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // to ensure this happens efficiently. Note that we expect this case // to be rare, so the handling of it is optimized for the cases in // which it does not happen. - if (recovery.virtualRegister() < (int)exit.m_variables.size()) { - switch (exit.m_variables[recovery.virtualRegister()].technique()) { + if (recovery.virtualRegister() < (int)operands.numberOfLocals()) { + switch (operands.local(recovery.virtualRegister()).technique()) { case InGPR: case UnboxedInt32InGPR: case UnboxedBooleanInGPR: @@ -214,19 +215,19 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // 5) Perform all reboxing of integers and cells, except for those in registers. if (haveUnboxedInt32InRegisterFile || haveUnboxedCellInRegisterFile || haveUnboxedBooleanInRegisterFile) { - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; switch (recovery.technique()) { case AlreadyInRegisterFileAsUnboxedInt32: - m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::Int32Tag), AssemblyHelpers::tagFor(static_cast(exit.operandForIndex(index)))); + m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::Int32Tag), AssemblyHelpers::tagFor(static_cast(operands.operandForIndex(index)))); break; case AlreadyInRegisterFileAsUnboxedCell: - m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor(static_cast(exit.operandForIndex(index)))); + m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor(static_cast(operands.operandForIndex(index)))); break; case AlreadyInRegisterFileAsUnboxedBoolean: - m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::BooleanTag), AssemblyHelpers::tagFor(static_cast(exit.operandForIndex(index)))); + m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::BooleanTag), AssemblyHelpers::tagFor(static_cast(operands.operandForIndex(index)))); break; default: @@ -239,19 +240,19 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // Note that GPRs do not have a fast change (like haveFPRs) because we expect that // most OSR failure points will have at least one GPR that needs to be dumped. - initializePoisoned(exit.m_variables.size()); + initializePoisoned(operands.numberOfLocals()); unsigned currentPoisonIndex = 0; - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); - int operand = exit.operandForIndex(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; + int operand = operands.operandForIndex(index); switch (recovery.technique()) { case InGPR: case UnboxedInt32InGPR: case UnboxedBooleanInGPR: - if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) { + if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) { m_jit.store32(recovery.gpr(), reinterpret_cast(scratchDataBuffer + currentPoisonIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); - m_poisonScratchIndices[exit.variableForIndex(index)] = currentPoisonIndex; + m_poisonScratchIndices[operands.variableForIndex(index)] = currentPoisonIndex; currentPoisonIndex++; } else { uint32_t tag = JSValue::EmptyValueTag; @@ -266,10 +267,10 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco } break; case InPair: - if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) { + if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) { m_jit.store32(recovery.tagGPR(), reinterpret_cast(scratchDataBuffer + currentPoisonIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); m_jit.store32(recovery.payloadGPR(), reinterpret_cast(scratchDataBuffer + currentPoisonIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); - m_poisonScratchIndices[exit.variableForIndex(index)] = currentPoisonIndex; + m_poisonScratchIndices[operands.variableForIndex(index)] = currentPoisonIndex; currentPoisonIndex++; } else { m_jit.store32(recovery.tagGPR(), AssemblyHelpers::tagFor((VirtualRegister)operand)); @@ -291,7 +292,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco m_jit.convertInt32ToDouble(recovery.gpr(), FPRInfo::fpRegT0); m_jit.addDouble(AssemblyHelpers::AbsoluteAddress(&AssemblyHelpers::twoToThe32), FPRInfo::fpRegT0); - if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) { + if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) { m_jit.move(AssemblyHelpers::TrustedImmPtr(scratchDataBuffer + currentPoisonIndex), addressGPR); m_jit.storeDouble(FPRInfo::fpRegT0, addressGPR); } else @@ -301,7 +302,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco positive.link(&m_jit); - if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) { + if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) { m_jit.store32(recovery.gpr(), reinterpret_cast(scratchDataBuffer + currentPoisonIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::Int32Tag), reinterpret_cast(scratchDataBuffer + currentPoisonIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); } else { @@ -315,8 +316,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco m_jit.loadDouble(addressGPR, FPRInfo::fpRegT0); m_jit.loadPtr(myScratch, addressGPR); - if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) { - m_poisonScratchIndices[exit.variableForIndex(index)] = currentPoisonIndex; + if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) { + m_poisonScratchIndices[operands.variableForIndex(index)] = currentPoisonIndex; currentPoisonIndex++; } break; @@ -329,16 +330,16 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // 7) Dump all doubles into the register file, or to the scratch storage if the // destination virtual register is poisoned. if (haveFPRs) { - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; if (recovery.technique() != InFPR) continue; - if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) { + if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) { m_jit.storeDouble(recovery.fpr(), scratchDataBuffer + currentPoisonIndex); - m_poisonScratchIndices[exit.variableForIndex(index)] = currentPoisonIndex; + m_poisonScratchIndices[operands.variableForIndex(index)] = currentPoisonIndex; currentPoisonIndex++; } else - m_jit.storeDouble(recovery.fpr(), AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.storeDouble(recovery.fpr(), AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index))); } } @@ -356,8 +357,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // that is far from guaranteed. unsigned displacementIndex = 0; - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; switch (recovery.technique()) { case DisplacedInRegisterFile: m_jit.load32(AssemblyHelpers::payloadFor(recovery.virtualRegister()), GPRInfo::toRegister(displacementIndex++)); @@ -381,15 +382,15 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco } displacementIndex = 0; - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; switch (recovery.technique()) { case DisplacedInRegisterFile: case Int32DisplacedInRegisterFile: case CellDisplacedInRegisterFile: case BooleanDisplacedInRegisterFile: - m_jit.store32(GPRInfo::toRegister(displacementIndex++), AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index))); - m_jit.store32(GPRInfo::toRegister(displacementIndex++), AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.store32(GPRInfo::toRegister(displacementIndex++), AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index))); + m_jit.store32(GPRInfo::toRegister(displacementIndex++), AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index))); break; default: break; @@ -414,8 +415,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // to their new (old JIT) locations. unsigned scratchIndex = numberOfPoisonedVirtualRegisters; - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; switch (recovery.technique()) { case DisplacedInRegisterFile: m_jit.load32(AssemblyHelpers::payloadFor(recovery.virtualRegister()), GPRInfo::regT0); @@ -436,30 +437,30 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco } scratchIndex = numberOfPoisonedVirtualRegisters; - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; switch (recovery.technique()) { case DisplacedInRegisterFile: m_jit.load32(reinterpret_cast(scratchDataBuffer + scratchIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload), GPRInfo::regT0); m_jit.load32(reinterpret_cast(scratchDataBuffer + scratchIndex) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag), GPRInfo::regT1); - m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index))); - m_jit.store32(GPRInfo::regT1, AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index))); + m_jit.store32(GPRInfo::regT1, AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index))); scratchIndex++; break; case Int32DisplacedInRegisterFile: m_jit.load32(reinterpret_cast(scratchDataBuffer + scratchIndex++) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload), GPRInfo::regT0); - m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::Int32Tag), AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index))); - m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::Int32Tag), AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index))); + m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index))); break; case CellDisplacedInRegisterFile: m_jit.load32(reinterpret_cast(scratchDataBuffer + scratchIndex++) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload), GPRInfo::regT0); - m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index))); - m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index))); + m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index))); break; case BooleanDisplacedInRegisterFile: m_jit.load32(reinterpret_cast(scratchDataBuffer + scratchIndex++) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload), GPRInfo::regT0); - m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::BooleanTag), AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index))); - m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::BooleanTag), AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index))); + m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index))); break; default: break; @@ -473,11 +474,11 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // 9) Dump all poisoned virtual registers. if (numberOfPoisonedVirtualRegisters) { - for (int virtualRegister = 0; virtualRegister < (int)exit.m_variables.size(); ++virtualRegister) { + for (int virtualRegister = 0; virtualRegister < (int)operands.numberOfLocals(); ++virtualRegister) { if (!poisonedVirtualRegisters[virtualRegister]) continue; - const ValueRecovery& recovery = exit.m_variables[virtualRegister]; + const ValueRecovery& recovery = operands.local(virtualRegister); switch (recovery.technique()) { case InGPR: case UnboxedInt32InGPR: @@ -519,16 +520,16 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco m_jit.move(AssemblyHelpers::TrustedImm32(jsUndefined().tag()), GPRInfo::regT1); } - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; if (recovery.technique() != Constant) continue; if (recovery.constant().isUndefined()) { - m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index))); - m_jit.store32(GPRInfo::regT1, AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index))); + m_jit.store32(GPRInfo::regT1, AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index))); } else { - m_jit.store32(AssemblyHelpers::TrustedImm32(recovery.constant().payload()), AssemblyHelpers::payloadFor((VirtualRegister)exit.operandForIndex(index))); - m_jit.store32(AssemblyHelpers::TrustedImm32(recovery.constant().tag()), AssemblyHelpers::tagFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.store32(AssemblyHelpers::TrustedImm32(recovery.constant().payload()), AssemblyHelpers::payloadFor((VirtualRegister)operands.operandForIndex(index))); + m_jit.store32(AssemblyHelpers::TrustedImm32(recovery.constant().tag()), AssemblyHelpers::tagFor((VirtualRegister)operands.operandForIndex(index))); } } } @@ -611,11 +612,11 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // registers. if (haveArguments) { - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; if (recovery.technique() != ArgumentsThatWereNotCreated) continue; - int operand = exit.operandForIndex(index); + int operand = operands.operandForIndex(index); // Find the right inline call frame. InlineCallFrame* inlineCallFrame = 0; for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame; diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp index 33ba69a..2f38ba7 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp @@ -29,10 +29,11 @@ #if ENABLE(DFG_JIT) && USE(JSVALUE64) #include "DFGOperations.h" +#include namespace JSC { namespace DFG { -void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* recovery) +void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands& operands, SpeculationRecovery* recovery) { // 1) Pro-forma stuff. #if DFG_ENABLE(DEBUG_VERBOSE) @@ -44,7 +45,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco dataLog(" -> %p ", codeOrigin.inlineCallFrame->executable.get()); } dataLog(") "); - exit.dump(WTF::dataFile()); + dumpOperands(operands, WTF::dataFile()); #endif #if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE) SpeculationFailureDebugInfo* debugInfo = new SpeculationFailureDebugInfo; @@ -110,7 +111,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // GPRInfo::numberOfRegisters of them. Also see if there are any constants, // any undefined slots, any FPR slots, and any unboxed ints. - Vector poisonedVirtualRegisters(exit.m_variables.size()); + Vector poisonedVirtualRegisters(operands.numberOfLocals()); for (unsigned i = 0; i < poisonedVirtualRegisters.size(); ++i) poisonedVirtualRegisters[i] = false; @@ -129,8 +130,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco bool haveUInt32s = false; bool haveArguments = false; - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; switch (recovery.technique()) { case Int32DisplacedInRegisterFile: case DoubleDisplacedInRegisterFile: @@ -145,8 +146,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // to ensure this happens efficiently. Note that we expect this case // to be rare, so the handling of it is optimized for the cases in // which it does not happen. - if (recovery.virtualRegister() < (int)exit.m_variables.size()) { - switch (exit.m_variables[recovery.virtualRegister()].technique()) { + if (recovery.virtualRegister() < (int)operands.numberOfLocals()) { + switch (operands.local(recovery.virtualRegister()).technique()) { case InGPR: case UnboxedInt32InGPR: case UInt32InGPR: @@ -224,8 +225,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // 5) Perform all reboxing of integers. if (haveUnboxedInt32s || haveUInt32s) { - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; switch (recovery.technique()) { case UnboxedInt32InGPR: if (recovery.gpr() != alreadyBoxed) @@ -233,7 +234,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco break; case AlreadyInRegisterFileAsUnboxedInt32: - m_jit.store32(AssemblyHelpers::TrustedImm32(static_cast(TagTypeNumber >> 32)), AssemblyHelpers::tagFor(static_cast(exit.operandForIndex(index)))); + m_jit.store32(AssemblyHelpers::TrustedImm32(static_cast(TagTypeNumber >> 32)), AssemblyHelpers::tagFor(static_cast(operands.operandForIndex(index)))); break; case UInt32InGPR: { @@ -284,19 +285,19 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // Note that GPRs do not have a fast change (like haveFPRs) because we expect that // most OSR failure points will have at least one GPR that needs to be dumped. - initializePoisoned(exit.m_variables.size()); + initializePoisoned(operands.numberOfLocals()); unsigned currentPoisonIndex = 0; - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); - int operand = exit.operandForIndex(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; + int operand = operands.operandForIndex(index); switch (recovery.technique()) { case InGPR: case UnboxedInt32InGPR: case UInt32InGPR: - if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) { + if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) { m_jit.storePtr(recovery.gpr(), scratchDataBuffer + currentPoisonIndex); - m_poisonScratchIndices[exit.variableForIndex(index)] = currentPoisonIndex; + m_poisonScratchIndices[operands.variableForIndex(index)] = currentPoisonIndex; currentPoisonIndex++; } else m_jit.storePtr(recovery.gpr(), AssemblyHelpers::addressFor((VirtualRegister)operand)); @@ -311,8 +312,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco if (haveFPRs) { // 7) Box all doubles (relies on there being more GPRs than FPRs) - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; if (recovery.technique() != InFPR) continue; FPRReg fpr = recovery.fpr(); @@ -323,17 +324,17 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // 8) Dump all doubles into the register file, or to the scratch storage if // the destination virtual register is poisoned. - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; if (recovery.technique() != InFPR) continue; GPRReg gpr = GPRInfo::toRegister(FPRInfo::toIndex(recovery.fpr())); - if (exit.isVariable(index) && poisonedVirtualRegisters[exit.variableForIndex(index)]) { + if (operands.isVariable(index) && poisonedVirtualRegisters[operands.variableForIndex(index)]) { m_jit.storePtr(gpr, scratchDataBuffer + currentPoisonIndex); - m_poisonScratchIndices[exit.variableForIndex(index)] = currentPoisonIndex; + m_poisonScratchIndices[operands.variableForIndex(index)] = currentPoisonIndex; currentPoisonIndex++; } else - m_jit.storePtr(gpr, AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.storePtr(gpr, AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index))); } } @@ -341,13 +342,13 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // 9) Box all unboxed doubles in the register file. if (haveUnboxedDoubles) { - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; if (recovery.technique() != AlreadyInRegisterFileAsUnboxedDouble) continue; - m_jit.loadDouble(AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index)), FPRInfo::fpRegT0); + m_jit.loadDouble(AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index)), FPRInfo::fpRegT0); m_jit.boxDouble(FPRInfo::fpRegT0, GPRInfo::regT0); - m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index))); } } @@ -363,8 +364,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // that is far from guaranteed. unsigned displacementIndex = 0; - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; switch (recovery.technique()) { case DisplacedInRegisterFile: m_jit.loadPtr(AssemblyHelpers::addressFor(recovery.virtualRegister()), GPRInfo::toRegister(displacementIndex++)); @@ -390,13 +391,13 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco } displacementIndex = 0; - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; switch (recovery.technique()) { case DisplacedInRegisterFile: case Int32DisplacedInRegisterFile: case DoubleDisplacedInRegisterFile: - m_jit.storePtr(GPRInfo::toRegister(displacementIndex++), AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.storePtr(GPRInfo::toRegister(displacementIndex++), AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index))); break; default: @@ -422,8 +423,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // to their new (old JIT) locations. unsigned scratchIndex = numberOfPoisonedVirtualRegisters; - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; switch (recovery.technique()) { case DisplacedInRegisterFile: @@ -451,14 +452,14 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco } scratchIndex = numberOfPoisonedVirtualRegisters; - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; switch (recovery.technique()) { case DisplacedInRegisterFile: case Int32DisplacedInRegisterFile: case DoubleDisplacedInRegisterFile: m_jit.loadPtr(scratchDataBuffer + scratchIndex++, GPRInfo::regT0); - m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index))); break; default: @@ -473,11 +474,11 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // 11) Dump all poisoned virtual registers. if (numberOfPoisonedVirtualRegisters) { - for (int virtualRegister = 0; virtualRegister < (int)exit.m_variables.size(); ++virtualRegister) { + for (int virtualRegister = 0; virtualRegister < (int)operands.numberOfLocals(); ++virtualRegister) { if (!poisonedVirtualRegisters[virtualRegister]) continue; - const ValueRecovery& recovery = exit.m_variables[virtualRegister]; + const ValueRecovery& recovery = operands.local(virtualRegister); switch (recovery.technique()) { case InGPR: case UnboxedInt32InGPR: @@ -500,14 +501,14 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco if (haveUndefined) m_jit.move(AssemblyHelpers::TrustedImmPtr(JSValue::encode(jsUndefined())), GPRInfo::regT0); - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; if (recovery.technique() != Constant) continue; if (recovery.constant().isUndefined()) - m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index))); else - m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(JSValue::encode(recovery.constant())), AssemblyHelpers::addressFor((VirtualRegister)exit.operandForIndex(index))); + m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(JSValue::encode(recovery.constant())), AssemblyHelpers::addressFor((VirtualRegister)operands.operandForIndex(index))); } } @@ -586,11 +587,11 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco // registers. if (haveArguments) { - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; if (recovery.technique() != ArgumentsThatWereNotCreated) continue; - int operand = exit.operandForIndex(index); + int operand = operands.operandForIndex(index); // Find the right inline call frame. InlineCallFrame* inlineCallFrame = 0; for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame; diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index 0bd81ec..320eb6c 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -908,6 +908,7 @@ private: bool performPredictionPropagation(Graph& graph) { + SamplingRegion samplingRegion("DFG Prediction Propagation Phase"); return runPhase(graph); } diff --git a/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp b/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp index 5453469..32e4ef1 100644 --- a/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGRedundantPhiEliminationPhase.cpp @@ -169,6 +169,7 @@ private: bool performRedundantPhiElimination(Graph& graph) { + SamplingRegion samplingRegion("DFG Redundant Phi Elimination Phase"); return runPhase(graph); } diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index 2250128..c6ec621 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -45,6 +45,8 @@ SpeculativeJIT::SpeculativeJIT(JITCompiler& jit) , m_variables(jit.graph().m_localVars) , m_lastSetOperand(std::numeric_limits::max()) , m_state(m_jit.graph()) + , m_stream(&jit.codeBlock()->variableEventStream()) + , m_minifiedGraph(&jit.codeBlock()->minifiedDFG()) , m_isCheckingArgumentTypes(false) { } @@ -99,7 +101,7 @@ GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex) GPRReg gpr = allocate(); m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); - info.fillStorage(gpr); + info.fillStorage(*m_stream, gpr); return gpr; } @@ -780,39 +782,6 @@ FPRTemporary::FPRTemporary(SpeculativeJIT* jit, JSValueOperand& op1) } #endif -void ValueSource::dump(FILE* out) const -{ - switch (kind()) { - case SourceNotSet: - fprintf(out, "NotSet"); - break; - case SourceIsDead: - fprintf(out, "IsDead"); - break; - case ValueInRegisterFile: - fprintf(out, "InRegFile"); - break; - case Int32InRegisterFile: - fprintf(out, "Int32"); - break; - case CellInRegisterFile: - fprintf(out, "Cell"); - break; - case BooleanInRegisterFile: - fprintf(out, "Bool"); - break; - case DoubleInRegisterFile: - fprintf(out, "Double"); - break; - case ArgumentsSource: - fprintf(out, "Arguments"); - break; - case HaveNode: - fprintf(out, "Node(%d)", m_nodeIndex); - break; - } -} - void SpeculativeJIT::compilePeepHoleDoubleBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition condition) { Node& branchNode = at(branchNodeIndex); @@ -953,12 +922,30 @@ bool SpeculativeJIT::compilePeepHoleBranch(Node& node, MacroAssembler::Relationa return false; } +void SpeculativeJIT::noticeOSRBirth(NodeIndex nodeIndex, Node& node) +{ + if (!node.hasVirtualRegister()) + return; + + VirtualRegister virtualRegister = node.virtualRegister(); + GenerationInfo& info = m_generationInfo[virtualRegister]; + + info.noticeOSRBirth(*m_stream, nodeIndex, virtualRegister); +} + void SpeculativeJIT::compileMovHint(Node& node) { ASSERT(node.op() == SetLocal); - setNodeIndexForOperand(node.child1().index(), node.local()); m_lastSetOperand = node.local(); + + Node& child = at(node.child1()); + noticeOSRBirth(node.child1().index(), child); + + if (child.op() == UInt32ToNumber) + noticeOSRBirth(child.child1().index(), at(child.child1())); + + m_stream->appendAndLog(VariableEvent::movHint(node.child1().index(), node.local())); } void SpeculativeJIT::compile(BasicBlock& block) @@ -983,11 +970,20 @@ void SpeculativeJIT::compile(BasicBlock& block) m_jit.breakpoint(); #endif +#if DFG_ENABLE(DEBUG_VERBOSE) + dataLog("Setting up state for block #%u: ", m_block); +#endif + + m_stream->appendAndLog(VariableEvent::reset()); + m_jit.jitAssertHasValidCallFrame(); ASSERT(m_arguments.size() == block.variablesAtHead.numberOfArguments()); - for (size_t i = 0; i < m_arguments.size(); ++i) - m_arguments[i] = ValueSource(ValueInRegisterFile); + for (size_t i = 0; i < m_arguments.size(); ++i) { + ValueSource valueSource = ValueSource(ValueInRegisterFile); + m_arguments[i] = valueSource; + m_stream->appendAndLog(VariableEvent::setLocal(argumentToOperand(i), valueSource.dataFormat())); + } m_state.reset(); m_state.beginBasicBlock(&block); @@ -995,18 +991,21 @@ void SpeculativeJIT::compile(BasicBlock& block) ASSERT(m_variables.size() == block.variablesAtHead.numberOfLocals()); for (size_t i = 0; i < m_variables.size(); ++i) { NodeIndex nodeIndex = block.variablesAtHead.local(i); + ValueSource valueSource; if (nodeIndex == NoNode) - m_variables[i] = ValueSource(SourceIsDead); + valueSource = ValueSource(SourceIsDead); else if (at(nodeIndex).variableAccessData()->isArgumentsAlias()) - m_variables[i] = ValueSource(ArgumentsSource); + valueSource = ValueSource(ArgumentsSource); else if (at(nodeIndex).variableAccessData()->isCaptured()) - m_variables[i] = ValueSource(ValueInRegisterFile); + valueSource = ValueSource(ValueInRegisterFile); else if (!at(nodeIndex).refCount()) - m_variables[i] = ValueSource(SourceIsDead); + valueSource = ValueSource(SourceIsDead); else if (at(nodeIndex).variableAccessData()->shouldUseDoubleFormat()) - m_variables[i] = ValueSource(DoubleInRegisterFile); + valueSource = ValueSource(DoubleInRegisterFile); else - m_variables[i] = ValueSource::forSpeculation(at(nodeIndex).variableAccessData()->argumentAwarePrediction()); + valueSource = ValueSource::forSpeculation(at(nodeIndex).variableAccessData()->argumentAwarePrediction()); + m_variables[i] = valueSource; + m_stream->appendAndLog(VariableEvent::setLocal(i, valueSource.dataFormat())); } m_lastSetOperand = std::numeric_limits::max(); @@ -1019,6 +1018,10 @@ void SpeculativeJIT::compile(BasicBlock& block) verificationSucceeded.link(&m_jit); } +#if DFG_ENABLE(DEBUG_VERBOSE) + dataLog("\n"); +#endif + for (m_indexInBlock = 0; m_indexInBlock < block.size(); ++m_indexInBlock) { m_compileIndex = block[m_indexInBlock]; m_jit.setForNode(m_compileIndex); @@ -1029,6 +1032,15 @@ void SpeculativeJIT::compile(BasicBlock& block) dataLog("SpeculativeJIT skipping Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex, m_jit.debugOffset()); #endif switch (node.op()) { + case JSConstant: + m_minifiedGraph->append(MinifiedNode::fromNode(m_compileIndex, node)); + break; + + case WeakJSConstant: + m_jit.addWeakReference(node.weakConstant()); + m_minifiedGraph->append(MinifiedNode::fromNode(m_compileIndex, node)); + break; + case SetLocal: compileMovHint(node); break; @@ -1073,11 +1085,9 @@ void SpeculativeJIT::compile(BasicBlock& block) break; } - case WeakJSConstant: - m_jit.addWeakReference(node.weakConstant()); - break; - default: + if (belongsInMinifiedGraph(node.op())) + m_minifiedGraph->append(MinifiedNode::fromNode(m_compileIndex, node)); break; } } else { @@ -1100,6 +1110,11 @@ void SpeculativeJIT::compile(BasicBlock& block) return; } + if (belongsInMinifiedGraph(node.op())) { + m_minifiedGraph->append(MinifiedNode::fromNode(m_compileIndex, node)); + noticeOSRBirth(m_compileIndex, node); + } + #if DFG_ENABLE(DEBUG_VERBOSE) if (node.hasResult()) { GenerationInfo& info = m_generationInfo[node.virtualRegister()]; @@ -1120,16 +1135,6 @@ void SpeculativeJIT::compile(BasicBlock& block) #endif } -#if DFG_ENABLE(VERBOSE_VALUE_RECOVERIES) - for (size_t i = 0; i < m_arguments.size(); ++i) - computeValueRecoveryFor(argumentToOperand(i)).dump(stderr); - - dataLog(" : "); - - for (int operand = 0; operand < (int)m_variables.size(); ++operand) - computeValueRecoveryFor(operand).dump(stderr); -#endif - #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("\n"); #endif @@ -1366,156 +1371,14 @@ void SpeculativeJIT::linkOSREntries(LinkBuffer& linkBuffer) ValueRecovery SpeculativeJIT::computeValueRecoveryFor(const ValueSource& valueSource) { - switch (valueSource.kind()) { - case SourceIsDead: - return ValueRecovery::constant(jsUndefined()); - - case ValueInRegisterFile: - return ValueRecovery::alreadyInRegisterFile(); - - case Int32InRegisterFile: - return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32(); - - case CellInRegisterFile: - return ValueRecovery::alreadyInRegisterFileAsUnboxedCell(); - - case BooleanInRegisterFile: - return ValueRecovery::alreadyInRegisterFileAsUnboxedBoolean(); - - case DoubleInRegisterFile: - return ValueRecovery::alreadyInRegisterFileAsUnboxedDouble(); - - case ArgumentsSource: - return ValueRecovery::argumentsThatWereNotCreated(); - - case HaveNode: { - Node* nodePtr = &at(valueSource.nodeIndex()); - - if (nodePtr->isPhantomArguments()) - return ValueRecovery::argumentsThatWereNotCreated(); + if (valueSource.isInRegisterFile()) + return valueSource.valueRecovery(); - if (nodePtr->hasConstant()) - return ValueRecovery::constant(valueOfJSConstant(valueSource.nodeIndex())); - - GenerationInfo* infoPtr; - if (nodePtr->shouldGenerate()) - infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; - else - infoPtr = 0; - if (!infoPtr || !infoPtr->alive() || infoPtr->nodeIndex() != valueSource.nodeIndex()) { - // Try to see if there is an alternate node that would contain the value we want. - // There are four possibilities: - // - // Int32ToDouble: We can use this in place of the original node, but - // we'd rather not; so we use it only if it is the only remaining - // live version. - // - // ValueToInt32: If the only remaining live version of the value is - // ValueToInt32, then we can use it. - // - // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber - // then the only remaining uses are ones that want a properly formed number - // rather than a UInt32 intermediate. - // - // The reverse of the above: This node could be a UInt32ToNumber, but its - // alternative is still alive. This means that the only remaining uses of - // the number would be fine with a UInt32 intermediate. - // - // DoubleAsInt32: Same as UInt32ToNumber. - // - - bool found = false; - - if (nodePtr->op() == UInt32ToNumber || nodePtr->op() == DoubleAsInt32) { - NodeIndex nodeIndex = nodePtr->child1().index(); - nodePtr = &at(nodeIndex); - if (nodePtr->shouldGenerate()) { - infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; - if (infoPtr->alive() && infoPtr->nodeIndex() == nodeIndex) - found = true; - } - } - - if (!found) { - NodeIndex int32ToDoubleIndex = NoNode; - NodeIndex valueToInt32Index = NoNode; - NodeIndex uint32ToNumberIndex = NoNode; - NodeIndex doubleAsInt32Index = NoNode; - - for (unsigned virtualRegister = 0; virtualRegister < m_generationInfo.size(); ++virtualRegister) { - GenerationInfo& info = m_generationInfo[virtualRegister]; - if (!info.alive()) - continue; - if (info.nodeIndex() == NoNode) - continue; - Node& node = at(info.nodeIndex()); - if (node.child1Unchecked() != valueSource.nodeIndex()) - continue; - switch (node.op()) { - case Int32ToDouble: - int32ToDoubleIndex = info.nodeIndex(); - break; - case ValueToInt32: - valueToInt32Index = info.nodeIndex(); - break; - case UInt32ToNumber: - uint32ToNumberIndex = info.nodeIndex(); - break; - case DoubleAsInt32: - doubleAsInt32Index = info.nodeIndex(); - default: - break; - } - } - - NodeIndex nodeIndexToUse; - if (doubleAsInt32Index != NoNode) - nodeIndexToUse = doubleAsInt32Index; - else if (int32ToDoubleIndex != NoNode) - nodeIndexToUse = int32ToDoubleIndex; - else if (valueToInt32Index != NoNode) - nodeIndexToUse = valueToInt32Index; - else if (uint32ToNumberIndex != NoNode) - nodeIndexToUse = uint32ToNumberIndex; - else - nodeIndexToUse = NoNode; - - if (nodeIndexToUse != NoNode) { - nodePtr = &at(nodeIndexToUse); - if (nodePtr->shouldGenerate()) { - infoPtr = &m_generationInfo[nodePtr->virtualRegister()]; - ASSERT(infoPtr->alive() && infoPtr->nodeIndex() == nodeIndexToUse); - found = true; - } - } - } - - if (!found) - return ValueRecovery::constant(jsUndefined()); - } - - ASSERT(infoPtr->alive()); - - if (infoPtr->registerFormat() != DataFormatNone) { - if (infoPtr->registerFormat() == DataFormatDouble) - return ValueRecovery::inFPR(infoPtr->fpr()); -#if USE(JSVALUE32_64) - if (infoPtr->registerFormat() & DataFormatJS) - return ValueRecovery::inPair(infoPtr->tagGPR(), infoPtr->payloadGPR()); -#endif - return ValueRecovery::inGPR(infoPtr->gpr(), infoPtr->registerFormat()); - } - if (infoPtr->spillFormat() != DataFormatNone) - return ValueRecovery::displacedInRegisterFile(static_cast(nodePtr->virtualRegister()), infoPtr->spillFormat()); + ASSERT(valueSource.kind() == HaveNode); + if (isConstant(valueSource.nodeIndex())) + return ValueRecovery::constant(valueOfJSConstant(valueSource.nodeIndex())); - ASSERT_NOT_REACHED(); - return ValueRecovery(); - } - - default: - ASSERT_NOT_REACHED(); - return ValueRecovery(); - } + return ValueRecovery(); } void SpeculativeJIT::compileGetCharCodeAt(Node& node) @@ -1654,10 +1517,11 @@ GeneratedOperandType SpeculativeJIT::checkGeneratedTypeForToInt32(NodeIndex node case DataFormatJSDouble: case DataFormatDouble: return GeneratedOperandDouble; + + default: + ASSERT_NOT_REACHED(); + return GeneratedOperandTypeUnknown; } - - ASSERT_NOT_REACHED(); - return GeneratedOperandTypeUnknown; } void SpeculativeJIT::compileValueToInt32(Node& node) diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 67a22b7..84b3061 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,6 +26,8 @@ #ifndef DFGSpeculativeJIT_h #define DFGSpeculativeJIT_h +#include + #if ENABLE(DFG_JIT) #include "DFGAbstractState.h" @@ -34,6 +36,7 @@ #include "DFGOSRExit.h" #include "DFGOperations.h" #include "DFGSilentRegisterSavePlan.h" +#include "DFGValueSource.h" #include "MarkedAllocator.h" #include "ValueRecovery.h" @@ -48,87 +51,6 @@ class SpeculateDoubleOperand; class SpeculateCellOperand; class SpeculateBooleanOperand; - -enum ValueSourceKind { - SourceNotSet, - ValueInRegisterFile, - Int32InRegisterFile, - CellInRegisterFile, - BooleanInRegisterFile, - DoubleInRegisterFile, - ArgumentsSource, - SourceIsDead, - HaveNode -}; - -class ValueSource { -public: - ValueSource() - : m_nodeIndex(nodeIndexFromKind(SourceNotSet)) - { - } - - explicit ValueSource(ValueSourceKind valueSourceKind) - : m_nodeIndex(nodeIndexFromKind(valueSourceKind)) - { - ASSERT(kind() != SourceNotSet); - ASSERT(kind() != HaveNode); - } - - explicit ValueSource(NodeIndex nodeIndex) - : m_nodeIndex(nodeIndex) - { - ASSERT(kind() == HaveNode); - } - - static ValueSource forSpeculation(SpeculatedType prediction) - { - if (isInt32Speculation(prediction)) - return ValueSource(Int32InRegisterFile); - if (isArraySpeculation(prediction)) - return ValueSource(CellInRegisterFile); - if (isBooleanSpeculation(prediction)) - return ValueSource(BooleanInRegisterFile); - return ValueSource(ValueInRegisterFile); - } - - bool isSet() const - { - return kindFromNodeIndex(m_nodeIndex) != SourceNotSet; - } - - ValueSourceKind kind() const - { - return kindFromNodeIndex(m_nodeIndex); - } - - NodeIndex nodeIndex() const - { - ASSERT(kind() == HaveNode); - return m_nodeIndex; - } - - void dump(FILE* out) const; - -private: - static NodeIndex nodeIndexFromKind(ValueSourceKind kind) - { - ASSERT(kind >= SourceNotSet && kind < HaveNode); - return NoNode - kind; - } - - static ValueSourceKind kindFromNodeIndex(NodeIndex nodeIndex) - { - unsigned kind = static_cast(NoNode - nodeIndex); - if (kind >= static_cast(HaveNode)) - return HaveNode; - return static_cast(kind); - } - - NodeIndex m_nodeIndex; -}; - - enum GeneratedOperandType { GeneratedOperandTypeUnknown, GeneratedOperandInteger, GeneratedOperandDouble, GeneratedOperandJSValue}; // === SpeculativeJIT === @@ -326,7 +248,7 @@ public: // use() returns true when the value becomes dead, and any // associated resources may be freed. - if (!info.use()) + if (!info.use(*m_stream)) return; // Release the associated machine registers. @@ -376,6 +298,7 @@ public: void runSlowPathGenerators(); void compile(Node&); + void noticeOSRBirth(NodeIndex, Node&); void compileMovHint(Node&); void compile(BasicBlock&); @@ -777,7 +700,7 @@ public: // Check the GenerationInfo to see if this value need writing // to the RegisterFile - if not, mark it as spilled & return. if (!info.needsSpill()) { - info.setSpilled(); + info.setSpilled(*m_stream, spillMe); return; } @@ -787,20 +710,20 @@ public: // This is special, since it's not a JS value - as in it's not visible to JS // code. m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe)); - info.spill(DataFormatStorage); + info.spill(*m_stream, spillMe, DataFormatStorage); return; } case DataFormatInteger: { m_jit.store32(info.gpr(), JITCompiler::payloadFor(spillMe)); - info.spill(DataFormatInteger); + info.spill(*m_stream, spillMe, DataFormatInteger); return; } #if USE(JSVALUE64) case DataFormatDouble: { m_jit.storeDouble(info.fpr(), JITCompiler::addressFor(spillMe)); - info.spill(DataFormatDouble); + info.spill(*m_stream, spillMe, DataFormatDouble); return; } @@ -816,13 +739,13 @@ public: // Spill the value, and record it as spilled in its boxed form. m_jit.storePtr(reg, JITCompiler::addressFor(spillMe)); - info.spill((DataFormat)(spillFormat | DataFormatJS)); + info.spill(*m_stream, spillMe, (DataFormat)(spillFormat | DataFormatJS)); return; #elif USE(JSVALUE32_64) case DataFormatCell: case DataFormatBoolean: { m_jit.store32(info.gpr(), JITCompiler::payloadFor(spillMe)); - info.spill(spillFormat); + info.spill(*m_stream, spillMe, spillFormat); return; } @@ -830,7 +753,7 @@ public: case DataFormatJSDouble: { // On JSVALUE32_64 boxing a double is a no-op. m_jit.storeDouble(info.fpr(), JITCompiler::addressFor(spillMe)); - info.spill(DataFormatJSDouble); + info.spill(*m_stream, spillMe, DataFormatJSDouble); return; } @@ -839,7 +762,7 @@ public: ASSERT(spillFormat & DataFormatJS); m_jit.store32(info.tagGPR(), JITCompiler::tagFor(spillMe)); m_jit.store32(info.payloadGPR(), JITCompiler::payloadFor(spillMe)); - info.spill(spillFormat); + info.spill(*m_stream, spillMe, spillFormat); return; #endif } @@ -2204,7 +2127,7 @@ public: if (!m_compileOkay) return; ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes); - m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), jumpToFail, this)); + m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), jumpToFail, this, m_stream->size())); } void speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail) { @@ -2231,7 +2154,7 @@ public: return; ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes); m_jit.codeBlock()->appendSpeculationRecovery(recovery); - m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), jumpToFail, this, m_jit.codeBlock()->numberOfSpeculationRecoveries())); + m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), jumpToFail, this, m_stream->size(), m_jit.codeBlock()->numberOfSpeculationRecoveries())); } void speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery) { @@ -2252,7 +2175,7 @@ public: m_jit.codeBlock()->appendOSRExit( OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), - JITCompiler::Jump(), this))); + JITCompiler::Jump(), this, m_stream->size()))); exit.m_watchpointIndex = m_jit.codeBlock()->appendWatchpoint( Watchpoint(m_jit.watchpointLabel())); return &m_jit.codeBlock()->watchpoint(exit.m_watchpointIndex); @@ -2295,7 +2218,8 @@ public: exit.m_codeOrigin = nextNode->codeOrigin; exit.m_lastSetOperand = setLocal->local(); - exit.valueRecoveryForOperand(setLocal->local()) = valueRecovery; + exit.m_valueRecoveryOverride = adoptRef( + new ValueRecoveryOverride(setLocal->local(), valueRecovery)); } void forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& valueRecovery) { @@ -2362,6 +2286,13 @@ public: return m_variables[operand]; } + void recordSetLocal(int operand, ValueSource valueSource) + { + valueSourceReferenceForOperand(operand) = valueSource; + m_stream->appendAndLog(VariableEvent::setLocal(operand, valueSource.dataFormat())); + } + + // The JIT, while also provides MacroAssembler functionality. JITCompiler& m_jit; // The current node being generated. @@ -2395,6 +2326,9 @@ public: AbstractState m_state; + VariableEventStream* m_stream; + MinifiedGraph* m_minifiedGraph; + bool m_isCheckingArgumentTypes; Vector m_slowPathGenerators; // doesn't use OwnPtr<> because I don't want to include DFGSlowPathGenerator.h diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index 2c1fee1..df543a9 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -62,7 +62,7 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr); } - info.fillInteger(gpr); + info.fillInteger(*m_stream, gpr); returnFormat = DataFormatInteger; return gpr; } @@ -91,7 +91,7 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat m_gprs.release(tagGPR); m_gprs.release(payloadGPR); m_gprs.retain(payloadGPR, virtualRegister, SpillOrderInteger); - info.fillInteger(payloadGPR); + info.fillInteger(*m_stream, payloadGPR); returnFormat = DataFormatInteger; return payloadGPR; } @@ -103,10 +103,11 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat returnFormat = DataFormatInteger; return gpr; } - } - ASSERT_NOT_REACHED(); - return InvalidGPRReg; + default: + ASSERT_NOT_REACHED(); + return InvalidGPRReg; + } } FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) @@ -123,13 +124,13 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) GPRReg gpr = allocate(); m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr); m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); - info.fillInteger(gpr); + info.fillInteger(*m_stream, gpr); unlock(gpr); } else if (isNumberConstant(nodeIndex)) { FPRReg fpr = fprAllocate(); m_jit.loadDouble(addressOfDoubleConstant(nodeIndex), fpr); m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); return fpr; } else { // FIXME: should not be reachable? @@ -142,7 +143,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) FPRReg fpr = fprAllocate(); m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr); m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); return fpr; } @@ -162,7 +163,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) hasUnboxedDouble.link(&m_jit); m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); return fpr; } } @@ -207,7 +208,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) m_gprs.unlock(tagGPR); m_gprs.unlock(payloadGPR); m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); info.killSpilled(); return fpr; } @@ -227,10 +228,11 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) m_fprs.lock(fpr); return fpr; } - } - ASSERT_NOT_REACHED(); - return InvalidFPRReg; + default: + ASSERT_NOT_REACHED(); + return InvalidFPRReg; + } } bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& payloadGPR, FPRReg& fpr) @@ -252,7 +254,7 @@ bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& pa m_jit.move(Imm32(valueOfJSConstant(nodeIndex).payload()), payloadGPR); m_gprs.retain(tagGPR, virtualRegister, SpillOrderConstant); m_gprs.retain(payloadGPR, virtualRegister, SpillOrderConstant); - info.fillJSValue(tagGPR, payloadGPR, isInt32Constant(nodeIndex) ? DataFormatJSInteger : DataFormatJS); + info.fillJSValue(*m_stream, tagGPR, payloadGPR, isInt32Constant(nodeIndex) ? DataFormatJSInteger : DataFormatJS); } else { DataFormat spillFormat = info.spillFormat(); ASSERT(spillFormat != DataFormatNone && spillFormat != DataFormatStorage); @@ -278,7 +280,7 @@ bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& pa m_jit.load32(JITCompiler::payloadFor(virtualRegister), payloadGPR); m_gprs.retain(tagGPR, virtualRegister, SpillOrderSpilled); m_gprs.retain(payloadGPR, virtualRegister, SpillOrderSpilled); - info.fillJSValue(tagGPR, payloadGPR, spillFormat == DataFormatJSDouble ? DataFormatJS : spillFormat); + info.fillJSValue(*m_stream, tagGPR, payloadGPR, spillFormat == DataFormatJSDouble ? DataFormatJS : spillFormat); } return true; @@ -320,7 +322,7 @@ bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& pa m_gprs.release(gpr); m_gprs.retain(tagGPR, virtualRegister, SpillOrderJS); m_gprs.retain(payloadGPR, virtualRegister, SpillOrderJS); - info.fillJSValue(tagGPR, payloadGPR, fillFormat); + info.fillJSValue(*m_stream, tagGPR, payloadGPR, fillFormat); return true; } @@ -335,7 +337,7 @@ bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& pa m_fprs.release(oldFPR); m_gprs.retain(tagGPR, virtualRegister, SpillOrderJS); m_gprs.retain(payloadGPR, virtualRegister, SpillOrderJS); - info.fillJSValue(tagGPR, payloadGPR, DataFormatJS); + info.fillJSValue(*m_stream, tagGPR, payloadGPR, DataFormatJS); return true; } @@ -353,10 +355,11 @@ bool SpeculativeJIT::fillJSValue(NodeIndex nodeIndex, GPRReg& tagGPR, GPRReg& pa case DataFormatStorage: // this type currently never occurs ASSERT_NOT_REACHED(); - } - ASSERT_NOT_REACHED(); - return true; + default: + ASSERT_NOT_REACHED(); + return true; + } } class ValueToNumberSlowPathGenerator @@ -1065,7 +1068,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& GPRReg gpr = allocate(); m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr); m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); - info.fillInteger(gpr); + info.fillInteger(*m_stream, gpr); returnFormat = DataFormatInteger; return gpr; } @@ -1080,7 +1083,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& GPRReg gpr = allocate(); m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr); m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); - info.fillInteger(gpr); + info.fillInteger(*m_stream, gpr); returnFormat = DataFormatInteger; return gpr; } @@ -1098,7 +1101,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& m_gprs.release(tagGPR); m_gprs.release(payloadGPR); m_gprs.retain(payloadGPR, virtualRegister, SpillOrderInteger); - info.fillInteger(payloadGPR); + info.fillInteger(*m_stream, payloadGPR); // If !strict we're done, return. returnFormat = DataFormatInteger; return payloadGPR; @@ -1119,10 +1122,11 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& case DataFormatJSBoolean: case DataFormatStorage: ASSERT_NOT_REACHED(); - } - ASSERT_NOT_REACHED(); - return InvalidGPRReg; + default: + ASSERT_NOT_REACHED(); + return InvalidGPRReg; + } } GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat) @@ -1160,13 +1164,13 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) GPRReg gpr = allocate(); m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr); m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); - info.fillInteger(gpr); + info.fillInteger(*m_stream, gpr); unlock(gpr); } else if (isNumberConstant(nodeIndex)) { FPRReg fpr = fprAllocate(); m_jit.loadDouble(addressOfDoubleConstant(nodeIndex), fpr); m_fprs.retain(fpr, virtualRegister, SpillOrderConstant); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); return fpr; } else ASSERT_NOT_REACHED(); @@ -1177,7 +1181,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) FPRReg fpr = fprAllocate(); m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr); m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); return fpr; } @@ -1200,7 +1204,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) hasUnboxedDouble.link(&m_jit); m_fprs.retain(fpr, virtualRegister, SpillOrderSpilled); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); info.killSpilled(); return fpr; } @@ -1238,7 +1242,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) m_gprs.unlock(tagGPR); m_gprs.unlock(payloadGPR); m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); info.killSpilled(); return fpr; } @@ -1266,10 +1270,11 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) case DataFormatBoolean: case DataFormatJSBoolean: ASSERT_NOT_REACHED(); - } - ASSERT_NOT_REACHED(); - return InvalidFPRReg; + default: + ASSERT_NOT_REACHED(); + return InvalidFPRReg; + } } GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) @@ -1296,7 +1301,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) GPRReg gpr = allocate(); m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr); - info.fillCell(gpr); + info.fillCell(*m_stream, gpr); return gpr; } @@ -1306,7 +1311,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) GPRReg gpr = allocate(); m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr); m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); - info.fillCell(gpr); + info.fillCell(*m_stream, gpr); return gpr; } @@ -1328,7 +1333,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) m_gprs.release(tagGPR); m_gprs.release(payloadGPR); m_gprs.retain(payloadGPR, virtualRegister, SpillOrderCell); - info.fillCell(payloadGPR); + info.fillCell(*m_stream, payloadGPR); return payloadGPR; } @@ -1340,10 +1345,11 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) case DataFormatBoolean: case DataFormatStorage: ASSERT_NOT_REACHED(); - } - ASSERT_NOT_REACHED(); - return InvalidGPRReg; + default: + ASSERT_NOT_REACHED(); + return InvalidGPRReg; + } } GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) @@ -1370,7 +1376,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) GPRReg gpr = allocate(); m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); m_jit.move(MacroAssembler::TrustedImm32(jsValue.asBoolean()), gpr); - info.fillBoolean(gpr); + info.fillBoolean(*m_stream, gpr); return gpr; } @@ -1382,7 +1388,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) GPRReg gpr = allocate(); m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr); m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); - info.fillBoolean(gpr); + info.fillBoolean(*m_stream, gpr); return gpr; } @@ -1405,7 +1411,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) m_gprs.release(tagGPR); m_gprs.release(payloadGPR); m_gprs.retain(payloadGPR, virtualRegister, SpillOrderBoolean); - info.fillBoolean(payloadGPR); + info.fillBoolean(*m_stream, payloadGPR); return payloadGPR; } @@ -1417,10 +1423,11 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) case DataFormatCell: case DataFormatStorage: ASSERT_NOT_REACHED(); - } - ASSERT_NOT_REACHED(); - return InvalidGPRReg; + default: + ASSERT_NOT_REACHED(); + return InvalidGPRReg; + } } JITCompiler::Jump SpeculativeJIT::convertToDouble(JSValueOperand& op, FPRReg result) @@ -2004,7 +2011,7 @@ void SpeculativeJIT::compile(Node& node) // Indicate that it's no longer necessary to retrieve the value of // this bytecode variable from registers or other locations in the register file, // but that it is stored as a double. - valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile); + recordSetLocal(node.local(), ValueSource(DoubleInRegisterFile)); break; } SpeculatedType predictedType = node.variableAccessData()->argumentAwarePrediction(); @@ -2012,14 +2019,14 @@ void SpeculativeJIT::compile(Node& node) DoubleOperand value(this, node.child1()); m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local())); noResult(m_compileIndex); - valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile); + recordSetLocal(node.local(), ValueSource(DoubleInRegisterFile)); break; } if (isInt32Speculation(predictedType)) { SpeculateIntegerOperand value(this, node.child1()); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); - valueSourceReferenceForOperand(node.local()) = ValueSource(Int32InRegisterFile); + recordSetLocal(node.local(), ValueSource(Int32InRegisterFile)); break; } if (isArraySpeculation(predictedType)) { @@ -2029,14 +2036,14 @@ void SpeculativeJIT::compile(Node& node) speculationCheck(BadType, JSValueSource::unboxedCell(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); - valueSourceReferenceForOperand(node.local()) = ValueSource(CellInRegisterFile); + recordSetLocal(node.local(), ValueSource(CellInRegisterFile)); break; } if (isBooleanSpeculation(predictedType)) { SpeculateBooleanOperand value(this, node.child1()); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); - valueSourceReferenceForOperand(node.local()) = ValueSource(BooleanInRegisterFile); + recordSetLocal(node.local(), ValueSource(BooleanInRegisterFile)); break; } } @@ -2044,7 +2051,7 @@ void SpeculativeJIT::compile(Node& node) m_jit.store32(value.payloadGPR(), JITCompiler::payloadFor(node.local())); m_jit.store32(value.tagGPR(), JITCompiler::tagFor(node.local())); noResult(m_compileIndex); - valueSourceReferenceForOperand(node.local()) = ValueSource(ValueInRegisterFile); + recordSetLocal(node.local(), ValueSource(ValueInRegisterFile)); break; } diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index 215f801..54575aa 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -48,7 +48,7 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); if (isInt32Constant(nodeIndex)) { m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr); - info.fillInteger(gpr); + info.fillInteger(*m_stream, gpr); returnFormat = DataFormatInteger; return gpr; } @@ -74,7 +74,7 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat // Since we statically know that we're filling an integer, and values // in the RegisterFile are boxed, this must be DataFormatJSInteger. // We will check this with a jitAssert below. - info.fillJSValue(gpr, DataFormatJSInteger); + info.fillJSValue(*m_stream, gpr, DataFormatJSInteger); unlock(gpr); } @@ -107,10 +107,11 @@ GPRReg SpeculativeJIT::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat returnFormat = DataFormatInteger; return gpr; } + + default: + ASSERT_NOT_REACHED(); + return InvalidGPRReg; } - - ASSERT_NOT_REACHED(); - return InvalidGPRReg; } FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) @@ -127,7 +128,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) // FIXME: should not be reachable? m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr); m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); - info.fillInteger(gpr); + info.fillInteger(*m_stream, gpr); unlock(gpr); } else if (isNumberConstant(nodeIndex)) { FPRReg fpr = fprAllocate(); @@ -136,7 +137,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) unlock(gpr); m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); return fpr; } else { // FIXME: should not be reachable? @@ -144,7 +145,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) JSValue jsValue = valueOfJSConstant(nodeIndex); m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsValue)), gpr); m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); - info.fillJSValue(gpr, DataFormatJS); + info.fillJSValue(*m_stream, gpr, DataFormatJS); unlock(gpr); } } else { @@ -154,7 +155,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) FPRReg fpr = fprAllocate(); m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr); m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); return fpr; } @@ -163,7 +164,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr); - info.fillInteger(gpr); + info.fillInteger(*m_stream, gpr); unlock(gpr); break; } @@ -174,7 +175,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) ASSERT(spillFormat & DataFormatJS); m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); - info.fillJSValue(gpr, spillFormat); + info.fillJSValue(*m_stream, gpr, spillFormat); unlock(gpr); break; } @@ -216,7 +217,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) m_gprs.unlock(jsValueGpr); m_gprs.unlock(tempGpr); m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); info.killSpilled(); return fpr; } @@ -247,7 +248,7 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) m_gprs.release(gpr); m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); return fpr; } @@ -256,10 +257,11 @@ FPRReg SpeculativeJIT::fillDouble(NodeIndex nodeIndex) m_fprs.lock(fpr); return fpr; } + + default: + ASSERT_NOT_REACHED(); + return InvalidFPRReg; } - - ASSERT_NOT_REACHED(); - return InvalidFPRReg; } GPRReg SpeculativeJIT::fillJSValue(NodeIndex nodeIndex) @@ -274,18 +276,18 @@ GPRReg SpeculativeJIT::fillJSValue(NodeIndex nodeIndex) if (node.hasConstant()) { if (isInt32Constant(nodeIndex)) { - info.fillJSValue(gpr, DataFormatJSInteger); + info.fillJSValue(*m_stream, gpr, DataFormatJSInteger); JSValue jsValue = jsNumber(valueOfInt32Constant(nodeIndex)); m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr); } else if (isNumberConstant(nodeIndex)) { - info.fillJSValue(gpr, DataFormatJSDouble); + info.fillJSValue(*m_stream, gpr, DataFormatJSDouble); JSValue jsValue(JSValue::EncodeAsDouble, valueOfNumberConstant(nodeIndex)); m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr); } else { ASSERT(isJSConstant(nodeIndex)); JSValue jsValue = valueOfJSConstant(nodeIndex); m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsValue)), gpr); - info.fillJSValue(gpr, DataFormatJS); + info.fillJSValue(*m_stream, gpr, DataFormatJS); } m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); @@ -305,7 +307,7 @@ GPRReg SpeculativeJIT::fillJSValue(NodeIndex nodeIndex) } else ASSERT(spillFormat & DataFormatJS); } - info.fillJSValue(gpr, spillFormat); + info.fillJSValue(*m_stream, gpr, spillFormat); } return gpr; } @@ -321,7 +323,7 @@ GPRReg SpeculativeJIT::fillJSValue(NodeIndex nodeIndex) } m_gprs.lock(gpr); m_jit.orPtr(GPRInfo::tagTypeNumberRegister, gpr); - info.fillJSValue(gpr, DataFormatJSInteger); + info.fillJSValue(*m_stream, gpr, DataFormatJSInteger); return gpr; } @@ -330,7 +332,7 @@ GPRReg SpeculativeJIT::fillJSValue(NodeIndex nodeIndex) GPRReg gpr = boxDouble(fpr); // Update all info - info.fillJSValue(gpr, DataFormatJSDouble); + info.fillJSValue(*m_stream, gpr, DataFormatJSDouble); m_fprs.release(fpr); m_gprs.retain(gpr, virtualRegister, SpillOrderJS); @@ -353,10 +355,11 @@ GPRReg SpeculativeJIT::fillJSValue(NodeIndex nodeIndex) case DataFormatStorage: // this type currently never occurs ASSERT_NOT_REACHED(); + + default: + ASSERT_NOT_REACHED(); + return InvalidGPRReg; } - - ASSERT_NOT_REACHED(); - return InvalidGPRReg; } class ValueToNumberSlowPathGenerator @@ -1047,7 +1050,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); ASSERT(isInt32Constant(nodeIndex)); m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr); - info.fillInteger(gpr); + info.fillInteger(*m_stream, gpr); returnFormat = DataFormatInteger; return gpr; } @@ -1062,7 +1065,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& // If we know this was spilled as an integer we can fill without checking. if (strict) { m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr); - info.fillInteger(gpr); + info.fillInteger(*m_stream, gpr); returnFormat = DataFormatInteger; return gpr; } @@ -1071,14 +1074,14 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& m_jit.orPtr(GPRInfo::tagTypeNumberRegister, gpr); } else m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); - info.fillJSValue(gpr, DataFormatJSInteger); + info.fillJSValue(*m_stream, gpr, DataFormatJSInteger); returnFormat = DataFormatJSInteger; return gpr; } m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); // Fill as JSValue, and fall through. - info.fillJSValue(gpr, DataFormatJSInteger); + info.fillJSValue(*m_stream, gpr, DataFormatJSInteger); m_gprs.unlock(gpr); } @@ -1088,7 +1091,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& m_gprs.lock(gpr); if (!isInt32Speculation(type)) speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchPtr(MacroAssembler::Below, gpr, GPRInfo::tagTypeNumberRegister)); - info.fillJSValue(gpr, DataFormatJSInteger); + info.fillJSValue(*m_stream, gpr, DataFormatJSInteger); // If !strict we're done, return. if (!strict) { returnFormat = DataFormatJSInteger; @@ -1109,7 +1112,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& result = allocate(); else { m_gprs.lock(gpr); - info.fillInteger(gpr); + info.fillInteger(*m_stream, gpr); result = gpr; } m_jit.zeroExtend32ToPtr(gpr, result); @@ -1151,10 +1154,11 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& case DataFormatStorage: ASSERT_NOT_REACHED(); + + default: + ASSERT_NOT_REACHED(); + return InvalidGPRReg; } - - ASSERT_NOT_REACHED(); - return InvalidGPRReg; } GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat) @@ -1191,7 +1195,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) unlock(gpr); m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); return fpr; } if (isNumberConstant(nodeIndex)) { @@ -1201,7 +1205,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) unlock(gpr); m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); return fpr; } terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); @@ -1214,7 +1218,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) FPRReg fpr = fprAllocate(); m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr); m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); return fpr; } @@ -1223,7 +1227,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr); - info.fillInteger(gpr); + info.fillInteger(*m_stream, gpr); unlock(gpr); break; } @@ -1234,7 +1238,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) ASSERT(spillFormat & DataFormatJS); m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); - info.fillJSValue(gpr, spillFormat); + info.fillJSValue(*m_stream, gpr, spillFormat); unlock(gpr); break; } @@ -1277,7 +1281,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) m_gprs.unlock(jsValueGpr); m_gprs.unlock(tempGpr); m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); info.killSpilled(); return fpr; } @@ -1308,7 +1312,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) m_gprs.release(gpr); m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); - info.fillDouble(fpr); + info.fillDouble(*m_stream, fpr); return fpr; } @@ -1317,10 +1321,11 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) m_fprs.lock(fpr); return fpr; } + + default: + ASSERT_NOT_REACHED(); + return InvalidFPRReg; } - - ASSERT_NOT_REACHED(); - return InvalidFPRReg; } GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) @@ -1347,7 +1352,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) if (jsValue.isCell()) { m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr); - info.fillJSValue(gpr, DataFormatJSCell); + info.fillJSValue(*m_stream, gpr, DataFormatJSCell); return gpr; } terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); @@ -1357,10 +1362,10 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); - info.fillJSValue(gpr, DataFormatJS); + info.fillJSValue(*m_stream, gpr, DataFormatJS); if (!isCellSpeculation(type)) speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister)); - info.fillJSValue(gpr, DataFormatJSCell); + info.fillJSValue(*m_stream, gpr, DataFormatJSCell); return gpr; } @@ -1376,7 +1381,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) m_gprs.lock(gpr); if (!isCellSpeculation(type)) speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister)); - info.fillJSValue(gpr, DataFormatJSCell); + info.fillJSValue(*m_stream, gpr, DataFormatJSCell); return gpr; } @@ -1392,10 +1397,11 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) case DataFormatStorage: ASSERT_NOT_REACHED(); + + default: + ASSERT_NOT_REACHED(); + return InvalidGPRReg; } - - ASSERT_NOT_REACHED(); - return InvalidGPRReg; } GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) @@ -1422,7 +1428,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) if (jsValue.isBoolean()) { m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsValue)), gpr); - info.fillJSValue(gpr, DataFormatJSBoolean); + info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean); return gpr; } terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); @@ -1432,13 +1438,13 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); - info.fillJSValue(gpr, DataFormatJS); + info.fillJSValue(*m_stream, gpr, DataFormatJS); if (!isBooleanSpeculation(type)) { m_jit.xorPtr(TrustedImm32(static_cast(ValueFalse)), gpr); speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg)); m_jit.xorPtr(TrustedImm32(static_cast(ValueFalse)), gpr); } - info.fillJSValue(gpr, DataFormatJSBoolean); + info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean); return gpr; } @@ -1457,7 +1463,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg)); m_jit.xorPtr(TrustedImm32(static_cast(ValueFalse)), gpr); } - info.fillJSValue(gpr, DataFormatJSBoolean); + info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean); return gpr; } @@ -1473,10 +1479,11 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) case DataFormatStorage: ASSERT_NOT_REACHED(); + + default: + ASSERT_NOT_REACHED(); + return InvalidGPRReg; } - - ASSERT_NOT_REACHED(); - return InvalidGPRReg; } JITCompiler::Jump SpeculativeJIT::convertToDouble(GPRReg value, FPRReg result, GPRReg tmp) @@ -2055,7 +2062,7 @@ void SpeculativeJIT::compile(Node& node) // Indicate that it's no longer necessary to retrieve the value of // this bytecode variable from registers or other locations in the register file, // but that it is stored as a double. - valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile); + recordSetLocal(node.local(), ValueSource(DoubleInRegisterFile)); break; } @@ -2064,7 +2071,7 @@ void SpeculativeJIT::compile(Node& node) SpeculateIntegerOperand value(this, node.child1()); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); - valueSourceReferenceForOperand(node.local()) = ValueSource(Int32InRegisterFile); + recordSetLocal(node.local(), ValueSource(Int32InRegisterFile)); break; } if (isArraySpeculation(predictedType)) { @@ -2074,14 +2081,14 @@ void SpeculativeJIT::compile(Node& node) speculationCheck(BadType, JSValueRegs(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local())); noResult(m_compileIndex); - valueSourceReferenceForOperand(node.local()) = ValueSource(CellInRegisterFile); + recordSetLocal(node.local(), ValueSource(CellInRegisterFile)); break; } if (isBooleanSpeculation(predictedType)) { SpeculateBooleanOperand boolean(this, node.child1()); m_jit.storePtr(boolean.gpr(), JITCompiler::addressFor(node.local())); noResult(m_compileIndex); - valueSourceReferenceForOperand(node.local()) = ValueSource(BooleanInRegisterFile); + recordSetLocal(node.local(), ValueSource(BooleanInRegisterFile)); break; } } @@ -2090,7 +2097,7 @@ void SpeculativeJIT::compile(Node& node) m_jit.storePtr(value.gpr(), JITCompiler::addressFor(node.local())); noResult(m_compileIndex); - valueSourceReferenceForOperand(node.local()) = ValueSource(ValueInRegisterFile); + recordSetLocal(node.local(), ValueSource(ValueInRegisterFile)); break; } diff --git a/Source/JavaScriptCore/dfg/DFGValueRecoveryOverride.h b/Source/JavaScriptCore/dfg/DFGValueRecoveryOverride.h new file mode 100644 index 0000000..317111a --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGValueRecoveryOverride.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 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 DFGValueRecoveryOverride_h +#define DFGValueRecoveryOverride_h + +#include + +#if ENABLE(DFG_JIT) + +#include "ValueRecovery.h" +#include + +namespace JSC { namespace DFG { + +class ValueRecoveryOverride : public RefCounted { +public: + ValueRecoveryOverride() { } + + ValueRecoveryOverride(int operand, const ValueRecovery& recovery) + : operand(operand) + , recovery(recovery) + { + } + + int operand; + ValueRecovery recovery; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGValueRecoveryOverride_h + diff --git a/Source/JavaScriptCore/dfg/DFGValueSource.cpp b/Source/JavaScriptCore/dfg/DFGValueSource.cpp new file mode 100644 index 0000000..25d43ee --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGValueSource.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 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 "DFGValueSource.h" + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +void ValueSource::dump(FILE* out) const +{ + switch (kind()) { + case SourceNotSet: + fprintf(out, "NotSet"); + break; + case SourceIsDead: + fprintf(out, "IsDead"); + break; + case ValueInRegisterFile: + fprintf(out, "InRegFile"); + break; + case Int32InRegisterFile: + fprintf(out, "Int32"); + break; + case CellInRegisterFile: + fprintf(out, "Cell"); + break; + case BooleanInRegisterFile: + fprintf(out, "Bool"); + break; + case DoubleInRegisterFile: + fprintf(out, "Double"); + break; + case ArgumentsSource: + fprintf(out, "Arguments"); + break; + case HaveNode: + fprintf(out, "Node(%d)", m_nodeIndex); + break; + } +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/Source/JavaScriptCore/dfg/DFGValueSource.h b/Source/JavaScriptCore/dfg/DFGValueSource.h new file mode 100644 index 0000000..be4a6e0 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGValueSource.h @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2011 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 DFGValueSource_h +#define DFGValueSource_h + +#include + +#if ENABLE(DFG_JIT) + +#include "DFGCommon.h" +#include "DataFormat.h" +#include "SpeculatedType.h" +#include "ValueRecovery.h" + +namespace JSC { namespace DFG { + +enum ValueSourceKind { + SourceNotSet, + ValueInRegisterFile, + Int32InRegisterFile, + CellInRegisterFile, + BooleanInRegisterFile, + DoubleInRegisterFile, + ArgumentsSource, + SourceIsDead, + HaveNode +}; + +static inline ValueSourceKind dataFormatToValueSourceKind(DataFormat dataFormat) +{ + switch (dataFormat) { + case DataFormatInteger: + return Int32InRegisterFile; + case DataFormatDouble: + return DoubleInRegisterFile; + case DataFormatBoolean: + return BooleanInRegisterFile; + case DataFormatCell: + return CellInRegisterFile; + case DataFormatDead: + return SourceIsDead; + case DataFormatArguments: + return ArgumentsSource; + default: + ASSERT(dataFormat & DataFormatJS); + return ValueInRegisterFile; + } +} + +static inline DataFormat valueSourceKindToDataFormat(ValueSourceKind kind) +{ + switch (kind) { + case ValueInRegisterFile: + return DataFormatJS; + case Int32InRegisterFile: + return DataFormatInteger; + case CellInRegisterFile: + return DataFormatCell; + case BooleanInRegisterFile: + return DataFormatBoolean; + case DoubleInRegisterFile: + return DataFormatDouble; + case ArgumentsSource: + return DataFormatArguments; + case SourceIsDead: + return DataFormatDead; + default: + return DataFormatNone; + } +} + +static inline bool isInRegisterFile(ValueSourceKind kind) +{ + DataFormat format = valueSourceKindToDataFormat(kind); + return format != DataFormatNone && format < DataFormatOSRMarker; +} + +// Can this value be recovered without having to look at register allocation state or +// DFG node liveness? +static inline bool isTriviallyRecoverable(ValueSourceKind kind) +{ + return valueSourceKindToDataFormat(kind) != DataFormatNone; +} + +class ValueSource { +public: + ValueSource() + : m_nodeIndex(nodeIndexFromKind(SourceNotSet)) + { + } + + explicit ValueSource(ValueSourceKind valueSourceKind) + : m_nodeIndex(nodeIndexFromKind(valueSourceKind)) + { + ASSERT(kind() != SourceNotSet); + ASSERT(kind() != HaveNode); + } + + explicit ValueSource(NodeIndex nodeIndex) + : m_nodeIndex(nodeIndex) + { + ASSERT(nodeIndex != NoNode); + ASSERT(kind() == HaveNode); + } + + static ValueSource forSpeculation(SpeculatedType prediction) + { + if (isInt32Speculation(prediction)) + return ValueSource(Int32InRegisterFile); + if (isArraySpeculation(prediction)) + return ValueSource(CellInRegisterFile); + if (isBooleanSpeculation(prediction)) + return ValueSource(BooleanInRegisterFile); + return ValueSource(ValueInRegisterFile); + } + + static ValueSource forDataFormat(DataFormat dataFormat) + { + return ValueSource(dataFormatToValueSourceKind(dataFormat)); + } + + bool isSet() const + { + return kindFromNodeIndex(m_nodeIndex) != SourceNotSet; + } + + ValueSourceKind kind() const + { + return kindFromNodeIndex(m_nodeIndex); + } + + bool isInRegisterFile() const { return JSC::DFG::isInRegisterFile(kind()); } + bool isTriviallyRecoverable() const { return JSC::DFG::isTriviallyRecoverable(kind()); } + + DataFormat dataFormat() const + { + return valueSourceKindToDataFormat(kind()); + } + + ValueRecovery valueRecovery() const + { + ASSERT(isTriviallyRecoverable()); + switch (kind()) { + case ValueInRegisterFile: + return ValueRecovery::alreadyInRegisterFile(); + + case Int32InRegisterFile: + return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32(); + + case CellInRegisterFile: + return ValueRecovery::alreadyInRegisterFileAsUnboxedCell(); + + case BooleanInRegisterFile: + return ValueRecovery::alreadyInRegisterFileAsUnboxedBoolean(); + + case DoubleInRegisterFile: + return ValueRecovery::alreadyInRegisterFileAsUnboxedDouble(); + + case SourceIsDead: + return ValueRecovery::constant(jsUndefined()); + + case ArgumentsSource: + return ValueRecovery::argumentsThatWereNotCreated(); + + default: + ASSERT_NOT_REACHED(); + return ValueRecovery(); + } + } + + NodeIndex nodeIndex() const + { + ASSERT(kind() == HaveNode); + return m_nodeIndex; + } + + void dump(FILE* out) const; + +private: + static NodeIndex nodeIndexFromKind(ValueSourceKind kind) + { + ASSERT(kind >= SourceNotSet && kind < HaveNode); + return NoNode - kind; + } + + static ValueSourceKind kindFromNodeIndex(NodeIndex nodeIndex) + { + unsigned kind = static_cast(NoNode - nodeIndex); + if (kind >= static_cast(HaveNode)) + return HaveNode; + return static_cast(kind); + } + + NodeIndex m_nodeIndex; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGValueSource_h + diff --git a/Source/JavaScriptCore/dfg/DFGVariableEvent.cpp b/Source/JavaScriptCore/dfg/DFGVariableEvent.cpp new file mode 100644 index 0000000..3e84a6b --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGVariableEvent.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012 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 "DFGVariableEvent.h" + +#if ENABLE(DFG_JIT) + +#include "DFGFPRInfo.h" +#include "DFGGPRInfo.h" + +namespace JSC { namespace DFG { + +void VariableEvent::dump(FILE* out) const +{ + switch (kind()) { + case Reset: + fprintf(out, "Reset"); + break; + case BirthToFill: + dumpFillInfo("BirthToFill", out); + break; + case BirthToSpill: + dumpSpillInfo("BirthToSpill", out); + break; + case Fill: + dumpFillInfo("Fill", out); + break; + case Spill: + dumpSpillInfo("Spill", out); + break; + case Death: + fprintf(out, "Death(@%u)", nodeIndex()); + break; + case MovHint: + fprintf(out, "MovHint(@%u, r%d)", nodeIndex(), operand()); + break; + case SetLocalEvent: + fprintf(out, "SetLocal(r%d, %s)", operand(), dataFormatToString(dataFormat())); + break; + default: + ASSERT_NOT_REACHED(); + break; + } +} + +void VariableEvent::dumpFillInfo(const char* name, FILE* out) const +{ + fprintf(out, "%s(@%u, ", name, nodeIndex()); + if (dataFormat() == DataFormatDouble) + fprintf(out, "%s", FPRInfo::debugName(fpr())); +#if USE(JSVALUE32_64) + else if (dataFormat() & DataFormatJS) + fprintf(out, "%s:%s", GPRInfo::debugName(tagGPR()), GPRInfo::debugName(payloadGPR())); +#endif + else + fprintf(out, "%s", GPRInfo::debugName(gpr())); + fprintf(out, ", %s)", dataFormatToString(dataFormat())); +} + +void VariableEvent::dumpSpillInfo(const char* name, FILE* out) const +{ + fprintf(out, "%s(@%u, r%d, %s)", name, nodeIndex(), virtualRegister(), dataFormatToString(dataFormat())); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/Source/JavaScriptCore/dfg/DFGVariableEvent.h b/Source/JavaScriptCore/dfg/DFGVariableEvent.h new file mode 100644 index 0000000..a491a3e --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGVariableEvent.h @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2012 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 DFGVariableEvent_h +#define DFGVariableEvent_h + +#include + +#if ENABLE(DFG_JIT) + +#include "DFGCommon.h" +#include "DataFormat.h" +#include "MacroAssembler.h" +#include + +namespace JSC { namespace DFG { + +enum VariableEventKind { + // Marks the beginning of a checkpoint. If you interpret the variable + // events starting at a Reset point then you'll get everything you need. + Reset, + + // Node births. Points in the code where a node becomes relevant for OSR. + // It may be the point where it is actually born (i.e. assigned) or it may + // be a later point, if it's only later in the sequence of instructions + // that we start to care about this node. + BirthToFill, + BirthToSpill, + + // Events related to how a node is represented. + Fill, + Spill, + + // Death of a node - after this we no longer care about this node. + Death, + + // A MovHint means that a node is being associated with a bytecode operand, + // but that it has not been stored into that operand. + MovHint, + + // A SetLocalEvent means that a node's value has actually been stored into the + // bytecode operand that it's associated with. + SetLocalEvent, + + // Used to indicate an uninitialized VariableEvent. Don't use for other + // purposes. + InvalidEventKind +}; + +union VariableRepresentation { + MacroAssembler::RegisterID gpr; + MacroAssembler::FPRegisterID fpr; +#if USE(JSVALUE32_64) + struct { + MacroAssembler::RegisterID tagGPR; + MacroAssembler::RegisterID payloadGPR; + } pair; +#endif + int32_t virtualReg; +}; + +class VariableEvent { +public: + VariableEvent() + : m_kind(InvalidEventKind) + { + } + + static VariableEvent reset() + { + VariableEvent event; + event.m_kind = Reset; + return event; + } + + static VariableEvent fillGPR(VariableEventKind kind, NodeIndex nodeIndex, MacroAssembler::RegisterID gpr, DataFormat dataFormat) + { + ASSERT(kind == BirthToFill || kind == Fill); + ASSERT(dataFormat != DataFormatDouble); +#if USE(JSVALUE32_64) + ASSERT(!(dataFormat & DataFormatJS)); +#endif + VariableEvent event; + event.m_index = nodeIndex; + event.u.gpr = gpr; + event.m_kind = kind; + event.m_dataFormat = dataFormat; + return event; + } + +#if USE(JSVALUE32_64) + static VariableEvent fillPair(VariableEventKind kind, NodeIndex nodeIndex, MacroAssembler::RegisterID tagGPR, MacroAssembler::RegisterID payloadGPR) + { + ASSERT(kind == BirthToFill || kind == Fill); + VariableEvent event; + event.m_index = nodeIndex; + event.u.pair.tagGPR = tagGPR; + event.u.pair.payloadGPR = payloadGPR; + event.m_kind = kind; + event.m_dataFormat = DataFormatJS; + return event; + } +#endif // USE(JSVALUE32_64) + + static VariableEvent fillFPR(VariableEventKind kind, NodeIndex nodeIndex, MacroAssembler::FPRegisterID fpr) + { + ASSERT(kind == BirthToFill || kind == Fill); + VariableEvent event; + event.m_index = nodeIndex; + event.u.fpr = fpr; + event.m_kind = kind; + event.m_dataFormat = DataFormatDouble; + return event; + } + + static VariableEvent spill(VariableEventKind kind, NodeIndex nodeIndex, VirtualRegister virtualRegister, DataFormat format) + { + ASSERT(kind == BirthToSpill || kind == Spill); + VariableEvent event; + event.m_index = nodeIndex; + event.u.virtualReg = virtualRegister; + event.m_kind = kind; + event.m_dataFormat = format; + return event; + } + + static VariableEvent death(NodeIndex nodeIndex) + { + VariableEvent event; + event.m_index = nodeIndex; + event.m_kind = Death; + return event; + } + + static VariableEvent setLocal(int operand, DataFormat format) + { + VariableEvent event; + event.u.virtualReg = operand; + event.m_kind = SetLocalEvent; + event.m_dataFormat = format; + return event; + } + + static VariableEvent movHint(NodeIndex nodeIndex, int operand) + { + VariableEvent event; + event.m_index = nodeIndex; + event.u.virtualReg = operand; + event.m_kind = MovHint; + return event; + } + + VariableEventKind kind() const + { + return static_cast(m_kind); + } + + NodeIndex nodeIndex() const + { + ASSERT(m_kind == BirthToFill || m_kind == Fill + || m_kind == BirthToSpill || m_kind == Spill + || m_kind == Death || m_kind == MovHint); + return m_index; + } + + DataFormat dataFormat() const + { + ASSERT(m_kind == BirthToFill || m_kind == Fill + || m_kind == BirthToSpill || m_kind == Spill + || m_kind == SetLocalEvent); + return static_cast(m_dataFormat); + } + + MacroAssembler::RegisterID gpr() const + { + ASSERT(m_kind == BirthToFill || m_kind == Fill); + ASSERT(m_dataFormat); + ASSERT(m_dataFormat != DataFormatDouble); +#if USE(JSVALUE32_64) + ASSERT(!(m_dataFormat & DataFormatJS)); +#endif + return u.gpr; + } + +#if USE(JSVALUE32_64) + MacroAssembler::RegisterID tagGPR() const + { + ASSERT(m_kind == BirthToFill || m_kind == Fill); + ASSERT(m_dataFormat & DataFormatJS); + return u.pair.tagGPR; + } + MacroAssembler::RegisterID payloadGPR() const + { + ASSERT(m_kind == BirthToFill || m_kind == Fill); + ASSERT(m_dataFormat & DataFormatJS); + return u.pair.payloadGPR; + } +#endif // USE(JSVALUE32_64) + + MacroAssembler::FPRegisterID fpr() const + { + ASSERT(m_kind == BirthToFill || m_kind == Fill); + ASSERT(m_dataFormat == DataFormatDouble); + return u.fpr; + } + + VirtualRegister virtualRegister() const + { + ASSERT(m_kind == BirthToSpill || m_kind == Spill); + return static_cast(u.virtualReg); + } + + int operand() const + { + ASSERT(m_kind == SetLocalEvent || m_kind == MovHint); + return u.virtualReg; + } + + const VariableRepresentation& variableRepresentation() const { return u; } + + void dump(FILE*) const; + +private: + void dumpFillInfo(const char* name, FILE*) const; + void dumpSpillInfo(const char* name, FILE*) const; + + NodeIndex m_index; + + // For BirthToFill, Fill: + // - The GPR or FPR, or a GPR pair. + // For BirthToSpill, Spill: + // - The virtual register. + // For MovHint, SetLocalEvent: + // - The bytecode operand. + // For Death: + // - Unused. + VariableRepresentation u; + + int8_t m_kind; + int8_t m_dataFormat; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGVariableEvent_h + diff --git a/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp b/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp new file mode 100644 index 0000000..5d548a7 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2012 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 "DFGVariableEventStream.h" + +#if ENABLE(DFG_JIT) + +#include "CodeBlock.h" +#include "DFGValueSource.h" +#include + +namespace JSC { namespace DFG { + +void VariableEventStream::logEvent(const VariableEvent& event) +{ + dataLog("seq#%u:", static_cast(size())); + event.dump(WTF::dataFile()); + dataLog(" "); +} + +struct MinifiedGenerationInfo { + bool filled; // true -> in gpr/fpr/pair, false -> spilled + VariableRepresentation u; + DataFormat format; + + MinifiedGenerationInfo() + : format(DataFormatNone) + { + } + + void update(const VariableEvent& event) + { + switch (event.kind()) { + case BirthToFill: + case Fill: + filled = true; + break; + case BirthToSpill: + case Spill: + filled = false; + break; + case Death: + format = DataFormatNone; + return; + default: + return; + } + + u = event.variableRepresentation(); + format = event.dataFormat(); + } +}; + +void VariableEventStream::reconstruct( + CodeBlock* codeBlock, CodeOrigin codeOrigin, MinifiedGraph& graph, + unsigned index, Operands& valueRecoveries) const +{ + ASSERT(codeBlock->getJITType() == JITCode::DFGJIT); + CodeBlock* baselineCodeBlock = codeBlock->baselineVersion(); + + unsigned numVariables; + if (codeOrigin.inlineCallFrame) + numVariables = baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame)->m_numCalleeRegisters + codeOrigin.inlineCallFrame->stackOffset; + else + numVariables = baselineCodeBlock->m_numCalleeRegisters; + + // Crazy special case: if we're at index == 0 then this must be an argument check + // failure, in which case all variables are already set up. The recoveries should + // reflect this. + if (!index) { + valueRecoveries = Operands(codeBlock->numParameters(), numVariables); + for (size_t i = 0; i < valueRecoveries.size(); ++i) + valueRecoveries[i] = ValueRecovery::alreadyInRegisterFile(); + return; + } + + // Step 1: Find the last checkpoint, and figure out the number of virtual registers as we go. + unsigned startIndex = index - 1; + while (at(startIndex).kind() != Reset) + startIndex--; + + // Step 2: Create a mock-up of the DFG's state and execute the events. + Operands operandSources(codeBlock->numParameters(), numVariables); + Vector generationInfos(graph.originalGraphSize()); + for (unsigned i = startIndex; i < index; ++i) { + const VariableEvent& event = at(i); + switch (event.kind()) { + case Reset: + // nothing to do. + break; + case BirthToFill: + case BirthToSpill: + case Fill: + case Spill: + case Death: + generationInfos[event.nodeIndex()].update(event); + break; + case MovHint: + if (operandSources.hasOperand(event.operand())) + operandSources.setOperand(event.operand(), ValueSource(event.nodeIndex())); + break; + case SetLocalEvent: + if (operandSources.hasOperand(event.operand())) + operandSources.setOperand(event.operand(), ValueSource::forDataFormat(event.dataFormat())); + break; + default: + ASSERT_NOT_REACHED(); + break; + } + } + + // Step 3: Record the things that are live, so we can get to them more quickly. + Vector indicesOfLiveThings; + for (unsigned i = 0; i < generationInfos.size(); ++i) { + if (generationInfos[i].format != DataFormatNone) + indicesOfLiveThings.append(i); + } + + // Step 4: Compute value recoveries! + valueRecoveries = Operands(codeBlock->numParameters(), numVariables); + for (unsigned i = 0; i < operandSources.size(); ++i) { + ValueSource& source = operandSources[i]; + if (source.isTriviallyRecoverable()) { + valueRecoveries[i] = source.valueRecovery(); + continue; + } + + ASSERT(source.kind() == HaveNode); + MinifiedNode* node = graph.at(source.nodeIndex()); + if (node) { + if (node->hasConstantNumber()) { + valueRecoveries[i] = ValueRecovery::constant( + codeBlock->constantRegister( + FirstConstantRegisterIndex + node->constantNumber()).get()); + continue; + } + if (node->hasWeakConstant()) { + valueRecoveries[i] = ValueRecovery::constant(node->weakConstant()); + continue; + } + if (node->op() == PhantomArguments) { + valueRecoveries[i] = ValueRecovery::argumentsThatWereNotCreated(); + continue; + } + } + + MinifiedGenerationInfo* info = &generationInfos[source.nodeIndex()]; + if (info->format == DataFormatNone) { + // Try to see if there is an alternate node that would contain the value we want. + // There are four possibilities: + // + // Int32ToDouble: We can use this in place of the original node, but + // we'd rather not; so we use it only if it is the only remaining + // live version. + // + // ValueToInt32: If the only remaining live version of the value is + // ValueToInt32, then we can use it. + // + // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber + // then the only remaining uses are ones that want a properly formed number + // rather than a UInt32 intermediate. + // + // DoubleAsInt32: Same as UInt32ToNumber. + // + // The reverse of the above: This node could be a UInt32ToNumber, but its + // alternative is still alive. This means that the only remaining uses of + // the number would be fine with a UInt32 intermediate. + + bool found = false; + + if (node && node->op() == UInt32ToNumber) { + NodeIndex nodeIndex = node->child1(); + node = graph.at(nodeIndex); + info = &generationInfos[nodeIndex]; + if (info->format != DataFormatNone) + found = true; + } + + if (!found) { + NodeIndex int32ToDoubleIndex = NoNode; + NodeIndex valueToInt32Index = NoNode; + NodeIndex uint32ToNumberIndex = NoNode; + NodeIndex doubleAsInt32Index = NoNode; + + for (unsigned i = 0; i < indicesOfLiveThings.size(); ++i) { + NodeIndex nodeIndex = indicesOfLiveThings[i]; + node = graph.at(nodeIndex); + if (!node) + continue; + if (!node->hasChild1()) + continue; + if (node->child1() != source.nodeIndex()) + continue; + ASSERT(generationInfos[nodeIndex].format != DataFormatNone); + switch (node->op()) { + case Int32ToDouble: + int32ToDoubleIndex = nodeIndex; + break; + case ValueToInt32: + valueToInt32Index = nodeIndex; + break; + case UInt32ToNumber: + uint32ToNumberIndex = nodeIndex; + break; + case DoubleAsInt32: + doubleAsInt32Index = nodeIndex; + break; + default: + break; + } + } + + NodeIndex nodeIndexToUse; + if (doubleAsInt32Index != NoNode) + nodeIndexToUse = doubleAsInt32Index; + else if (int32ToDoubleIndex != NoNode) + nodeIndexToUse = int32ToDoubleIndex; + else if (valueToInt32Index != NoNode) + nodeIndexToUse = valueToInt32Index; + else if (uint32ToNumberIndex != NoNode) + nodeIndexToUse = uint32ToNumberIndex; + else + nodeIndexToUse = NoNode; + + if (nodeIndexToUse != NoNode) { + info = &generationInfos[nodeIndexToUse]; + ASSERT(info->format != DataFormatNone); + found = true; + } + } + + if (!found) { + valueRecoveries[i] = ValueRecovery::constant(jsUndefined()); + continue; + } + } + + ASSERT(info->format != DataFormatNone); + + if (info->filled) { + if (info->format == DataFormatDouble) { + valueRecoveries[i] = ValueRecovery::inFPR(info->u.fpr); + continue; + } +#if USE(JSVALUE32_64) + if (info->format & DataFormatJS) { + valueRecoveries[i] = ValueRecovery::inPair(info->u.pair.tagGPR, info->u.pair.payloadGPR); + continue; + } +#endif + valueRecoveries[i] = ValueRecovery::inGPR(info->u.gpr, info->format); + continue; + } + + valueRecoveries[i] = + ValueRecovery::displacedInRegisterFile(static_cast(info->u.virtualReg), info->format); + } +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/Source/JavaScriptCore/dfg/DFGVariableEventStream.h b/Source/JavaScriptCore/dfg/DFGVariableEventStream.h new file mode 100644 index 0000000..0d10eb0 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGVariableEventStream.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2012 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 DFGVariableEventStream_h +#define DFGVariableEventStream_h + +#include + +#if ENABLE(DFG_JIT) + +#include "DFGCommon.h" +#include "DFGMinifiedGraph.h" +#include "DFGVariableEvent.h" +#include "Operands.h" +#include + +namespace JSC { namespace DFG { + +class VariableEventStream : public Vector { +public: + void appendAndLog(const VariableEvent& event) + { +#if DFG_ENABLE(DEBUG_VERBOSE) + logEvent(event); +#endif + append(event); + } + + void reconstruct( + CodeBlock*, CodeOrigin, MinifiedGraph&, + unsigned index, Operands&) const; + +private: + void logEvent(const VariableEvent&); +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGVariableEventStream_h + diff --git a/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp b/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp index 2d7ce33..86b3383 100644 --- a/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp @@ -132,6 +132,7 @@ public: bool performVirtualRegisterAllocation(Graph& graph) { + SamplingRegion samplingRegion("DFG Virtual Register Allocation Phase"); return runPhase(graph); } -- 2.7.4