diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGAbstractState.cpp | 12 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp | 4 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h | 19 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp | 27 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGCSEPhase.cpp | 165 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGGraph.h | 6 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGNode.h | 8 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGNodeType.h | 9 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp | 5 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGRepatch.cpp | 19 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp | 5 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp | 112 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp | 96 |
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; } |