Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (136275 => 136276)
--- trunk/Source/_javascript_Core/ChangeLog 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-11-30 21:56:24 UTC (rev 136276)
@@ -1,3 +1,83 @@
+2012-11-30 Filip Pizlo <[email protected]>
+
+ Rationalize and clean up DFG handling of scoped accesses
+ https://bugs.webkit.org/show_bug.cgi?id=103715
+
+ Reviewed by Oliver Hunt.
+
+ Previously, we had a GetScope node that specified the depth to which you wanted
+ to travel to get a JSScope, and the backend implementation of the node would
+ perform all of the necessary footwork, including potentially skipping the top
+ scope if necessary, and doing however many loads were needed. But there were
+ strange things. First, if you had accesses at different scope depths, then the
+ loads to get to the common depth could not be CSE'd - CSE would match only
+ GetScope's that had identical depth. Second, GetScope would be emitted even if
+ we already had the scope, for example in put_to_base. And finally, even though
+ the ResolveOperations could tell us whether or not we had to skip the top scope,
+ the backend would recompute this information itself, often pessimistically.
+
+ This eliminates GetScope and replaces it with the following:
+
+ GetMyScope: just get the JSScope from the call frame header. This will forever
+ mean getting the JSScope associated with the machine call frame; it will not
+ mean getting the scope of an inlined function. Or at least that's the intent.
+
+ SkipTopScope: check if there is an activation, and if so, skip a scope. This
+ takes a scope as a child and returns a scope.
+
+ SkipScope: skip one scope level.
+
+ The bytecode parser now emits the right combination of the above, and
+ potentially emits multiple SkipScope's, based on the ResolveOperations.
+
+ This change also includes some fixups to debug logging. We now always print
+ the ExecutableBase* in addition to the CodeBlock* in the CodeBlock's dump,
+ and we are now more verbose when dumping CodeOrigins and InlineCallFrames.
+
+ This is performance-neutral. It's just meant to be a clean-up.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dumpAssumingJITType):
+ * bytecode/CodeOrigin.cpp:
+ (JSC::CodeOrigin::inlineStack):
+ (JSC::CodeOrigin::dump):
+ (JSC):
+ (JSC::InlineCallFrame::dump):
+ * bytecode/CodeOrigin.h:
+ (CodeOrigin):
+ (InlineCallFrame):
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGByteCodeParser.cpp:
+ (ByteCodeParser):
+ (JSC::DFG::ByteCodeParser::getScope):
+ (DFG):
+ (JSC::DFG::ByteCodeParser::parseResolveOperations):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCSEPhase.cpp:
+ (JSC::DFG::CSEPhase::scopedVarLoadElimination):
+ (JSC::DFG::CSEPhase::scopedVarStoreElimination):
+ (JSC::DFG::CSEPhase::getMyScopeLoadElimination):
+ (JSC::DFG::CSEPhase::setLocalStoreElimination):
+ (JSC::DFG::CSEPhase::performNodeCSE):
+ * dfg/DFGDisassembler.cpp:
+ (JSC::DFG::Disassembler::dump):
+ * dfg/DFGGraph.cpp:
+ (JSC::DFG::Graph::dumpCodeOrigin):
+ (JSC::DFG::Graph::dumpBlockHeader):
+ * dfg/DFGNode.h:
+ (Node):
+ * dfg/DFGNodeType.h:
+ (DFG):
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * jit/JITDisassembler.cpp:
+ (JSC::JITDisassembler::dump):
+
2012-11-30 Oliver Hunt <[email protected]>
Add direct string->function code cache
Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (136275 => 136276)
--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2012-11-30 21:56:24 UTC (rev 136276)
@@ -69,7 +69,7 @@
void CodeBlock::dumpAssumingJITType(PrintStream& out, JITCode::JITType jitType) const
{
- out.print("#", hash(), ":[", RawPointer(this), ", ", jitType, codeType());
+ out.print("#", hash(), ":[", RawPointer(this), "->", RawPointer(ownerExecutable()), ", ", jitType, codeType());
if (codeType() == FunctionCode)
out.print(specializationKind());
out.print("]");
Modified: trunk/Source/_javascript_Core/bytecode/CodeOrigin.cpp (136275 => 136276)
--- trunk/Source/_javascript_Core/bytecode/CodeOrigin.cpp 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/bytecode/CodeOrigin.cpp 2012-11-30 21:56:24 UTC (rev 136276)
@@ -50,13 +50,33 @@
unsigned index = result.size() - 2;
for (InlineCallFrame* current = inlineCallFrame; current; current = current->caller.inlineCallFrame)
result[index--] = current->caller;
+ ASSERT(!result[0].inlineCallFrame);
return result;
}
+void CodeOrigin::dump(PrintStream& out) const
+{
+ Vector<CodeOrigin> stack = inlineStack();
+ for (unsigned i = 0; i < stack.size(); ++i) {
+ if (i)
+ out.print(" --> ");
+
+ if (InlineCallFrame* frame = stack[i].inlineCallFrame)
+ out.print("#", frame->hash(), ":<", RawPointer(frame->executable.get()), "> ");
+
+ out.print("bc#", stack[i].bytecodeIndex);
+ }
+}
+
CodeBlockHash InlineCallFrame::hash() const
{
return executable->hashFor(specializationKind());
}
+void InlineCallFrame::dump(PrintStream& out) const
+{
+ out.print("#", hash(), ":<", RawPointer(executable.get()), ", bc#", caller.bytecodeIndex, ", ", specializationKind(), ">");
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/bytecode/CodeOrigin.h (136275 => 136276)
--- trunk/Source/_javascript_Core/bytecode/CodeOrigin.h 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/bytecode/CodeOrigin.h 2012-11-30 21:56:24 UTC (rev 136276)
@@ -31,6 +31,7 @@
#include "ValueRecovery.h"
#include "WriteBarrier.h"
#include <wtf/BitVector.h>
+#include <wtf/PrintStream.h>
#include <wtf/StdLibExtras.h>
#include <wtf/Vector.h>
@@ -90,6 +91,8 @@
// Get the inline stack. This is slow, and is intended for debugging only.
Vector<CodeOrigin> inlineStack() const;
+
+ void dump(PrintStream&) const;
};
struct InlineCallFrame {
@@ -104,6 +107,8 @@
CodeSpecializationKind specializationKind() const { return specializationFromIsCall(isCall); }
CodeBlockHash hash() const;
+
+ void dump(PrintStream&) const;
};
struct CodeOriginAtCallReturnOffset {
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (136275 => 136276)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-11-30 21:56:24 UTC (rev 136276)
@@ -1383,7 +1383,9 @@
forNode(nodeIndex).set(SpecFunction);
break;
- case GetScope:
+ case GetMyScope:
+ case SkipTopScope:
+ case SkipScope:
node.setCanExit(false);
forNode(nodeIndex).set(SpecCellOther);
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (136275 => 136276)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2012-11-30 21:56:24 UTC (rev 136276)
@@ -176,6 +176,8 @@
int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber,
const GetByIdStatus&);
+ NodeIndex getScope(bool skipTop, unsigned skipCount);
+
// Convert a set of ResolveOperations into graph nodes
bool parseResolveOperations(SpeculatedType, unsigned identifierNumber, unsigned operations, unsigned putToBaseOperation, NodeIndex* base, NodeIndex* value);
@@ -1882,6 +1884,16 @@
m_cellConstantNodes.clear();
}
+NodeIndex ByteCodeParser::getScope(bool skipTop, unsigned skipCount)
+{
+ NodeIndex localBase = addToGraph(GetMyScope);
+ if (skipTop)
+ localBase = addToGraph(SkipTopScope, localBase);
+ for (unsigned n = skipCount; n--;)
+ localBase = addToGraph(SkipScope, localBase);
+ return localBase;
+}
+
bool ByteCodeParser::parseResolveOperations(SpeculatedType prediction, unsigned identifier, unsigned operations, unsigned putToBaseOperation, NodeIndex* base, NodeIndex* value)
{
ResolveOperations* resolveOperations = m_codeBlock->resolveOperations(operations);
@@ -1891,6 +1903,7 @@
}
JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
int skipCount = 0;
+ bool skipTop = false;
bool skippedScopes = false;
bool setBase = false;
ResolveOperation* pc = resolveOperations->data();
@@ -1918,7 +1931,7 @@
break;
case ResolveOperation::SetBaseToScope:
- localBase = addToGraph(GetScope, OpInfo(skipCount));
+ localBase = getScope(skipTop, skipCount);
*base = localBase;
setBase = true;
@@ -1929,21 +1942,19 @@
++pc;
break;
case ResolveOperation::ReturnScopeAsBase:
- *base = addToGraph(GetScope, OpInfo(skipCount));
+ *base = getScope(skipTop, skipCount);
ASSERT(!value);
return true;
case ResolveOperation::SkipTopScopeNode:
- if (m_inlineStackTop->m_inlineCallFrame)
- return false;
- skipCount = 1;
+ ASSERT(!m_inlineStackTop->m_inlineCallFrame);
+ skipTop = true;
skippedScopes = true;
++pc;
break;
case ResolveOperation::SkipScopes:
- if (m_inlineStackTop->m_inlineCallFrame)
- return false;
+ ASSERT(!m_inlineStackTop->m_inlineCallFrame);
skipCount += pc->m_scopesToSkip;
skippedScopes = true;
++pc;
@@ -1960,7 +1971,7 @@
}
}
if (skippedScopes)
- localBase = addToGraph(GetScope, OpInfo(skipCount));
+ localBase = getScope(skipTop, skipCount);
if (base && !setBase)
*base = localBase;
@@ -3050,10 +3061,9 @@
get(value));
break;
case PutToBaseOperation::VariablePut: {
- addToGraph(Phantom, get(base));
- NodeIndex getScope = addToGraph(GetScope, OpInfo(putToBase->m_scopeDepth));
- NodeIndex getScopeRegisters = addToGraph(GetScopeRegisters, getScope);
- addToGraph(PutScopedVar, OpInfo(putToBase->m_offset), getScope, getScopeRegisters, get(value));
+ NodeIndex scope = get(base);
+ NodeIndex scopeRegisters = addToGraph(GetScopeRegisters, scope);
+ addToGraph(PutScopedVar, OpInfo(putToBase->m_offset), scope, scopeRegisters, get(value));
break;
}
case PutToBaseOperation::GlobalPropertyPut: {
Modified: trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp (136275 => 136276)
--- trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2012-11-30 21:56:24 UTC (rev 136276)
@@ -213,7 +213,7 @@
return NoNode;
}
- NodeIndex scopedVarLoadElimination(unsigned scopeChainDepth, unsigned varNumber)
+ NodeIndex scopedVarLoadElimination(NodeIndex registers, unsigned varNumber)
{
for (unsigned i = m_indexInBlock; i--;) {
NodeIndex index = m_currentBlock->at(i);
@@ -222,15 +222,12 @@
continue;
switch (node.op()) {
case GetScopedVar: {
- Node& getScopeRegisters = m_graph[node.child1()];
- Node& getScope = m_graph[getScopeRegisters.child1()];
- if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
+ if (node.child1() == registers && node.varNumber() == varNumber)
return index;
break;
}
case PutScopedVar: {
- Node& getScope = m_graph[node.child1()];
- if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
+ if (node.child2() == registers && node.varNumber() == varNumber)
return node.child3().index();
break;
}
@@ -296,7 +293,7 @@
return NoNode;
}
- NodeIndex scopedVarStoreElimination(unsigned scopeChainDepth, unsigned varNumber)
+ NodeIndex scopedVarStoreElimination(NodeIndex scope, NodeIndex registers, unsigned varNumber)
{
for (unsigned i = m_indexInBlock; i--;) {
NodeIndex index = m_currentBlock->at(i);
@@ -305,16 +302,14 @@
continue;
switch (node.op()) {
case PutScopedVar: {
- Node& getScope = m_graph[node.child1()];
- if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
+ if (node.child1() == scope && node.child2() == registers && node.varNumber() == varNumber)
return index;
break;
}
case GetScopedVar: {
- Node& getScopeRegisters = m_graph[node.child1()];
- Node& getScope = m_graph[getScopeRegisters.child1()];
- if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
+ // Let's be conservative.
+ if (node.varNumber() == varNumber)
return NoNode;
break;
}
@@ -779,33 +774,25 @@
return NoNode;
}
- NodeIndex getScopeLoadElimination(unsigned depth)
+ NodeIndex getMyScopeLoadElimination()
{
- for (unsigned i = endIndexForPureCSE(); i--;) {
+ for (unsigned i = m_indexInBlock; i--;) {
NodeIndex index = m_currentBlock->at(i);
Node& node = m_graph[index];
if (!node.shouldGenerate())
continue;
- if (node.op() == GetScope
- && node.scopeChainDepth() == depth)
+ switch (node.op()) {
+ case CreateActivation:
+ // This may cause us to return a different scope.
+ return NoNode;
+ case GetMyScope:
return index;
+ default:
+ break;
+ }
}
return NoNode;
}
-
- NodeIndex getScopeRegistersLoadElimination(unsigned depth)
- {
- for (unsigned i = endIndexForPureCSE(); i--;) {
- NodeIndex index = m_currentBlock->at(i);
- Node& node = m_graph[index];
- if (!node.shouldGenerate())
- continue;
- if (node.op() == GetScopeRegisters
- && m_graph[node.scope()].scopeChainDepth() == depth)
- return index;
- }
- return NoNode;
- }
NodeIndex getLocalLoadElimination(VirtualRegister local, NodeIndex& relevantLocalOp, bool careAboutClobbering)
{
@@ -890,7 +877,8 @@
return result;
}
- case GetScope:
+ case GetMyScope:
+ case SkipTopScope:
case GetScopeRegisters:
if (m_graph.uncheckedActivationRegisterFor(node.codeOrigin) == local)
result.mayBeAccessed = true;
@@ -1076,6 +1064,9 @@
case IsFunction:
case DoubleAsInt32:
case LogicalNot:
+ case SkipTopScope:
+ case SkipScope:
+ case GetScopeRegisters:
setReplacement(pureCSE(node));
break;
@@ -1189,14 +1180,10 @@
setReplacement(getArrayLengthElimination(node.child1().index()));
break;
- case GetScope:
- setReplacement(getScopeLoadElimination(node.scopeChainDepth()));
+ case GetMyScope:
+ setReplacement(getMyScopeLoadElimination());
break;
-
- case GetScopeRegisters:
- setReplacement(getScopeRegistersLoadElimination(m_graph[node.scope()].scopeChainDepth()));
- break;
-
+
// Handle nodes that are conditionally pure: these are pure, and can
// be CSE'd, so long as the prediction is the one we want.
case ValueAdd:
@@ -1220,9 +1207,7 @@
break;
case GetScopedVar: {
- Node& getScopeRegisters = m_graph[node.child1()];
- Node& getScope = m_graph[getScopeRegisters.child1()];
- setReplacement(scopedVarLoadElimination(getScope.scopeChainDepth(), node.varNumber()));
+ setReplacement(scopedVarLoadElimination(node.child1().index(), node.varNumber()));
break;
}
@@ -1241,8 +1226,7 @@
case PutScopedVar: {
if (m_graph.m_fixpointState == FixpointNotConverged)
break;
- Node& getScope = m_graph[node.child1()];
- eliminate(scopedVarStoreElimination(getScope.scopeChainDepth(), node.varNumber()));
+ eliminate(scopedVarStoreElimination(node.child1().index(), node.child2().index(), node.varNumber()));
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGDisassembler.cpp (136275 => 136276)
--- trunk/Source/_javascript_Core/dfg/DFGDisassembler.cpp 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/dfg/DFGDisassembler.cpp 2012-11-30 21:56:24 UTC (rev 136276)
@@ -44,7 +44,7 @@
{
m_graph.m_dominators.computeIfNecessary(m_graph);
- out.print("Generated JIT code for ", CodeBlockWithJITType(m_graph.m_codeBlock, JITCode::DFGJIT), ", instruction count = ", m_graph.m_codeBlock->instructionCount(), ":\n");
+ out.print("Generated DFG JIT code for ", CodeBlockWithJITType(m_graph.m_codeBlock, JITCode::DFGJIT), ", instruction count = ", m_graph.m_codeBlock->instructionCount(), ":\n");
out.print(" Code at [", RawPointer(linkBuffer.debugAddress()), ", ", RawPointer(static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize()), "):\n");
const char* prefix = " ";
Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.cpp (136275 => 136276)
--- trunk/Source/_javascript_Core/dfg/DFGGraph.cpp 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.cpp 2012-11-30 21:56:24 UTC (rev 136276)
@@ -88,14 +88,14 @@
for (unsigned i = previousInlineStack.size(); i-- > indexOfDivergence;) {
out.print(prefix);
printWhiteSpace(out, i * 2);
- out.print("<-- #", previousInlineStack[i].inlineCallFrame->hash(), "\n");
+ out.print("<-- ", *previousInlineStack[i].inlineCallFrame, "\n");
}
// Print the pushes.
for (unsigned i = indexOfDivergence; i < currentInlineStack.size(); ++i) {
out.print(prefix);
printWhiteSpace(out, i * 2);
- out.print("--> #", currentInlineStack[i].inlineCallFrame->hash(), "\n");
+ out.print("--> ", *currentInlineStack[i].inlineCallFrame, "\n");
}
}
@@ -294,7 +294,7 @@
{
BasicBlock* block = m_blocks[blockIndex].get();
- out.print(prefix, "Block #", blockIndex, " (bc#", block->bytecodeBegin, "): ", block->isReachable ? "" : "(skipped)", block->isOSRTarget ? " (OSR target)" : "", "\n");
+ out.print(prefix, "Block #", blockIndex, " (", at(block->at(0)).codeOrigin, "): ", block->isReachable ? "" : "(skipped)", block->isOSRTarget ? " (OSR target)" : "", "\n");
out.print(prefix, " Predecessors:");
for (size_t i = 0; i < block->m_predecessors.size(); ++i)
out.print(" #", block->m_predecessors[i]);
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (136275 => 136276)
--- trunk/Source/_javascript_Core/dfg/DFGNode.h 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h 2012-11-30 21:56:24 UTC (rev 136276)
@@ -523,23 +523,6 @@
return bitwise_cast<WriteBarrier<Unknown>*>(m_opInfo);
}
- bool hasScopeChainDepth()
- {
- return op() == GetScope;
- }
-
- unsigned scopeChainDepth()
- {
- ASSERT(hasScopeChainDepth());
- return m_opInfo;
- }
-
- Edge scope()
- {
- ASSERT(op() == GetScopeRegisters);
- return child1();
- }
-
bool hasResult()
{
return m_flags & NodeResultMask;
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (136275 => 136276)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2012-11-30 21:56:24 UTC (rev 136276)
@@ -150,7 +150,9 @@
macro(GetByOffset, NodeResultJS) \
macro(PutByOffset, NodeMustGenerate) \
macro(GetArrayLength, NodeResultInt32) \
- macro(GetScope, NodeResultJS) \
+ macro(GetMyScope, NodeResultJS) \
+ macro(SkipTopScope, NodeResultJS) \
+ macro(SkipScope, NodeResultJS) \
macro(GetScopeRegisters, NodeResultStorage) \
macro(GetScopedVar, NodeResultJS) \
macro(PutScopedVar, NodeMustGenerate) \
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (136275 => 136276)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2012-11-30 21:56:24 UTC (rev 136276)
@@ -594,7 +594,9 @@
break;
}
- case GetScope: {
+ case GetMyScope:
+ case SkipTopScope:
+ case SkipScope: {
changed |= setPrediction(SpecCellOther);
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (136275 => 136276)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2012-11-30 21:56:24 UTC (rev 136276)
@@ -3967,32 +3967,44 @@
case GetCallee: {
GPRTemporary result(this);
- m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(JSStack::Callee)), result.gpr());
+ m_jit.loadPtr(JITCompiler::payloadFor(static_cast<VirtualRegister>(JSStack::Callee)), result.gpr());
cellResult(result.gpr(), m_compileIndex);
break;
}
-
- case GetScope: {
+
+ case GetMyScope: {
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
- m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(JSStack::ScopeChain)), resultGPR);
- bool checkTopLevel = m_jit.codeBlock()->codeType() == FunctionCode && m_jit.codeBlock()->needsFullScopeChain();
- int skip = node.scopeChainDepth();
- ASSERT(skip || !checkTopLevel);
- if (checkTopLevel && skip--) {
- JITCompiler::Jump activationNotCreated;
- if (checkTopLevel)
- activationNotCreated = m_jit.branchTestPtr(JITCompiler::Zero, JITCompiler::addressFor(static_cast<VirtualRegister>(m_jit.codeBlock()->activationRegister())));
- m_jit.loadPtr(JITCompiler::Address(resultGPR, JSScope::offsetOfNext()), resultGPR);
- activationNotCreated.link(&m_jit);
- }
- while (skip--)
- m_jit.loadPtr(JITCompiler::Address(resultGPR, JSScope::offsetOfNext()), resultGPR);
+ m_jit.loadPtr(JITCompiler::payloadFor(static_cast<VirtualRegister>(JSStack::ScopeChain)), resultGPR);
+ cellResult(resultGPR, m_compileIndex);
+ break;
+ }
+ case SkipTopScope: {
+ SpeculateCellOperand scope(this, node.child1());
+ GPRTemporary result(this, scope);
+ GPRReg resultGPR = result.gpr();
+ m_jit.move(scope.gpr(), resultGPR);
+ JITCompiler::Jump activationNotCreated =
+ m_jit.branchTestPtr(
+ JITCompiler::Zero,
+ JITCompiler::payloadFor(
+ static_cast<VirtualRegister>(m_jit.codeBlock()->activationRegister())));
+ m_jit.loadPtr(JITCompiler::Address(resultGPR, JSScope::offsetOfNext()), resultGPR);
+ activationNotCreated.link(&m_jit);
cellResult(resultGPR, m_compileIndex);
break;
}
+
+ case SkipScope: {
+ SpeculateCellOperand scope(this, node.child1());
+ GPRTemporary result(this, scope);
+ m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSScope::offsetOfNext()), result.gpr());
+ cellResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
case GetScopeRegisters: {
SpeculateCellOperand scope(this, node.child1());
GPRTemporary result(this);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (136275 => 136276)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2012-11-30 21:56:24 UTC (rev 136276)
@@ -3923,28 +3923,40 @@
cellResult(result.gpr(), m_compileIndex);
break;
}
-
- case GetScope: {
+
+ case GetMyScope: {
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(JSStack::ScopeChain)), resultGPR);
- bool checkTopLevel = m_jit.codeBlock()->codeType() == FunctionCode && m_jit.codeBlock()->needsFullScopeChain();
- int skip = node.scopeChainDepth();
- ASSERT(skip || !checkTopLevel);
- if (checkTopLevel && skip--) {
- JITCompiler::Jump activationNotCreated;
- if (checkTopLevel)
- activationNotCreated = m_jit.branchTest64(JITCompiler::Zero, JITCompiler::addressFor(static_cast<VirtualRegister>(m_jit.codeBlock()->activationRegister())));
- m_jit.loadPtr(JITCompiler::Address(resultGPR, JSScope::offsetOfNext()), resultGPR);
- activationNotCreated.link(&m_jit);
- }
- while (skip--)
- m_jit.loadPtr(JITCompiler::Address(resultGPR, JSScope::offsetOfNext()), resultGPR);
+ cellResult(resultGPR, m_compileIndex);
+ break;
+ }
+ case SkipTopScope: {
+ SpeculateCellOperand scope(this, node.child1());
+ GPRTemporary result(this, scope);
+ GPRReg resultGPR = result.gpr();
+ m_jit.move(scope.gpr(), resultGPR);
+ JITCompiler::Jump activationNotCreated =
+ m_jit.branchTest64(
+ JITCompiler::Zero,
+ JITCompiler::addressFor(
+ static_cast<VirtualRegister>(m_jit.codeBlock()->activationRegister())));
+ m_jit.loadPtr(JITCompiler::Address(resultGPR, JSScope::offsetOfNext()), resultGPR);
+ activationNotCreated.link(&m_jit);
cellResult(resultGPR, m_compileIndex);
break;
}
+
+ case SkipScope: {
+ SpeculateCellOperand scope(this, node.child1());
+ GPRTemporary result(this, scope);
+ m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSScope::offsetOfNext()), result.gpr());
+ cellResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
case GetScopeRegisters: {
SpeculateCellOperand scope(this, node.child1());
GPRTemporary result(this);
Modified: trunk/Source/_javascript_Core/jit/JITDisassembler.cpp (136275 => 136276)
--- trunk/Source/_javascript_Core/jit/JITDisassembler.cpp 2012-11-30 21:54:51 UTC (rev 136275)
+++ trunk/Source/_javascript_Core/jit/JITDisassembler.cpp 2012-11-30 21:56:24 UTC (rev 136276)
@@ -47,7 +47,7 @@
void JITDisassembler::dump(PrintStream& out, LinkBuffer& linkBuffer)
{
- out.print("Baseline JIT code for ", CodeBlockWithJITType(m_codeBlock, JITCode::BaselineJIT), ", instruction count = ", m_codeBlock->instructionCount(), "\n");
+ out.print("Generated Baseline JIT code for ", CodeBlockWithJITType(m_codeBlock, JITCode::BaselineJIT), ", instruction count = ", m_codeBlock->instructionCount(), "\n");
out.print(" Code at [", RawPointer(linkBuffer.debugAddress()), ", ", RawPointer(static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize()), "):\n");
dumpDisassembly(out, linkBuffer, m_startOfCode, m_labelForBytecodeIndexInMainPath[0]);