summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp12
-rw-r--r--Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp4
-rw-r--r--Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h19
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp27
-rw-r--r--Source/JavaScriptCore/dfg/DFGCSEPhase.cpp165
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h6
-rw-r--r--Source/JavaScriptCore/dfg/DFGNode.h8
-rw-r--r--Source/JavaScriptCore/dfg/DFGNodeType.h9
-rw-r--r--Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp5
-rw-r--r--Source/JavaScriptCore/dfg/DFGRepatch.cpp19
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp5
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp112
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp96
13 files changed, 380 insertions, 107 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 50b9e2b9f..18b5ad02a 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -1262,11 +1262,17 @@ bool AbstractState::execute(unsigned indexInBlock)
forNode(nodeIndex).set(SpecFunction);
break;
- case GetScopeChain:
+ case GetScope:
node.setCanExit(false);
forNode(nodeIndex).set(SpecCellOther);
break;
-
+
+ case GetScopeRegisters:
+ node.setCanExit(false);
+ forNode(node.child1()).filter(SpecCell);
+ forNode(nodeIndex).clear(); // The result is not a JS value.
+ break;
+
case GetScopedVar:
node.setCanExit(false);
forNode(nodeIndex).makeTop();
@@ -1477,7 +1483,7 @@ bool AbstractState::execute(unsigned indexInBlock)
// Again, sadly, we don't propagate the fact that we've done InstanceOf
if (!(m_graph[node.child1()].prediction() & ~SpecCell) && !(forNode(node.child1()).m_type & ~SpecCell))
forNode(node.child1()).filter(SpecCell);
- forNode(node.child3()).filter(SpecCell);
+ forNode(node.child2()).filter(SpecCell);
forNode(nodeIndex).set(SpecBoolean);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
index ba6673963..513357424 100644
--- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
@@ -584,8 +584,8 @@ public:
node.convertToGetLocalUnlinked(
static_cast<VirtualRegister>(
node.codeOrigin.inlineCallFrame->stackOffset +
- argumentToOperand(index + 1)));
-
+ m_graph.baselineCodeBlockFor(node.codeOrigin)->argumentIndexAfterCapture(index)));
+
NodeIndex checkNodeIndex = m_graph.size();
m_graph.append(check);
insertionSet.append(indexInBlock, checkNodeIndex);
diff --git a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
index 57f758c9c..a2003c5bf 100644
--- a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
+++ b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
@@ -343,6 +343,25 @@ public:
return argumentsRegisterFor(codeOrigin.inlineCallFrame);
}
+ SharedSymbolTable* symbolTableFor(const CodeOrigin& codeOrigin)
+ {
+ return baselineCodeBlockFor(codeOrigin)->symbolTable();
+ }
+
+ int offsetOfLocals(const CodeOrigin& codeOrigin)
+ {
+ if (!codeOrigin.inlineCallFrame)
+ return 0;
+ return codeOrigin.inlineCallFrame->stackOffset * sizeof(Register);
+ }
+
+ int offsetOfArgumentsIncludingThis(const CodeOrigin& codeOrigin)
+ {
+ if (!codeOrigin.inlineCallFrame)
+ return CallFrame::argumentOffsetIncludingThis(0) * sizeof(Register);
+ return (codeOrigin.inlineCallFrame->stackOffset + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register);
+ }
+
Vector<BytecodeAndMachineOffset>& decodedCodeMapFor(CodeBlock*);
static const double twoToThe32;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index fb897ff5b..901b67b19 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -467,8 +467,11 @@ private:
numArguments = m_inlineStackTop->m_codeBlock->numParameters();
for (unsigned argument = numArguments; argument-- > 1;)
flush(argumentToOperand(argument));
- for (unsigned local = m_inlineStackTop->m_codeBlock->m_numCapturedVars; local--;)
+ for (int local = 0; local < m_inlineStackTop->m_codeBlock->m_numVars; ++local) {
+ if (!m_inlineStackTop->m_codeBlock->isCaptured(local))
+ continue;
flush(local);
+ }
}
// Get an operand, and perform a ToInt32/ToNumber conversion on it.
@@ -2049,14 +2052,13 @@ bool ByteCodeParser::parseBlock(unsigned limit)
}
case op_check_has_instance:
- addToGraph(CheckHasInstance, get(currentInstruction[1].u.operand));
+ addToGraph(CheckHasInstance, get(currentInstruction[3].u.operand));
NEXT_OPCODE(op_check_has_instance);
case op_instanceof: {
NodeIndex value = get(currentInstruction[2].u.operand);
- NodeIndex baseValue = get(currentInstruction[3].u.operand);
- NodeIndex prototype = get(currentInstruction[4].u.operand);
- set(currentInstruction[1].u.operand, addToGraph(InstanceOf, value, baseValue, prototype));
+ NodeIndex prototype = get(currentInstruction[3].u.operand);
+ set(currentInstruction[1].u.operand, addToGraph(InstanceOf, value, prototype));
NEXT_OPCODE(op_instanceof);
}
@@ -2263,8 +2265,9 @@ bool ByteCodeParser::parseBlock(unsigned limit)
int dst = currentInstruction[1].u.operand;
int slot = currentInstruction[2].u.operand;
int depth = currentInstruction[3].u.operand;
- NodeIndex getScopeChain = addToGraph(GetScopeChain, OpInfo(depth));
- NodeIndex getScopedVar = addToGraph(GetScopedVar, OpInfo(slot), OpInfo(prediction), getScopeChain);
+ NodeIndex getScope = addToGraph(GetScope, OpInfo(depth));
+ NodeIndex getScopeRegisters = addToGraph(GetScopeRegisters, getScope);
+ NodeIndex getScopedVar = addToGraph(GetScopedVar, OpInfo(slot), OpInfo(prediction), getScopeRegisters);
set(dst, getScopedVar);
NEXT_OPCODE(op_get_scoped_var);
}
@@ -2272,8 +2275,9 @@ bool ByteCodeParser::parseBlock(unsigned limit)
int slot = currentInstruction[1].u.operand;
int depth = currentInstruction[2].u.operand;
int source = currentInstruction[3].u.operand;
- NodeIndex getScopeChain = addToGraph(GetScopeChain, OpInfo(depth));
- addToGraph(PutScopedVar, OpInfo(slot), getScopeChain, get(source));
+ NodeIndex getScope = addToGraph(GetScope, OpInfo(depth));
+ NodeIndex getScopeRegisters = addToGraph(GetScopeRegisters, getScope);
+ addToGraph(PutScopedVar, OpInfo(slot), getScope, getScopeRegisters, get(source));
NEXT_OPCODE(op_put_scoped_var);
}
case op_get_by_id:
@@ -2714,6 +2718,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
case op_call_varargs: {
ASSERT(m_inlineStackTop->m_inlineCallFrame);
ASSERT(currentInstruction[3].u.operand == m_inlineStackTop->m_codeBlock->argumentsRegister());
+ ASSERT(!m_inlineStackTop->m_codeBlock->symbolTable()->slowArguments());
// It would be cool to funnel this into handleCall() so that it can handle
// inlining. But currently that won't be profitable anyway, since none of the
// uses of call_varargs will be inlineable. So we set this up manually and
@@ -3282,10 +3287,10 @@ void ByteCodeParser::parseCodeBlock()
CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock;
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLog("Parsing code block %p. codeType = %s, numCapturedVars = %u, needsFullScopeChain = %s, needsActivation = %s, isStrictMode = %s\n",
+ dataLog("Parsing code block %p. codeType = %s, captureCount = %u, needsFullScopeChain = %s, needsActivation = %s, isStrictMode = %s\n",
codeBlock,
codeTypeToString(codeBlock->codeType()),
- codeBlock->m_numCapturedVars,
+ codeBlock->symbolTable()->captureCount(),
codeBlock->needsFullScopeChain()?"true":"false",
codeBlock->ownerExecutable()->needsActivation()?"true":"false",
codeBlock->ownerExecutable()->isStrictMode()?"true":"false");
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index 111c15f17..cea2f3c48 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -96,6 +96,9 @@ private:
break;
Node& otherNode = m_graph[index];
+ if (!otherNode.shouldGenerate())
+ continue;
+
if (node.op() != otherNode.op())
continue;
@@ -157,38 +160,34 @@ private:
return NoNode;
}
- NodeIndex impureCSE(Node& node)
+ NodeIndex getArrayLengthElimination(NodeIndex array)
{
- NodeIndex child1 = canonicalize(node.child1());
- NodeIndex child2 = canonicalize(node.child2());
- NodeIndex child3 = canonicalize(node.child3());
-
for (unsigned i = m_indexInBlock; i--;) {
NodeIndex index = m_currentBlock->at(i);
- if (index == child1 || index == child2 || index == child3)
- break;
-
- Node& otherNode = m_graph[index];
- if (node.op() == otherNode.op()
- && node.arithNodeFlags() == otherNode.arithNodeFlags()) {
- NodeIndex otherChild = canonicalize(otherNode.child1());
- if (otherChild == NoNode)
+ Node& node = m_graph[index];
+ if (!node.shouldGenerate())
+ continue;
+ switch (node.op()) {
+ case GetArrayLength:
+ if (node.child1() == array)
return index;
- if (otherChild == child1) {
- otherChild = canonicalize(otherNode.child2());
- if (otherChild == NoNode)
- return index;
- if (otherChild == child2) {
- otherChild = canonicalize(otherNode.child3());
- if (otherChild == NoNode)
- return index;
- if (otherChild == child3)
- return index;
- }
+ break;
+
+ case PutByVal:
+ if (!m_graph.byValIsPure(node))
+ return NoNode;
+ switch (node.arrayMode()) {
+ case ARRAY_STORAGE_TO_HOLE_MODES:
+ return NoNode;
+ default:
+ break;
}
- }
- if (m_graph.clobbersWorld(index))
break;
+
+ default:
+ if (m_graph.clobbersWorld(index))
+ return NoNode;
+ }
}
return NoNode;
}
@@ -216,6 +215,34 @@ private:
return NoNode;
}
+ NodeIndex scopedVarLoadElimination(unsigned scopeChainDepth, unsigned varNumber)
+ {
+ for (unsigned i = m_indexInBlock; i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ Node& node = m_graph[index];
+ switch (node.op()) {
+ case GetScopedVar: {
+ Node& getScopeRegisters = m_graph[node.child1()];
+ Node& getScope = m_graph[getScopeRegisters.child1()];
+ if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
+ return index;
+ break;
+ }
+ case PutScopedVar: {
+ Node& getScope = m_graph[node.child1()];
+ if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber)
+ return node.child3().index();
+ break;
+ }
+ default:
+ break;
+ }
+ if (m_graph.clobbersWorld(index))
+ break;
+ }
+ return NoNode;
+ }
+
bool globalVarWatchpointElimination(WriteBarrier<Unknown>* registerPointer)
{
for (unsigned i = m_indexInBlock; i--;) {
@@ -267,6 +294,38 @@ private:
return NoNode;
}
+ NodeIndex scopedVarStoreElimination(unsigned scopeChainDepth, unsigned varNumber)
+ {
+ for (unsigned i = m_indexInBlock; i--;) {
+ NodeIndex index = m_currentBlock->at(i);
+ Node& node = m_graph[index];
+ if (!node.shouldGenerate())
+ continue;
+ switch (node.op()) {
+ case PutScopedVar: {
+ Node& getScope = m_graph[node.child1()];
+ if (getScope.scopeChainDepth() == scopeChainDepth && 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)
+ return NoNode;
+ break;
+ }
+
+ default:
+ break;
+ }
+ if (m_graph.clobbersWorld(index) || node.canExit())
+ return NoNode;
+ }
+ return NoNode;
+ }
+
NodeIndex getByValLoadElimination(NodeIndex child1, NodeIndex child2)
{
for (unsigned i = m_indexInBlock; i--;) {
@@ -437,7 +496,7 @@ private:
break;
Node& node = m_graph[index];
if (!node.shouldGenerate())
- break;
+ continue;
switch (node.op()) {
case CheckStructure:
case ForwardCheckStructure:
@@ -690,19 +749,35 @@ private:
return NoNode;
}
- NodeIndex getScopeChainLoadElimination(unsigned depth)
+ NodeIndex getScopeLoadElimination(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() == GetScopeChain
+ if (node.op() == GetScope
&& node.scopeChainDepth() == depth)
return index;
}
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)
{
@@ -787,7 +862,8 @@ private:
return result;
}
- case GetScopeChain:
+ case GetScope:
+ case GetScopeRegisters:
if (m_graph.uncheckedActivationRegisterFor(node.codeOrigin) == local)
result.mayBeAccessed = true;
break;
@@ -1078,11 +1154,15 @@ private:
break;
case GetArrayLength:
- setReplacement(impureCSE(node));
+ setReplacement(getArrayLengthElimination(node.child1().index()));
break;
-
- case GetScopeChain:
- setReplacement(getScopeChainLoadElimination(node.scopeChainDepth()));
+
+ case GetScope:
+ setReplacement(getScopeLoadElimination(node.scopeChainDepth()));
+ break;
+
+ case GetScopeRegisters:
+ setReplacement(getScopeRegistersLoadElimination(m_graph[node.scope()].scopeChainDepth()));
break;
// Handle nodes that are conditionally pure: these are pure, and can
@@ -1106,7 +1186,14 @@ private:
case GetGlobalVar:
setReplacement(globalVarLoadElimination(node.registerPointer()));
break;
-
+
+ case GetScopedVar: {
+ Node& getScopeRegisters = m_graph[node.child1()];
+ Node& getScope = m_graph[getScopeRegisters.child1()];
+ setReplacement(scopedVarLoadElimination(getScope.scopeChainDepth(), node.varNumber()));
+ break;
+ }
+
case GlobalVarWatchpoint:
if (globalVarWatchpointElimination(node.registerPointer()))
eliminate();
@@ -1119,6 +1206,14 @@ private:
eliminate(globalVarStoreElimination(node.registerPointer()));
break;
+ case PutScopedVar: {
+ if (m_graph.m_fixpointState == FixpointNotConverged)
+ break;
+ Node& getScope = m_graph[node.child1()];
+ eliminate(scopedVarStoreElimination(getScope.scopeChainDepth(), node.varNumber()));
+ break;
+ }
+
case GetByVal:
if (m_graph.byValIsPure(node))
setReplacement(getByValLoadElimination(node.child1().index(), node.child2().index()));
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 64d81f526..b02c9991c 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -469,6 +469,12 @@ public:
return isNumberSpeculation(left) && isNumberSpeculation(right);
}
+ // Note that a 'true' return does not actually mean that the ByVal access clobbers nothing.
+ // It really means that it will not clobber the entire world. It's still up to you to
+ // carefully consider things like:
+ // - PutByVal definitely changes the array it stores to, and may even change its length.
+ // - PutByOffset definitely changes the object it stores to.
+ // - and so on.
bool byValIsPure(Node& node)
{
switch (node.arrayMode()) {
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 195135c7b..df6191eab 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -466,7 +466,7 @@ struct Node {
bool hasScopeChainDepth()
{
- return op() == GetScopeChain;
+ return op() == GetScope;
}
unsigned scopeChainDepth()
@@ -475,6 +475,12 @@ struct Node {
return m_opInfo;
}
+ Edge scope()
+ {
+ ASSERT(op() == GetScopeRegisters);
+ return child1();
+ }
+
bool hasResult()
{
return m_flags & NodeResultMask;
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 584e28cca..9c93a8ba3 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -144,10 +144,11 @@ namespace JSC { namespace DFG {
macro(GetByOffset, NodeResultJS) \
macro(PutByOffset, NodeMustGenerate) \
macro(GetArrayLength, NodeResultInt32) \
- macro(GetScopeChain, NodeResultJS) \
- macro(GetScopedVar, NodeResultJS | NodeMustGenerate) \
- macro(PutScopedVar, NodeMustGenerate | NodeClobbersWorld) \
- macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \
+ macro(GetScope, NodeResultJS) \
+ macro(GetScopeRegisters, NodeResultStorage) \
+ macro(GetScopedVar, NodeResultJS) \
+ macro(PutScopedVar, NodeMustGenerate) \
+ macro(GetGlobalVar, NodeResultJS) \
macro(PutGlobalVar, NodeMustGenerate) \
macro(GlobalVarWatchpoint, NodeMustGenerate) \
macro(PutGlobalVarCheck, NodeMustGenerate) \
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index a918bbbe5..d76fd8018 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -447,7 +447,8 @@ private:
changed |= setPrediction(SpecInt32);
break;
}
-
+
+ case GetScopeRegisters:
case GetButterfly:
case GetIndexedPropertyStorage:
case AllocatePropertyStorage:
@@ -509,7 +510,7 @@ private:
break;
}
- case GetScopeChain: {
+ case GetScope: {
changed |= setPrediction(SpecCellOther);
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
index 690f0dd3e..b05537fdf 100644
--- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp
+++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
@@ -216,7 +216,7 @@ static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stu
linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, successLabel, slowCaseLabel);
- stubRoutine = FINALIZE_CODE_FOR_STUB(
+ stubRoutine = FINALIZE_CODE_FOR_DFG_STUB(
patchBuffer,
("DFG prototype chain access stub for CodeBlock %p, return point %p",
exec->codeBlock(), successLabel.executableAddress()));
@@ -277,7 +277,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
linkRestoreScratch(patchBuffer, needToRestoreScratch, stubInfo, success, fail, failureCases);
- stubInfo.stubRoutine = FINALIZE_CODE_FOR_STUB(
+ stubInfo.stubRoutine = FINALIZE_CODE_FOR_DFG_STUB(
patchBuffer,
("DFG GetById array length stub for CodeBlock %p, return point %p",
exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset(
@@ -506,7 +506,7 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
RefPtr<JITStubRoutine> stubRoutine =
createJITStubRoutine(
- FINALIZE_CODE(
+ FINALIZE_DFG_CODE(
patchBuffer,
("DFG GetById polymorphic list access for CodeBlock %p, return point %p",
exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset(
@@ -717,7 +717,7 @@ static void emitPutReplaceStub(
patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToDone));
patchBuffer.link(failure, failureLabel);
- stubRoutine = FINALIZE_CODE_FOR_STUB(
+ stubRoutine = FINALIZE_CODE_FOR_DFG_STUB(
patchBuffer,
("DFG PutById replace stub for CodeBlock %p, return point %p",
exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset(
@@ -917,9 +917,11 @@ static void emitPutTransitionStub(
stubRoutine =
createJITStubRoutine(
- FINALIZE_CODE(
+ FINALIZE_DFG_CODE(
patchBuffer,
- ("DFG PutById transition stub for CodeBlock %p, return point %p",
+ ("DFG PutById %stransition stub (%p -> %p) for CodeBlock %p, return point %p",
+ structure->outOfLineCapacity() != oldStructure->outOfLineCapacity() ? "reallocating " : "",
+ oldStructure, structure,
exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset(
stubInfo.patch.dfg.deltaCallToDone).executableAddress())),
*globalData,
@@ -957,6 +959,11 @@ static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier
&& oldStructure->outOfLineCapacity())
return false;
+ // Skip optimizing the case where we need realloc, and the structure has
+ // indexing storage.
+ if (hasIndexingHeader(oldStructure->indexingType()))
+ return false;
+
normalizePrototypeChain(exec, baseCell);
StructureChain* prototypeChain = structure->prototypeChain(exec);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 0228f846a..e42752d8a 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -2382,7 +2382,7 @@ void SpeculativeJIT::compileInstanceOf(Node& node)
// from speculating any more aggressively than we absolutely need to.
JSValueOperand value(this, node.child1());
- SpeculateCellOperand prototype(this, node.child3());
+ SpeculateCellOperand prototype(this, node.child2());
GPRTemporary scratch(this);
GPRReg prototypeReg = prototype.gpr();
@@ -2416,8 +2416,7 @@ void SpeculativeJIT::compileInstanceOf(Node& node)
}
SpeculateCellOperand value(this, node.child1());
- // Base unused since we speculate default InstanceOf behaviour in CheckHasInstance.
- SpeculateCellOperand prototype(this, node.child3());
+ SpeculateCellOperand prototype(this, node.child2());
GPRTemporary scratch(this);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 22941358a..8039ad2ab 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -3371,7 +3371,7 @@ void SpeculativeJIT::compile(Node& node)
break;
}
- case GetScopeChain: {
+ case GetScope: {
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
@@ -3392,27 +3392,42 @@ void SpeculativeJIT::compile(Node& node)
cellResult(resultGPR, m_compileIndex);
break;
}
- case GetScopedVar: {
+ case GetScopeRegisters: {
SpeculateCellOperand scope(this, node.child1());
+ GPRTemporary result(this);
+ GPRReg scopeGPR = scope.gpr();
+ GPRReg resultGPR = result.gpr();
+
+ m_jit.loadPtr(JITCompiler::Address(scopeGPR, JSVariableObject::offsetOfRegisters()), resultGPR);
+ storageResult(resultGPR, m_compileIndex);
+ break;
+ }
+ case GetScopedVar: {
+ StorageOperand registers(this, node.child1());
GPRTemporary resultTag(this);
GPRTemporary resultPayload(this);
+ GPRReg registersGPR = registers.gpr();
GPRReg resultTagGPR = resultTag.gpr();
GPRReg resultPayloadGPR = resultPayload.gpr();
- m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), resultPayloadGPR);
- m_jit.load32(JITCompiler::Address(resultPayloadGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
- m_jit.load32(JITCompiler::Address(resultPayloadGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
+ m_jit.load32(JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
+ m_jit.load32(JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
break;
}
case PutScopedVar: {
SpeculateCellOperand scope(this, node.child1());
+ StorageOperand registers(this, node.child2());
+ JSValueOperand value(this, node.child3());
GPRTemporary scratchRegister(this);
+ GPRReg scopeGPR = scope.gpr();
+ GPRReg registersGPR = registers.gpr();
+ GPRReg valueTagGPR = value.tagGPR();
+ GPRReg valuePayloadGPR = value.payloadGPR();
GPRReg scratchGPR = scratchRegister.gpr();
- m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), scratchGPR);
- JSValueOperand value(this, node.child2());
- m_jit.store32(value.tagGPR(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
- m_jit.store32(value.payloadGPR(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
- writeBarrier(scope.gpr(), value.tagGPR(), node.child2(), WriteBarrierForVariableAccess, scratchGPR);
+
+ m_jit.store32(valueTagGPR, JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+ m_jit.store32(valuePayloadGPR, JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+ writeBarrier(scopeGPR, valueTagGPR, node.child2(), WriteBarrierForVariableAccess, scratchGPR);
noResult(m_compileIndex);
break;
}
@@ -4202,23 +4217,50 @@ void SpeculativeJIT::compile(Node& node)
JITCompiler::payloadFor(RegisterFile::ArgumentCount)));
}
+ JITCompiler::JumpList slowArgument;
+ JITCompiler::JumpList slowArgumentOutOfBounds;
+ if (const SlowArgument* slowArguments = m_jit.symbolTableFor(node.codeOrigin)->slowArguments()) {
+ slowArgumentOutOfBounds.append(
+ m_jit.branch32(
+ JITCompiler::AboveOrEqual, indexGPR,
+ Imm32(m_jit.symbolTableFor(node.codeOrigin)->parameterCount())));
+
+ COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes);
+ m_jit.move(ImmPtr(slowArguments), resultPayloadGPR);
+ m_jit.load32(
+ JITCompiler::BaseIndex(
+ resultPayloadGPR, indexGPR, JITCompiler::TimesEight,
+ OBJECT_OFFSETOF(SlowArgument, index)),
+ resultPayloadGPR);
+
+ m_jit.load32(
+ JITCompiler::BaseIndex(
+ GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
+ m_jit.offsetOfLocals(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
+ resultTagGPR);
+ m_jit.load32(
+ JITCompiler::BaseIndex(
+ GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
+ m_jit.offsetOfLocals(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
+ resultPayloadGPR);
+ slowArgument.append(m_jit.jump());
+ }
+ slowArgumentOutOfBounds.link(&m_jit);
+
m_jit.neg32(resultPayloadGPR);
- size_t baseOffset =
- ((node.codeOrigin.inlineCallFrame
- ? node.codeOrigin.inlineCallFrame->stackOffset
- : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register);
m_jit.load32(
JITCompiler::BaseIndex(
GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
- baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
+ m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
resultTagGPR);
m_jit.load32(
JITCompiler::BaseIndex(
GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
- baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
+ m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
resultPayloadGPR);
+ slowArgument.link(&m_jit);
jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
break;
}
@@ -4252,21 +4294,46 @@ void SpeculativeJIT::compile(Node& node)
JITCompiler::payloadFor(RegisterFile::ArgumentCount)));
}
+ JITCompiler::JumpList slowArgument;
+ JITCompiler::JumpList slowArgumentOutOfBounds;
+ if (const SlowArgument* slowArguments = m_jit.symbolTableFor(node.codeOrigin)->slowArguments()) {
+ slowArgumentOutOfBounds.append(
+ m_jit.branch32(
+ JITCompiler::AboveOrEqual, indexGPR,
+ Imm32(m_jit.symbolTableFor(node.codeOrigin)->parameterCount())));
+
+ COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes);
+ m_jit.move(ImmPtr(slowArguments), resultPayloadGPR);
+ m_jit.load32(
+ JITCompiler::BaseIndex(
+ resultPayloadGPR, indexGPR, JITCompiler::TimesEight,
+ OBJECT_OFFSETOF(SlowArgument, index)),
+ resultPayloadGPR);
+ m_jit.load32(
+ JITCompiler::BaseIndex(
+ GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
+ m_jit.offsetOfLocals(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
+ resultTagGPR);
+ m_jit.load32(
+ JITCompiler::BaseIndex(
+ GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
+ m_jit.offsetOfLocals(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
+ resultPayloadGPR);
+ slowArgument.append(m_jit.jump());
+ }
+ slowArgumentOutOfBounds.link(&m_jit);
+
m_jit.neg32(resultPayloadGPR);
- size_t baseOffset =
- ((node.codeOrigin.inlineCallFrame
- ? node.codeOrigin.inlineCallFrame->stackOffset
- : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register);
m_jit.load32(
JITCompiler::BaseIndex(
GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
- baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
+ m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
resultTagGPR);
m_jit.load32(
JITCompiler::BaseIndex(
GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight,
- baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
+ m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)),
resultPayloadGPR);
if (node.codeOrigin.inlineCallFrame) {
@@ -4284,6 +4351,7 @@ void SpeculativeJIT::compile(Node& node)
m_jit.argumentsRegisterFor(node.codeOrigin), indexGPR));
}
+ slowArgument.link(&m_jit);
jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex);
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 87be658ad..8488d261d 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -3380,7 +3380,7 @@ void SpeculativeJIT::compile(Node& node)
break;
}
- case GetScopeChain: {
+ case GetScope: {
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
@@ -3401,23 +3401,39 @@ void SpeculativeJIT::compile(Node& node)
cellResult(resultGPR, m_compileIndex);
break;
}
- case GetScopedVar: {
+ case GetScopeRegisters: {
SpeculateCellOperand scope(this, node.child1());
GPRTemporary result(this);
+ GPRReg scopeGPR = scope.gpr();
+ GPRReg resultGPR = result.gpr();
+
+ m_jit.loadPtr(JITCompiler::Address(scopeGPR, JSVariableObject::offsetOfRegisters()), resultGPR);
+ storageResult(resultGPR, m_compileIndex);
+ break;
+ }
+ case GetScopedVar: {
+ StorageOperand registers(this, node.child1());
+ GPRTemporary result(this);
+ GPRReg registersGPR = registers.gpr();
GPRReg resultGPR = result.gpr();
- m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), resultGPR);
- m_jit.loadPtr(JITCompiler::Address(resultGPR, node.varNumber() * sizeof(Register)), resultGPR);
+
+ m_jit.loadPtr(JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register)), resultGPR);
jsValueResult(resultGPR, m_compileIndex);
break;
}
case PutScopedVar: {
SpeculateCellOperand scope(this, node.child1());
+ StorageOperand registers(this, node.child2());
+ JSValueOperand value(this, node.child3());
GPRTemporary scratchRegister(this);
+
+ GPRReg scopeGPR = scope.gpr();
+ GPRReg registersGPR = registers.gpr();
+ GPRReg valueGPR = value.gpr();
GPRReg scratchGPR = scratchRegister.gpr();
- m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), scratchGPR);
- JSValueOperand value(this, node.child2());
- m_jit.storePtr(value.gpr(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register)));
- writeBarrier(scope.gpr(), value.gpr(), node.child2(), WriteBarrierForVariableAccess, scratchGPR);
+
+ m_jit.storePtr(valueGPR, JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register)));
+ writeBarrier(scopeGPR, valueGPR, node.child3(), WriteBarrierForVariableAccess, scratchGPR);
noResult(m_compileIndex);
break;
}
@@ -4122,7 +4138,7 @@ void SpeculativeJIT::compile(Node& node)
GPRTemporary result(this);
GPRReg indexGPR = index.gpr();
GPRReg resultGPR = result.gpr();
-
+
if (!isEmptySpeculation(
m_state.variables().operand(
m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
@@ -4150,18 +4166,40 @@ void SpeculativeJIT::compile(Node& node)
resultGPR,
JITCompiler::payloadFor(RegisterFile::ArgumentCount)));
}
-
+
+ JITCompiler::JumpList slowArgument;
+ JITCompiler::JumpList slowArgumentOutOfBounds;
+ if (const SlowArgument* slowArguments = m_jit.symbolTableFor(node.codeOrigin)->slowArguments()) {
+ slowArgumentOutOfBounds.append(
+ m_jit.branch32(
+ JITCompiler::AboveOrEqual, indexGPR,
+ Imm32(m_jit.symbolTableFor(node.codeOrigin)->parameterCount())));
+
+ COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes);
+ m_jit.move(ImmPtr(slowArguments), resultGPR);
+ m_jit.load32(
+ JITCompiler::BaseIndex(
+ resultGPR, indexGPR, JITCompiler::TimesEight,
+ OBJECT_OFFSETOF(SlowArgument, index)),
+ resultGPR);
+ m_jit.signExtend32ToPtr(resultGPR, resultGPR);
+ m_jit.loadPtr(
+ JITCompiler::BaseIndex(
+ GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfLocals(node.codeOrigin)),
+ resultGPR);
+ slowArgument.append(m_jit.jump());
+ }
+ slowArgumentOutOfBounds.link(&m_jit);
+
m_jit.neg32(resultGPR);
m_jit.signExtend32ToPtr(resultGPR, resultGPR);
m_jit.loadPtr(
JITCompiler::BaseIndex(
- GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight,
- ((node.codeOrigin.inlineCallFrame
- ? node.codeOrigin.inlineCallFrame->stackOffset
- : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register)),
+ GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin)),
resultGPR);
+ slowArgument.link(&m_jit);
jsValueResult(resultGPR, m_compileIndex);
break;
}
@@ -4194,15 +4232,36 @@ void SpeculativeJIT::compile(Node& node)
JITCompiler::payloadFor(RegisterFile::ArgumentCount)));
}
+ JITCompiler::JumpList slowArgument;
+ JITCompiler::JumpList slowArgumentOutOfBounds;
+ if (const SlowArgument* slowArguments = m_jit.symbolTableFor(node.codeOrigin)->slowArguments()) {
+ slowArgumentOutOfBounds.append(
+ m_jit.branch32(
+ JITCompiler::AboveOrEqual, indexGPR,
+ Imm32(m_jit.symbolTableFor(node.codeOrigin)->parameterCount())));
+
+ COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes);
+ m_jit.move(ImmPtr(slowArguments), resultGPR);
+ m_jit.load32(
+ JITCompiler::BaseIndex(
+ resultGPR, indexGPR, JITCompiler::TimesEight,
+ OBJECT_OFFSETOF(SlowArgument, index)),
+ resultGPR);
+ m_jit.signExtend32ToPtr(resultGPR, resultGPR);
+ m_jit.loadPtr(
+ JITCompiler::BaseIndex(
+ GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfLocals(node.codeOrigin)),
+ resultGPR);
+ slowArgument.append(m_jit.jump());
+ }
+ slowArgumentOutOfBounds.link(&m_jit);
+
m_jit.neg32(resultGPR);
m_jit.signExtend32ToPtr(resultGPR, resultGPR);
m_jit.loadPtr(
JITCompiler::BaseIndex(
- GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight,
- ((node.codeOrigin.inlineCallFrame
- ? node.codeOrigin.inlineCallFrame->stackOffset
- : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register)),
+ GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin)),
resultGPR);
if (node.codeOrigin.inlineCallFrame) {
@@ -4220,6 +4279,7 @@ void SpeculativeJIT::compile(Node& node)
indexGPR));
}
+ slowArgument.link(&m_jit);
jsValueResult(resultGPR, m_compileIndex);
break;
}