Skip to content
Permalink
Browse files

The current state of the call frame should be taken into account in t…

…he DFG for both predictions and proofs

https://bugs.webkit.org/show_bug.cgi?id=94412

Reviewed by Geoffrey Garen.

This ensures that no matter how smart the DFG gets, it'll always know through
which entrypoint OSR will try to enter, and with which values it will attempt
to do so. For prologue OSR, this has no effect other than adding the current
arguments to the argument predictions. For loop OSR, this makes our treatment
of the loop slightly more conservative - just conservative enough to ensure
that OSR succeeds.

* bytecode/CodeBlock.cpp:
(JSC::ProgramCodeBlock::compileOptimized):
(JSC::EvalCodeBlock::compileOptimized):
(JSC::FunctionCodeBlock::compileOptimized):
* bytecode/CodeBlock.h:
(CodeBlock):
(ProgramCodeBlock):
(EvalCodeBlock):
(FunctionCodeBlock):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::initialize):
* dfg/DFGAbstractValue.h:
(JSC::DFG::AbstractValue::setMostSpecific):
(AbstractValue):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::fixVariableAccessPredictions):
(JSC::DFG::ByteCodeParser::parse):
* dfg/DFGDriver.cpp:
(JSC::DFG::compile):
(JSC::DFG::tryCompile):
(JSC::DFG::tryCompileFunction):
* dfg/DFGDriver.h:
(DFG):
(JSC::DFG::tryCompile):
(JSC::DFG::tryCompileFunction):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::Graph):
(Graph):
* jit/JITDriver.h:
(JSC::jitCompileIfAppropriate):
(JSC::jitCompileFunctionIfAppropriate):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* runtime/Executable.cpp:
(JSC::EvalExecutable::compileOptimized):
(JSC::EvalExecutable::compileInternal):
(JSC::ProgramExecutable::compileOptimized):
(JSC::ProgramExecutable::compileInternal):
(JSC::FunctionExecutable::compileOptimizedForCall):
(JSC::FunctionExecutable::compileOptimizedForConstruct):
(JSC::FunctionExecutable::compileForCallInternal):
(JSC::FunctionExecutable::compileForConstructInternal):
* runtime/Executable.h:
(EvalExecutable):
(ProgramExecutable):
(FunctionExecutable):
(JSC::FunctionExecutable::compileOptimizedFor):
* runtime/ExecutionHarness.h:
(JSC::prepareForExecution):
(JSC::prepareFunctionForExecution):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@125982 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
fpizlo@apple.com
fpizlo@apple.com committed Aug 19, 2012
1 parent 3a1e86d commit 0fd7ec908ba87eea05f8d6fd701d4b3b322aabd5
@@ -1,3 +1,68 @@
2012-08-17 Filip Pizlo <fpizlo@apple.com>

The current state of the call frame should be taken into account in the DFG for both predictions and proofs
https://bugs.webkit.org/show_bug.cgi?id=94412

Reviewed by Geoffrey Garen.

This ensures that no matter how smart the DFG gets, it'll always know through
which entrypoint OSR will try to enter, and with which values it will attempt
to do so. For prologue OSR, this has no effect other than adding the current
arguments to the argument predictions. For loop OSR, this makes our treatment
of the loop slightly more conservative - just conservative enough to ensure
that OSR succeeds.

* bytecode/CodeBlock.cpp:
(JSC::ProgramCodeBlock::compileOptimized):
(JSC::EvalCodeBlock::compileOptimized):
(JSC::FunctionCodeBlock::compileOptimized):
* bytecode/CodeBlock.h:
(CodeBlock):
(ProgramCodeBlock):
(EvalCodeBlock):
(FunctionCodeBlock):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::initialize):
* dfg/DFGAbstractValue.h:
(JSC::DFG::AbstractValue::setMostSpecific):
(AbstractValue):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::fixVariableAccessPredictions):
(JSC::DFG::ByteCodeParser::parse):
* dfg/DFGDriver.cpp:
(JSC::DFG::compile):
(JSC::DFG::tryCompile):
(JSC::DFG::tryCompileFunction):
* dfg/DFGDriver.h:
(DFG):
(JSC::DFG::tryCompile):
(JSC::DFG::tryCompileFunction):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::Graph):
(Graph):
* jit/JITDriver.h:
(JSC::jitCompileIfAppropriate):
(JSC::jitCompileFunctionIfAppropriate):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* runtime/Executable.cpp:
(JSC::EvalExecutable::compileOptimized):
(JSC::EvalExecutable::compileInternal):
(JSC::ProgramExecutable::compileOptimized):
(JSC::ProgramExecutable::compileInternal):
(JSC::FunctionExecutable::compileOptimizedForCall):
(JSC::FunctionExecutable::compileOptimizedForConstruct):
(JSC::FunctionExecutable::compileForCallInternal):
(JSC::FunctionExecutable::compileForConstructInternal):
* runtime/Executable.h:
(EvalExecutable):
(ProgramExecutable):
(FunctionExecutable):
(JSC::FunctionExecutable::compileOptimizedFor):
* runtime/ExecutionHarness.h:
(JSC::prepareForExecution):
(JSC::prepareFunctionForExecution):

2012-08-17 Filip Pizlo <fpizlo@apple.com>

DFG CSE should be more honest about when it changed the IR
@@ -2687,27 +2687,27 @@ CodeBlock* FunctionCodeBlock::replacement()
return &static_cast<FunctionExecutable*>(ownerExecutable())->generatedBytecodeFor(m_isConstructor ? CodeForConstruct : CodeForCall);
}

JSObject* ProgramCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode)
JSObject* ProgramCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode, unsigned bytecodeIndex)
{
if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType()))
return 0;
JSObject* error = static_cast<ProgramExecutable*>(ownerExecutable())->compileOptimized(exec, scopeChainNode);
JSObject* error = static_cast<ProgramExecutable*>(ownerExecutable())->compileOptimized(exec, scopeChainNode, bytecodeIndex);
return error;
}

JSObject* EvalCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode)
JSObject* EvalCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode, unsigned bytecodeIndex)
{
if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType()))
return 0;
JSObject* error = static_cast<EvalExecutable*>(ownerExecutable())->compileOptimized(exec, scopeChainNode);
JSObject* error = static_cast<EvalExecutable*>(ownerExecutable())->compileOptimized(exec, scopeChainNode, bytecodeIndex);
return error;
}

JSObject* FunctionCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode)
JSObject* FunctionCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode, unsigned bytecodeIndex)
{
if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType()))
return 0;
JSObject* error = static_cast<FunctionExecutable*>(ownerExecutable())->compileOptimizedFor(exec, scopeChainNode, m_isConstructor ? CodeForConstruct : CodeForCall);
JSObject* error = static_cast<FunctionExecutable*>(ownerExecutable())->compileOptimizedFor(exec, scopeChainNode, bytecodeIndex, m_isConstructor ? CodeForConstruct : CodeForCall);
return error;
}

@@ -442,7 +442,7 @@ namespace JSC {
MacroAssemblerCodePtr getJITCodeWithArityCheck() { return m_jitCodeWithArityCheck; }
JITCode::JITType getJITType() { return m_jitCode.jitType(); }
ExecutableMemoryHandle* executableMemory() { return getJITCode().getExecutableMemory(); }
virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*) = 0;
virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*, unsigned bytecodeIndex) = 0;
virtual void jettison() = 0;
enum JITCompilationResult { AlreadyCompiled, CouldNotCompile, CompiledSuccessfully };
JITCompilationResult jitCompile(ExecState* exec)
@@ -1448,7 +1448,7 @@ namespace JSC {

#if ENABLE(JIT)
protected:
virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*);
virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*, unsigned bytecodeIndex);
virtual void jettison();
virtual bool jitCompileImpl(ExecState*);
virtual CodeBlock* replacement();
@@ -1483,7 +1483,7 @@ namespace JSC {

#if ENABLE(JIT)
protected:
virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*);
virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*, unsigned bytecodeIndex);
virtual void jettison();
virtual bool jitCompileImpl(ExecState*);
virtual CodeBlock* replacement();
@@ -1521,7 +1521,7 @@ namespace JSC {

#if ENABLE(JIT)
protected:
virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*);
virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*, unsigned bytecodeIndex);
virtual void jettison();
virtual bool jitCompileImpl(ExecState*);
virtual CodeBlock* replacement();
@@ -158,6 +158,16 @@ void AbstractState::initialize(Graph& graph)
block->valuesAtHead.local(i).clear();
block->valuesAtTail.local(i).clear();
}
if (!block->isOSRTarget)
continue;
if (block->bytecodeBegin != graph.m_osrEntryBytecodeIndex)
continue;
for (size_t i = 0; i < graph.m_mustHandleValues.size(); ++i) {
AbstractValue value;
value.setMostSpecific(graph.m_mustHandleValues[i]);
block->valuesAtHead.operand(graph.m_mustHandleValues.operandForIndex(i)).merge(value);
}
block->cfaShouldRevisit = true;
}
}

@@ -386,6 +386,23 @@ struct AbstractValue {
return result;
}

void setMostSpecific(JSValue value)
{
if (!!value && value.isCell()) {
Structure* structure = value.asCell()->structure();
m_structure = structure;
m_unclobberedStructure = structure;
} else {
m_structure.clear();
m_unclobberedStructure.clear();
}

m_type = speculationFromValue(value);
m_value = value;

checkConsistency();
}

void set(JSValue value)
{
if (!!value && value.isCell()) {
@@ -118,7 +118,7 @@ class ByteCodeParser {
template<PhiStackType stackType>
void processPhiStack();

void fixVariableAccessSpeculations();
void fixVariableAccessPredictions();
// Add spill locations to nodes.
void allocateVirtualRegisters();

@@ -3030,7 +3030,7 @@ void ByteCodeParser::processPhiStack()
}
}

void ByteCodeParser::fixVariableAccessSpeculations()
void ByteCodeParser::fixVariableAccessPredictions()
{
for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
VariableAccessData* data = &m_graph.m_variableAccessData[i];
@@ -3362,7 +3362,27 @@ bool ByteCodeParser::parse()
m_graph.m_blocks[blockIndex].clear();
}

fixVariableAccessSpeculations();
fixVariableAccessPredictions();

for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
BasicBlock* block = m_graph.m_blocks[blockIndex].get();
if (!block)
continue;
if (!block->isOSRTarget)
continue;
if (block->bytecodeBegin != m_graph.m_osrEntryBytecodeIndex)
continue;
for (size_t i = 0; i < m_graph.m_mustHandleValues.size(); ++i) {
NodeIndex nodeIndex = block->variablesAtHead.operand(
m_graph.m_mustHandleValues.operandForIndex(i));
if (nodeIndex == NoNode)
continue;
Node& node = m_graph[nodeIndex];
ASSERT(node.hasLocal());
node.variableAccessData()->predict(
speculationFromValue(m_graph.m_mustHandleValues[i]));
}
}

m_graph.m_preservedVars = m_preservedVars;
m_graph.m_localVars = m_numLocals;
@@ -57,7 +57,7 @@ unsigned getNumCompilations()
}

enum CompileMode { CompileFunction, CompileOther };
inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr* jitCodeWithArityCheck)
inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr* jitCodeWithArityCheck, unsigned osrEntryBytecodeIndex)
{
SamplingRegion samplingRegion("DFG Compilation (Driver)");

@@ -66,6 +66,8 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo
ASSERT(codeBlock);
ASSERT(codeBlock->alternative());
ASSERT(codeBlock->alternative()->getJITType() == JITCode::BaselineJIT);

ASSERT(osrEntryBytecodeIndex != UINT_MAX);

if (!Options::useDFGJIT())
return false;
@@ -74,7 +76,30 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo
dataLog("DFG compiling code block %p(%p) for executable %p, number of instructions = %u.\n", codeBlock, codeBlock->alternative(), codeBlock->ownerExecutable(), codeBlock->instructionCount());
#endif

Graph dfg(exec->globalData(), codeBlock);
// Derive our set of must-handle values. The compilation must be at least conservative
// enough to allow for OSR entry with these values.
unsigned numVarsWithValues;
if (osrEntryBytecodeIndex)
numVarsWithValues = codeBlock->m_numVars;
else
numVarsWithValues = 0;
Operands<JSValue> mustHandleValues(codeBlock->numParameters(), numVarsWithValues);
for (size_t i = 0; i < mustHandleValues.size(); ++i) {
int operand = mustHandleValues.operandForIndex(i);
if (operandIsArgument(operand)
&& !operandToArgument(operand)
&& compileMode == CompileFunction
&& codeBlock->specializationKind() == CodeForConstruct) {
// Ugh. If we're in a constructor, the 'this' argument may hold garbage. It will
// also never be used. It doesn't matter what we put into the value for this,
// but it has to be an actual value that can be grokked by subsequent DFG passes,
// so we sanitize it here by turning it into Undefined.
mustHandleValues[i] = jsUndefined();
} else
mustHandleValues[i] = exec->uncheckedR(operand).jsValue();
}

Graph dfg(exec->globalData(), codeBlock, osrEntryBytecodeIndex, mustHandleValues);
if (!parse(exec, dfg))
return false;

@@ -137,14 +162,14 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo
return result;
}

bool tryCompile(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode)
bool tryCompile(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, unsigned bytecodeIndex)
{
return compile(CompileOther, exec, codeBlock, jitCode, 0);
return compile(CompileOther, exec, codeBlock, jitCode, 0, bytecodeIndex);
}

bool tryCompileFunction(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck)
bool tryCompileFunction(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck, unsigned bytecodeIndex)
{
return compile(CompileFunction, exec, codeBlock, jitCode, &jitCodeWithArityCheck);
return compile(CompileFunction, exec, codeBlock, jitCode, &jitCodeWithArityCheck, bytecodeIndex);
}

} } // namespace JSC::DFG
@@ -41,11 +41,11 @@ namespace DFG {
JS_EXPORT_PRIVATE unsigned getNumCompilations();

#if ENABLE(DFG_JIT)
bool tryCompile(ExecState*, CodeBlock*, JITCode&);
bool tryCompileFunction(ExecState*, CodeBlock*, JITCode&, MacroAssemblerCodePtr& jitCodeWithArityCheck);
bool tryCompile(ExecState*, CodeBlock*, JITCode&, unsigned bytecodeIndex);
bool tryCompileFunction(ExecState*, CodeBlock*, JITCode&, MacroAssemblerCodePtr& jitCodeWithArityCheck, unsigned bytecodeIndex);
#else
inline bool tryCompile(ExecState*, CodeBlock*, JITCode&) { return false; }
inline bool tryCompileFunction(ExecState*, CodeBlock*, JITCode&, MacroAssemblerCodePtr&) { return false; }
inline bool tryCompile(ExecState*, CodeBlock*, JITCode&, unsigned) { return false; }
inline bool tryCompileFunction(ExecState*, CodeBlock*, JITCode&, MacroAssemblerCodePtr&, unsigned) { return false; }
#endif

} } // namespace JSC::DFG
@@ -76,11 +76,13 @@ struct ResolveGlobalData {
// Nodes that are 'dead' remain in the vector with refCount 0.
class Graph : public Vector<Node, 64> {
public:
Graph(JSGlobalData& globalData, CodeBlock* codeBlock)
Graph(JSGlobalData& globalData, CodeBlock* codeBlock, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues)
: m_globalData(globalData)
, m_codeBlock(codeBlock)
, m_profiledBlock(codeBlock->alternative())
, m_hasArguments(false)
, m_osrEntryBytecodeIndex(osrEntryBytecodeIndex)
, m_mustHandleValues(mustHandleValues)
{
ASSERT(m_profiledBlock);
}
@@ -710,6 +712,8 @@ class Graph : public Vector<Node, 64> {
Dominators m_dominators;
unsigned m_localVars;
unsigned m_parameterSlots;
unsigned m_osrEntryBytecodeIndex;
Operands<JSValue> m_mustHandleValues;
private:

void handleSuccessor(Vector<BlockIndex, 16>& worklist, BlockIndex blockIndex, BlockIndex successorIndex);
@@ -38,7 +38,7 @@
namespace JSC {

template<typename CodeBlockType>
inline bool jitCompileIfAppropriate(ExecState* exec, OwnPtr<CodeBlockType>& codeBlock, JITCode& jitCode, JITCode::JITType jitType, JITCompilationEffort effort)
inline bool jitCompileIfAppropriate(ExecState* exec, OwnPtr<CodeBlockType>& codeBlock, JITCode& jitCode, JITCode::JITType jitType, unsigned bytecodeIndex, JITCompilationEffort effort)
{
JSGlobalData& globalData = exec->globalData();

@@ -54,7 +54,7 @@ inline bool jitCompileIfAppropriate(ExecState* exec, OwnPtr<CodeBlockType>& code

bool dfgCompiled = false;
if (jitType == JITCode::DFGJIT)
dfgCompiled = DFG::tryCompile(exec, codeBlock.get(), jitCode);
dfgCompiled = DFG::tryCompile(exec, codeBlock.get(), jitCode, bytecodeIndex);
if (dfgCompiled) {
if (codeBlock->alternative())
codeBlock->alternative()->unlinkIncomingCalls();
@@ -75,7 +75,7 @@ inline bool jitCompileIfAppropriate(ExecState* exec, OwnPtr<CodeBlockType>& code
return true;
}

inline bool jitCompileFunctionIfAppropriate(ExecState* exec, OwnPtr<FunctionCodeBlock>& codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck, SharedSymbolTable*& symbolTable, JITCode::JITType jitType, JITCompilationEffort effort)
inline bool jitCompileFunctionIfAppropriate(ExecState* exec, OwnPtr<FunctionCodeBlock>& codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck, SharedSymbolTable*& symbolTable, JITCode::JITType jitType, unsigned bytecodeIndex, JITCompilationEffort effort)
{
JSGlobalData& globalData = exec->globalData();

@@ -92,7 +92,7 @@ inline bool jitCompileFunctionIfAppropriate(ExecState* exec, OwnPtr<FunctionCode

bool dfgCompiled = false;
if (jitType == JITCode::DFGJIT)
dfgCompiled = DFG::tryCompileFunction(exec, codeBlock.get(), jitCode, jitCodeWithArityCheck);
dfgCompiled = DFG::tryCompileFunction(exec, codeBlock.get(), jitCode, jitCodeWithArityCheck, bytecodeIndex);
if (dfgCompiled) {
if (codeBlock->alternative())
codeBlock->alternative()->unlinkIncomingCalls();
@@ -2022,8 +2022,7 @@ DEFINE_STUB_FUNCTION(void, optimize)
}
ScopeChainNode* scopeChain = callFrame->scopeChain();
JSObject* error = codeBlock->compileOptimized(callFrame, scopeChain);
JSObject* error = codeBlock->compileOptimized(callFrame, scopeChain, bytecodeIndex);
#if ENABLE(JIT_VERBOSE_OSR)
if (error)
dataLog("WARNING: optimized compilation failed.\n");

0 comments on commit 0fd7ec9

Please sign in to comment.
You can’t perform that action at this time.