Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (138668 => 138669)
--- trunk/Source/_javascript_Core/ChangeLog 2013-01-02 23:54:21 UTC (rev 138668)
+++ trunk/Source/_javascript_Core/ChangeLog 2013-01-02 23:54:42 UTC (rev 138669)
@@ -1,3 +1,48 @@
+2013-01-02 Filip Pizlo <[email protected]>
+
+ DFG inlining machinery should be robust against the inline callee varying while the executable stays the same
+ https://bugs.webkit.org/show_bug.cgi?id=105953
+
+ Reviewed by Mark Hahnenberg.
+
+ This institutes the policy that if InlineCallFrame::callee is null, then the callee and scope have already
+ been stored into the true call frame (i.e. the place where the call frame of the inlined call would have
+ been) and so any attempt to access the callee or scope should do a load instead of assuming that the value
+ is constant. This wires the changes through the bytecode parser, the stack scanning logic, and the compiler
+ optimization phases and backends.
+
+ * bytecode/CodeOrigin.cpp:
+ (JSC::InlineCallFrame::dump):
+ * bytecode/CodeOrigin.h:
+ (CodeOrigin):
+ (InlineCallFrame):
+ (JSC::InlineCallFrame::isClosureCall):
+ (JSC::CodeOrigin::stackOffset):
+ (JSC):
+ * dfg/DFGAssemblyHelpers.h:
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::get):
+ (InlineStackEntry):
+ (JSC::DFG::ByteCodeParser::getScope):
+ (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
+ * dfg/DFGCSEPhase.cpp:
+ (CSEPhase):
+ (JSC::DFG::CSEPhase::genericPureCSE):
+ (JSC::DFG::CSEPhase::pureCSE):
+ (JSC::DFG::CSEPhase::pureCSERequiringSameInlineCallFrame):
+ (JSC::DFG::CSEPhase::getMyScopeLoadElimination):
+ (JSC::DFG::CSEPhase::performNodeCSE):
+ * dfg/DFGOSRExitCompiler32_64.cpp:
+ (JSC::DFG::OSRExitCompiler::compileExit):
+ * dfg/DFGOSRExitCompiler64.cpp:
+ (JSC::DFG::OSRExitCompiler::compileExit):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * interpreter/CallFrame.cpp:
+ (JSC::CallFrame::trueCallFrame):
+
2013-01-02 Gavin Barraclough <[email protected]>
Objective-C API for _javascript_Core
Modified: trunk/Source/_javascript_Core/bytecode/CodeOrigin.cpp (138668 => 138669)
--- trunk/Source/_javascript_Core/bytecode/CodeOrigin.cpp 2013-01-02 23:54:21 UTC (rev 138668)
+++ trunk/Source/_javascript_Core/bytecode/CodeOrigin.cpp 2013-01-02 23:54:42 UTC (rev 138669)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -81,7 +81,12 @@
void InlineCallFrame::dump(PrintStream& out) const
{
- out.print("#", hash(), ":<", RawPointer(executable.get()), ", bc#", caller.bytecodeIndex, ", ", specializationKind(), ">");
+ out.print("#", hash(), ":<", RawPointer(executable.get()), ", bc#", caller.bytecodeIndex, ", ", specializationKind());
+ if (callee)
+ out.print(", known callee: ", JSValue(callee.get()));
+ else
+ out.print(", closure call");
+ out.print(">");
}
} // namespace JSC
Modified: trunk/Source/_javascript_Core/bytecode/CodeOrigin.h (138668 => 138669)
--- trunk/Source/_javascript_Core/bytecode/CodeOrigin.h 2013-01-02 23:54:21 UTC (rev 138668)
+++ trunk/Source/_javascript_Core/bytecode/CodeOrigin.h 2013-01-02 23:54:42 UTC (rev 138669)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -83,6 +83,8 @@
// would have owned the code if it had not been inlined. Otherwise returns 0.
ExecutableBase* codeOriginOwner() const;
+ unsigned stackOffset() const;
+
static unsigned inlineDepthForCallFrame(InlineCallFrame*);
bool operator==(const CodeOrigin& other) const;
@@ -98,7 +100,7 @@
struct InlineCallFrame {
Vector<ValueRecovery> arguments;
WriteBarrier<ExecutableBase> executable;
- WriteBarrier<JSFunction> callee;
+ WriteBarrier<JSFunction> callee; // This may be null, indicating that this is a closure call and that the JSFunction and JSScope are already on the stack.
CodeOrigin caller;
BitVector capturedVars; // Indexed by the machine call frame's variable numbering.
unsigned stackOffset : 31;
@@ -106,6 +108,8 @@
CodeSpecializationKind specializationKind() const { return specializationFromIsCall(isCall); }
+ bool isClosureCall() const { return !callee; }
+
CodeBlockHash hash() const;
CodeBlock* baselineCodeBlock() const;
@@ -118,6 +122,14 @@
unsigned callReturnOffset;
};
+inline unsigned CodeOrigin::stackOffset() const
+{
+ if (!inlineCallFrame)
+ return 0;
+
+ return inlineCallFrame->stackOffset;
+}
+
inline bool CodeOrigin::operator==(const CodeOrigin& other) const
{
return bytecodeIndex == other.bytecodeIndex
Modified: trunk/Source/_javascript_Core/dfg/DFGAssemblyHelpers.h (138668 => 138669)
--- trunk/Source/_javascript_Core/dfg/DFGAssemblyHelpers.h 2013-01-02 23:54:21 UTC (rev 138668)
+++ trunk/Source/_javascript_Core/dfg/DFGAssemblyHelpers.h 2013-01-02 23:54:42 UTC (rev 138669)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (138668 => 138669)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2013-01-02 23:54:21 UTC (rev 138668)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2013-01-02 23:54:42 UTC (rev 138669)
@@ -230,7 +230,7 @@
NodeIndex get(int operand)
{
if (operand == JSStack::Callee) {
- if (m_inlineStackTop->m_inlineCallFrame)
+ if (m_inlineStackTop->m_inlineCallFrame && m_inlineStackTop->m_inlineCallFrame->callee)
return cellConstant(m_inlineStackTop->m_inlineCallFrame->callee.get());
return getCallee();
@@ -1222,7 +1222,7 @@
CodeBlock*,
CodeBlock* profiledBlock,
BlockIndex callsiteBlockHead,
- JSFunction* callee,
+ JSFunction* callee, // Null if this is a closure call.
VirtualRegister returnValueVR,
VirtualRegister inlineCallFrameStart,
int argumentCountIncludingThis,
@@ -1892,7 +1892,7 @@
NodeIndex ByteCodeParser::getScope(bool skipTop, unsigned skipCount)
{
NodeIndex localBase;
- if (m_inlineStackTop->m_inlineCallFrame) {
+ if (m_inlineStackTop->m_inlineCallFrame && !m_inlineStackTop->m_inlineCallFrame->isClosureCall()) {
ASSERT(m_inlineStackTop->m_inlineCallFrame->callee);
localBase = cellConstant(m_inlineStackTop->m_inlineCallFrame->callee->scope());
} else
@@ -3497,7 +3497,7 @@
CodeBlock* codeBlock,
CodeBlock* profiledBlock,
BlockIndex callsiteBlockHead,
- JSFunction* callee,
+ JSFunction* callee, // Null if this is a closure call.
VirtualRegister returnValueVR,
VirtualRegister inlineCallFrameStart,
int argumentCountIncludingThis,
@@ -3529,14 +3529,14 @@
if (m_caller) {
// Inline case.
ASSERT(codeBlock != byteCodeParser->m_codeBlock);
- ASSERT(callee);
ASSERT(inlineCallFrameStart != InvalidVirtualRegister);
ASSERT(callsiteBlockHead != NoBlock);
InlineCallFrame inlineCallFrame;
inlineCallFrame.executable.set(*byteCodeParser->m_globalData, byteCodeParser->m_codeBlock->ownerExecutable(), codeBlock->ownerExecutable());
inlineCallFrame.stackOffset = inlineCallFrameStart + JSStack::CallFrameHeaderSize;
- inlineCallFrame.callee.set(*byteCodeParser->m_globalData, byteCodeParser->m_codeBlock->ownerExecutable(), callee);
+ if (callee)
+ inlineCallFrame.callee.set(*byteCodeParser->m_globalData, byteCodeParser->m_codeBlock->ownerExecutable(), callee);
inlineCallFrame.caller = byteCodeParser->currentCodeOrigin();
inlineCallFrame.arguments.resize(argumentCountIncludingThis); // Set the number of arguments including this, but don't configure the value recoveries, yet.
inlineCallFrame.isCall = isCall(kind);
Modified: trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp (138668 => 138669)
--- trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2013-01-02 23:54:21 UTC (rev 138668)
+++ trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2013-01-02 23:54:42 UTC (rev 138669)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -88,8 +88,10 @@
#endif
return result;
}
-
- NodeIndex pureCSE(Node& node)
+
+ enum InlineCallFrameRequirement { RequireSameInlineCallFrame, DoNotCareAboutInlineCallFrame };
+ template<InlineCallFrameRequirement inlineCallFrameRequirement>
+ NodeIndex genericPureCSE(Node& node)
{
NodeIndex child1 = canonicalize(node.child1());
NodeIndex child2 = canonicalize(node.child2());
@@ -110,6 +112,10 @@
if (node.arithNodeFlags() != otherNode.arithNodeFlags())
continue;
+ if (inlineCallFrameRequirement == RequireSameInlineCallFrame
+ && node.codeOrigin.inlineCallFrame != otherNode.codeOrigin.inlineCallFrame)
+ continue;
+
NodeIndex otherChild = canonicalize(otherNode.child1());
if (otherChild == NoNode)
return index;
@@ -133,6 +139,16 @@
return NoNode;
}
+ NodeIndex pureCSE(Node& node)
+ {
+ return genericPureCSE<DoNotCareAboutInlineCallFrame>(node);
+ }
+
+ NodeIndex pureCSERequiringSameInlineCallFrame(Node& node)
+ {
+ return genericPureCSE<RequireSameInlineCallFrame>(node);
+ }
+
NodeIndex constantCSE(Node& node)
{
for (unsigned i = endIndexForPureCSE(); i--;) {
@@ -799,13 +815,15 @@
return NoNode;
}
- NodeIndex getMyScopeLoadElimination()
+ NodeIndex getMyScopeLoadElimination(InlineCallFrame* inlineCallFrame)
{
for (unsigned i = m_indexInBlock; i--;) {
NodeIndex index = m_currentBlock->at(i);
Node& node = m_graph[index];
if (!node.shouldGenerate())
continue;
+ if (node.codeOrigin.inlineCallFrame != inlineCallFrame)
+ continue;
switch (node.op()) {
case CreateActivation:
// This may cause us to return a different scope.
@@ -1112,7 +1130,6 @@
case ArithMin:
case ArithMax:
case ArithSqrt:
- case GetCallee:
case StringCharAt:
case StringCharCodeAt:
case Int32ToDouble:
@@ -1130,6 +1147,10 @@
setReplacement(pureCSE(node));
break;
+ case GetCallee:
+ setReplacement(pureCSERequiringSameInlineCallFrame(node));
+ break;
+
case GetLocal: {
VariableAccessData* variableAccessData = node.variableAccessData();
if (!variableAccessData->isCaptured())
@@ -1241,7 +1262,7 @@
break;
case GetMyScope:
- setReplacement(getMyScopeLoadElimination());
+ setReplacement(getMyScopeLoadElimination(node.codeOrigin.inlineCallFrame));
break;
// Handle nodes that are conditionally pure: these are pure, and can
Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler32_64.cpp (138668 => 138669)
--- trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler32_64.cpp 2013-01-02 23:54:21 UTC (rev 138668)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler32_64.cpp 2013-01-02 23:54:42 UTC (rev 138669)
@@ -656,13 +656,15 @@
m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(baselineCodeBlock), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::CodeBlock)));
m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ScopeChain)));
- m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->callee->scope()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ScopeChain)));
+ if (!inlineCallFrame->isClosureCall())
+ m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->callee->scope()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ScopeChain)));
m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::CallerFrame)));
m_jit.storePtr(callerFrameGPR, AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::CallerFrame)));
m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ReturnPC)));
m_jit.store32(AssemblyHelpers::TrustedImm32(inlineCallFrame->arguments.size()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount)));
m_jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::Callee)));
- m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->callee.get()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::Callee)));
+ if (!inlineCallFrame->isClosureCall())
+ m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->callee.get()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::Callee)));
}
// 14) Create arguments if necessary and place them into the appropriate aliased
Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler64.cpp (138668 => 138669)
--- trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler64.cpp 2013-01-02 23:54:21 UTC (rev 138668)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler64.cpp 2013-01-02 23:54:42 UTC (rev 138669)
@@ -623,11 +623,13 @@
callerFrameGPR = GPRInfo::callFrameRegister;
m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(baselineCodeBlock), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::CodeBlock)));
- m_jit.store64(AssemblyHelpers::TrustedImm64(JSValue::encode(JSValue(inlineCallFrame->callee->scope()))), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ScopeChain)));
+ if (!inlineCallFrame->isClosureCall())
+ m_jit.store64(AssemblyHelpers::TrustedImm64(JSValue::encode(JSValue(inlineCallFrame->callee->scope()))), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ScopeChain)));
m_jit.store64(callerFrameGPR, AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::CallerFrame)));
m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ReturnPC)));
m_jit.store32(AssemblyHelpers::TrustedImm32(inlineCallFrame->arguments.size()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount)));
- m_jit.store64(AssemblyHelpers::TrustedImm64(JSValue::encode(JSValue(inlineCallFrame->callee.get()))), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::Callee)));
+ if (!inlineCallFrame->isClosureCall())
+ m_jit.store64(AssemblyHelpers::TrustedImm64(JSValue::encode(JSValue(inlineCallFrame->callee.get()))), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::Callee)));
}
// 15) Create arguments if necessary and place them into the appropriate aliased
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (138668 => 138669)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2013-01-02 23:54:21 UTC (rev 138668)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2013-01-02 23:54:42 UTC (rev 138669)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
* Copyright (C) 2011 Intel Corporation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -3964,7 +3964,7 @@
case GetCallee: {
GPRTemporary result(this);
- m_jit.loadPtr(JITCompiler::payloadFor(static_cast<VirtualRegister>(JSStack::Callee)), result.gpr());
+ m_jit.loadPtr(JITCompiler::payloadFor(static_cast<VirtualRegister>(node.codeOrigin.stackOffset() + static_cast<int>(JSStack::Callee))), result.gpr());
cellResult(result.gpr(), m_compileIndex);
break;
}
@@ -3973,7 +3973,7 @@
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
- m_jit.loadPtr(JITCompiler::payloadFor(static_cast<VirtualRegister>(JSStack::ScopeChain)), resultGPR);
+ m_jit.loadPtr(JITCompiler::payloadFor(static_cast<VirtualRegister>(node.codeOrigin.stackOffset() + static_cast<int>(JSStack::ScopeChain))), resultGPR);
cellResult(resultGPR, m_compileIndex);
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (138668 => 138669)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2013-01-02 23:54:21 UTC (rev 138668)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2013-01-02 23:54:42 UTC (rev 138669)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -3916,7 +3916,7 @@
case GetCallee: {
GPRTemporary result(this);
- m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(JSStack::Callee)), result.gpr());
+ m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(node.codeOrigin.stackOffset() + static_cast<int>(JSStack::Callee))), result.gpr());
cellResult(result.gpr(), m_compileIndex);
break;
}
@@ -3925,7 +3925,7 @@
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
- m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(JSStack::ScopeChain)), resultGPR);
+ m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(node.codeOrigin.stackOffset() + static_cast<int>(JSStack::ScopeChain))), resultGPR);
cellResult(resultGPR, m_compileIndex);
break;
}
Modified: trunk/Source/_javascript_Core/interpreter/CallFrame.cpp (138668 => 138669)
--- trunk/Source/_javascript_Core/interpreter/CallFrame.cpp 2013-01-02 23:54:21 UTC (rev 138668)
+++ trunk/Source/_javascript_Core/interpreter/CallFrame.cpp 2013-01-02 23:54:42 UTC (rev 138669)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2013 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -138,8 +138,8 @@
// Fill in the inlinedCaller
inlinedCaller->setCodeBlock(machineCodeBlock);
-
- inlinedCaller->setScope(calleeAsFunction->scope());
+ if (calleeAsFunction)
+ inlinedCaller->setScope(calleeAsFunction->scope());
if (nextInlineCallFrame)
inlinedCaller->setCallerFrame(this + nextInlineCallFrame->stackOffset);
else
@@ -147,7 +147,8 @@
inlinedCaller->setInlineCallFrame(inlineCallFrame);
inlinedCaller->setArgumentCountIncludingThis(inlineCallFrame->arguments.size());
- inlinedCaller->setCallee(calleeAsFunction);
+ if (calleeAsFunction)
+ inlinedCaller->setCallee(calleeAsFunction);
inlineCallFrame = nextInlineCallFrame;
}