diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
commit | 49233e234e5c787396cadb2cea33b31ae0cd65c1 (patch) | |
tree | 5410cb9a8fd53168bb60d62c54b654d86f03c38d /Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp | |
parent | b211c645d8ab690f713515dfdc84d80b11c27d2c (diff) | |
download | qtwebkit-49233e234e5c787396cadb2cea33b31ae0cd65c1.tar.gz |
Imported WebKit commit 3a8c29f35d00659d2ce7a0ccdfa8304f14e82327 (http://svn.webkit.org/repository/webkit/trunk@120813)
New snapshot with Windows build fixes
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp | 319 |
1 files changed, 236 insertions, 83 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 358171029..317a08504 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -93,7 +93,10 @@ private: // Handle setting the result of an intrinsic. void setIntrinsicResult(bool usesResult, int resultOperand, NodeIndex); // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call. - bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, PredictedType prediction); + bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction); + void handleGetById( + int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber, + const GetByIdStatus&); // Prepare to parse a block. void prepareToParseBlock(); // Parse a single basic block of bytecode instructions. @@ -109,7 +112,7 @@ private: template<PhiStackType stackType> void processPhiStack(); - void fixVariableAccessPredictions(); + void fixVariableAccessSpeculations(); // Add spill locations to nodes. void allocateVirtualRegisters(); @@ -159,17 +162,17 @@ private: setDirect(m_inlineStackTop->remapOperand(operand), value, setMode); } - NodeIndex injectLazyOperandPrediction(NodeIndex nodeIndex) + NodeIndex injectLazyOperandSpeculation(NodeIndex nodeIndex) { Node& node = m_graph[nodeIndex]; ASSERT(node.op() == GetLocal); ASSERT(node.codeOrigin.bytecodeIndex == m_currentIndex); - PredictedType prediction = + SpeculatedType prediction = m_inlineStackTop->m_lazyOperands.prediction( LazyOperandValueProfileKey(m_currentIndex, node.local())); #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("Lazy operand [@%u, bc#%u, r%d] prediction: %s\n", - nodeIndex, m_currentIndex, node.local(), predictionToString(prediction)); + nodeIndex, m_currentIndex, node.local(), speculationToString(prediction)); #endif node.variableAccessData()->predict(prediction); return nodeIndex; @@ -192,7 +195,7 @@ private: if (flushChild.op() == Phi) { VariableAccessData* variableAccessData = flushChild.variableAccessData(); variableAccessData->mergeIsCaptured(isCaptured); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex)); m_currentBlock->variablesAtTail.local(operand) = nodeIndex; return nodeIndex; } @@ -213,7 +216,7 @@ private: if (nodePtr->op() == GetLocal) nodeIndex = nodePtr->child1().index(); - return injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); + return injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); } if (nodePtr->op() == GetLocal) @@ -230,7 +233,7 @@ private: NodeIndex phi = addToGraph(Phi, OpInfo(variableAccessData)); m_localPhiStack.append(PhiStackEntry(m_currentBlock, phi, operand)); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), phi)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variableAccessData), phi)); m_currentBlock->variablesAtTail.local(operand) = nodeIndex; m_currentBlock->variablesAtHead.setLocalFirstTime(operand, nodeIndex); @@ -274,7 +277,7 @@ private: if (flushChild.op() == Phi) { VariableAccessData* variableAccessData = flushChild.variableAccessData(); variableAccessData->mergeIsCaptured(isCaptured); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex)); m_currentBlock->variablesAtTail.argument(argument) = nodeIndex; return nodeIndex; } @@ -290,7 +293,7 @@ private: // We're getting an argument in the first basic block; link // the GetLocal to the SetArgument. ASSERT(nodePtr->local() == static_cast<VirtualRegister>(operand)); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); m_currentBlock->variablesAtTail.argument(argument) = nodeIndex; return nodeIndex; } @@ -298,7 +301,7 @@ private: if (isCaptured) { if (nodePtr->op() == GetLocal) nodeIndex = nodePtr->child1().index(); - return injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); + return injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); } if (nodePtr->op() == GetLocal) @@ -312,7 +315,7 @@ private: NodeIndex phi = addToGraph(Phi, OpInfo(variableAccessData)); m_argumentPhiStack.append(PhiStackEntry(m_currentBlock, phi, argument)); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), phi)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variableAccessData), phi)); m_currentBlock->variablesAtTail.argument(argument) = nodeIndex; m_currentBlock->variablesAtHead.setArgumentFirstTime(argument, nodeIndex); @@ -725,7 +728,7 @@ private: { Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call); - PredictedType prediction = PredictNone; + SpeculatedType prediction = SpecNone; if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { m_currentProfilingIndex = m_currentIndex + OPCODE_LENGTH(op_call); prediction = getPrediction(); @@ -747,23 +750,44 @@ private: return call; } - PredictedType getPredictionWithoutOSRExit(NodeIndex nodeIndex, unsigned bytecodeIndex) + NodeIndex addStructureTransitionCheck(JSCell* object, Structure* structure) + { + // Add a weak JS constant for the object regardless, since the code should + // be jettisoned if the object ever dies. + NodeIndex objectIndex = cellConstant(object); + + if (object->structure() == structure && structure->transitionWatchpointSetIsStillValid()) { + addToGraph(StructureTransitionWatchpoint, OpInfo(structure), objectIndex); + return objectIndex; + } + + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structure)), objectIndex); + + return objectIndex; + } + + NodeIndex addStructureTransitionCheck(JSCell* object) + { + return addStructureTransitionCheck(object, object->structure()); + } + + SpeculatedType getPredictionWithoutOSRExit(NodeIndex nodeIndex, unsigned bytecodeIndex) { UNUSED_PARAM(nodeIndex); - PredictedType prediction = m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(bytecodeIndex); + SpeculatedType prediction = m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(bytecodeIndex); #if DFG_ENABLE(DEBUG_VERBOSE) - dataLog("Dynamic [@%u, bc#%u] prediction: %s\n", nodeIndex, bytecodeIndex, predictionToString(prediction)); + dataLog("Dynamic [@%u, bc#%u] prediction: %s\n", nodeIndex, bytecodeIndex, speculationToString(prediction)); #endif return prediction; } - PredictedType getPrediction(NodeIndex nodeIndex, unsigned bytecodeIndex) + SpeculatedType getPrediction(NodeIndex nodeIndex, unsigned bytecodeIndex) { - PredictedType prediction = getPredictionWithoutOSRExit(nodeIndex, bytecodeIndex); + SpeculatedType prediction = getPredictionWithoutOSRExit(nodeIndex, bytecodeIndex); - if (prediction == PredictNone) { + if (prediction == SpecNone) { // We have no information about what values this node generates. Give up // on executing this code, since we're likely to do more damage than good. addToGraph(ForceOSRExit); @@ -772,12 +796,12 @@ private: return prediction; } - PredictedType getPredictionWithoutOSRExit() + SpeculatedType getPredictionWithoutOSRExit() { return getPredictionWithoutOSRExit(m_graph.size(), m_currentProfilingIndex); } - PredictedType getPrediction() + SpeculatedType getPrediction() { return getPrediction(m_graph.size(), m_currentProfilingIndex); } @@ -1020,7 +1044,7 @@ private: VirtualRegister m_returnValue; - // Predictions about variable types collected from the profiled code block, + // Speculations about variable types collected from the profiled code block, // which are based on OSR exit profiles that past DFG compilatins of this // code block had gathered. LazyOperandValueProfileParser m_lazyOperands; @@ -1147,7 +1171,7 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn int resultOperand = 0; // make compiler happy unsigned nextOffset = m_currentIndex + OPCODE_LENGTH(op_call); Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call); - PredictedType prediction = PredictNone; + SpeculatedType prediction = SpecNone; if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { resultOperand = putInstruction[1].u.operand; usesResult = true; @@ -1231,6 +1255,9 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c // Does the code block's size match the heuristics/requirements for being // an inline candidate? CodeBlock* profiledBlock = executable->profiledCodeBlockFor(kind); + if (!profiledBlock) + return false; + if (!mightInlineFunctionFor(profiledBlock, kind)) return false; @@ -1270,6 +1297,8 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c for (size_t i = 0; i < m_graph.m_blocks.size(); ++i) m_graph.m_blocks[i]->ensureLocals(newNumLocals); } + + size_t argumentPositionStart = m_graph.m_argumentPositions.size(); InlineStackEntry inlineStackEntry( this, codeBlock, profiledBlock, m_graph.m_blocks.size() - 1, @@ -1284,7 +1313,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c m_currentIndex = 0; m_currentProfilingIndex = 0; - addToGraph(InlineStart); + addToGraph(InlineStart, OpInfo(argumentPositionStart)); parseCodeBlock(); @@ -1418,7 +1447,7 @@ bool ByteCodeParser::handleMinMax(bool usesResult, int resultOperand, NodeType o // FIXME: We dead-code-eliminate unused Math intrinsics, but that's invalid because // they need to perform the ToNumber conversion, which can have side-effects. -bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, PredictedType prediction) +bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction) { switch (intrinsic) { case AbsIntrinsic: { @@ -1482,7 +1511,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins return false; int thisOperand = registerOffset + argumentToOperand(0); - if (!(m_graph[get(thisOperand)].prediction() & PredictString)) + if (!(m_graph[get(thisOperand)].prediction() & SpecString)) return false; int indexOperand = registerOffset + argumentToOperand(1); @@ -1499,7 +1528,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins return false; int thisOperand = registerOffset + argumentToOperand(0); - if (!(m_graph[get(thisOperand)].prediction() & PredictString)) + if (!(m_graph[get(thisOperand)].prediction() & SpecString)) return false; int indexOperand = registerOffset + argumentToOperand(1); @@ -1538,6 +1567,80 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins } } +void ByteCodeParser::handleGetById( + int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber, + const GetByIdStatus& getByIdStatus) +{ + if (!getByIdStatus.isSimple() + || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) { + set(destinationOperand, + addToGraph( + getByIdStatus.makesCalls() ? GetByIdFlush : GetById, + OpInfo(identifierNumber), OpInfo(prediction), base)); + return; + } + + ASSERT(getByIdStatus.structureSet().size()); + + // The implementation of GetByOffset does not know to terminate speculative + // execution if it doesn't have a prediction, so we do it manually. + if (prediction == SpecNone) + addToGraph(ForceOSRExit); + + NodeIndex originalBaseForBaselineJIT = base; + + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(getByIdStatus.structureSet())), base); + + bool useInlineStorage; + if (!getByIdStatus.chain().isEmpty()) { + Structure* currentStructure = getByIdStatus.structureSet().singletonStructure(); + JSObject* currentObject = 0; + for (unsigned i = 0; i < getByIdStatus.chain().size(); ++i) { + currentObject = asObject(currentStructure->prototypeForLookup(m_inlineStackTop->m_codeBlock)); + currentStructure = getByIdStatus.chain()[i]; + base = addStructureTransitionCheck(currentObject, currentStructure); + } + useInlineStorage = currentStructure->isUsingInlineStorage(); + } else + useInlineStorage = getByIdStatus.structureSet().allAreUsingInlinePropertyStorage(); + + // Unless we want bugs like https://bugs.webkit.org/show_bug.cgi?id=88783, we need to + // ensure that the base of the original get_by_id is kept alive until we're done with + // all of the speculations. We only insert the Phantom if there had been a CheckStructure + // on something other than the base following the CheckStructure on base, or if the + // access was compiled to a WeakJSConstant specific value, in which case we might not + // have any explicit use of the base at all. + if (getByIdStatus.specificValue() || originalBaseForBaselineJIT != base) + addToGraph(Phantom, originalBaseForBaselineJIT); + + if (getByIdStatus.specificValue()) { + ASSERT(getByIdStatus.specificValue().isCell()); + + set(destinationOperand, cellConstant(getByIdStatus.specificValue().asCell())); + return; + } + + NodeIndex propertyStorage; + size_t offsetOffset; + if (useInlineStorage) { + propertyStorage = base; + ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue))); + offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue); + } else { + propertyStorage = addToGraph(GetPropertyStorage, base); + offsetOffset = 0; + } + set(destinationOperand, + addToGraph( + GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), + propertyStorage)); + + StorageAccessData storageAccessData; + storageAccessData.offset = getByIdStatus.offset() + offsetOffset; + storageAccessData.identifierNumber = identifierNumber; + m_graph.m_storageAccessData.append(storageAccessData); +} + void ByteCodeParser::prepareToParseBlock() { for (unsigned i = 0; i < m_constants.size(); ++i) @@ -1972,7 +2075,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) // === Property access operations === case op_get_by_val: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); NodeIndex base = get(currentInstruction[2].u.operand); NodeIndex property = get(currentInstruction[3].u.operand); @@ -1997,7 +2100,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) m_currentProfilingIndex += OPCODE_LENGTH(op_method_check); Instruction* getInstruction = currentInstruction + OPCODE_LENGTH(op_method_check); - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); ASSERT(interpreter->getOpcodeID(getInstruction->u.opcode) == op_get_by_id); @@ -2020,18 +2123,22 @@ bool ByteCodeParser::parseBlock(unsigned limit) // but the slow path (i.e. the normal get_by_id) never fired. addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCallStatus.structure())), base); - if (methodCallStatus.needsPrototypeCheck()) - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCallStatus.prototypeStructure())), cellConstant(methodCallStatus.prototype())); - + if (methodCallStatus.needsPrototypeCheck()) { + addStructureTransitionCheck( + methodCallStatus.prototype(), methodCallStatus.prototypeStructure()); + addToGraph(Phantom, base); + } set(getInstruction[1].u.operand, cellConstant(methodCallStatus.function())); - } else - set(getInstruction[1].u.operand, addToGraph(getByIdStatus.makesCalls() ? GetByIdFlush : GetById, OpInfo(identifier), OpInfo(prediction), base)); + } else { + handleGetById( + getInstruction[1].u.operand, prediction, base, identifier, getByIdStatus); + } m_currentIndex += OPCODE_LENGTH(op_method_check) + OPCODE_LENGTH(op_get_by_id); continue; } case op_get_scoped_var: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); int dst = currentInstruction[1].u.operand; int slot = currentInstruction[2].u.operand; int depth = currentInstruction[3].u.operand; @@ -2049,7 +2156,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) NEXT_OPCODE(op_put_scoped_var); } case op_get_by_id: { - PredictedType prediction = getPredictionWithoutOSRExit(); + SpeculatedType prediction = getPredictionWithoutOSRExit(); NodeIndex base = get(currentInstruction[2].u.operand); unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand]; @@ -2058,34 +2165,8 @@ bool ByteCodeParser::parseBlock(unsigned limit) GetByIdStatus getByIdStatus = GetByIdStatus::computeFor( m_inlineStackTop->m_profiledBlock, m_currentIndex, identifier); - if (getByIdStatus.isSimpleDirect() - && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) { - ASSERT(getByIdStatus.structureSet().size()); - - // The implementation of GetByOffset does not know to terminate speculative - // execution if it doesn't have a prediction, so we do it manually. - if (prediction == PredictNone) - addToGraph(ForceOSRExit); - - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(getByIdStatus.structureSet())), base); - NodeIndex propertyStorage; - size_t offsetOffset; - if (getByIdStatus.structureSet().allAreUsingInlinePropertyStorage()) { - propertyStorage = base; - ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue))); - offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue); - } else { - propertyStorage = addToGraph(GetPropertyStorage, base); - offsetOffset = 0; - } - set(currentInstruction[1].u.operand, addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), propertyStorage)); - - StorageAccessData storageAccessData; - storageAccessData.offset = getByIdStatus.offset() + offsetOffset; - storageAccessData.identifierNumber = identifierNumber; - m_graph.m_storageAccessData.append(storageAccessData); - } else - set(currentInstruction[1].u.operand, addToGraph(getByIdStatus.makesCalls() ? GetByIdFlush : GetById, OpInfo(identifierNumber), OpInfo(prediction), base)); + handleGetById( + currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus); NEXT_OPCODE(op_get_by_id); } @@ -2134,23 +2215,20 @@ bool ByteCodeParser::parseBlock(unsigned limit) addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure())), base); if (!direct) { - if (!putByIdStatus.oldStructure()->storedPrototype().isNull()) - addToGraph( - CheckStructure, - OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure()->storedPrototype().asCell()->structure())), - cellConstant(putByIdStatus.oldStructure()->storedPrototype().asCell())); + if (!putByIdStatus.oldStructure()->storedPrototype().isNull()) { + addStructureTransitionCheck( + putByIdStatus.oldStructure()->storedPrototype().asCell()); + } for (WriteBarrier<Structure>* it = putByIdStatus.structureChain()->head(); *it; ++it) { JSValue prototype = (*it)->storedPrototype(); if (prototype.isNull()) continue; ASSERT(prototype.isCell()); - addToGraph( - CheckStructure, - OpInfo(m_graph.addStructureSet(prototype.asCell()->structure())), - cellConstant(prototype.asCell())); + addStructureTransitionCheck(prototype.asCell()); } } + ASSERT(putByIdStatus.oldStructure()->transitionWatchpointSetHasBeenInvalidated()); addToGraph( PutStructure, OpInfo( @@ -2192,19 +2270,94 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_get_global_var: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); - NodeIndex getGlobalVar = addToGraph(GetGlobalVar, OpInfo(currentInstruction[2].u.operand), OpInfo(prediction)); + JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject(); + + NodeIndex getGlobalVar = addToGraph( + GetGlobalVar, + OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)), + OpInfo(prediction)); set(currentInstruction[1].u.operand, getGlobalVar); NEXT_OPCODE(op_get_global_var); } + + case op_get_global_var_watchable: { + SpeculatedType prediction = getPrediction(); + + JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject(); + + unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand]; + Identifier identifier = m_codeBlock->identifier(identifierNumber); + SymbolTableEntry entry = globalObject->symbolTable().get(identifier.impl()); + if (!entry.couldBeWatched()) { + NodeIndex getGlobalVar = addToGraph( + GetGlobalVar, + OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)), + OpInfo(prediction)); + set(currentInstruction[1].u.operand, getGlobalVar); + NEXT_OPCODE(op_get_global_var_watchable); + } + + // The watchpoint is still intact! This means that we will get notified if the + // current value in the global variable changes. So, we can inline that value. + // Moreover, currently we can assume that this value is a JSFunction*, which + // implies that it's a cell. This simplifies things, since in general we'd have + // to use a JSConstant for non-cells and a WeakJSConstant for cells. So instead + // of having both cases we just assert that the value is a cell. + + // NB. If it wasn't for CSE, GlobalVarWatchpoint would have no need for the + // register pointer. But CSE tracks effects on global variables by comparing + // register pointers. Because CSE executes multiple times while the backend + // executes once, we use the following performance trade-off: + // - The node refers directly to the register pointer to make CSE super cheap. + // - To perform backend code generation, the node only contains the identifier + // number, from which it is possible to get (via a few average-time O(1) + // lookups) to the WatchpointSet. + + addToGraph( + GlobalVarWatchpoint, + OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)), + OpInfo(identifierNumber)); + + JSValue specificValue = globalObject->registerAt(entry.getIndex()).get(); + ASSERT(specificValue.isCell()); + set(currentInstruction[1].u.operand, cellConstant(specificValue.asCell())); + + NEXT_OPCODE(op_get_global_var_watchable); + } case op_put_global_var: { NodeIndex value = get(currentInstruction[2].u.operand); - addToGraph(PutGlobalVar, OpInfo(currentInstruction[1].u.operand), value); + addToGraph( + PutGlobalVar, + OpInfo(m_inlineStackTop->m_codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)), + value); NEXT_OPCODE(op_put_global_var); } + case op_put_global_var_check: { + NodeIndex value = get(currentInstruction[2].u.operand); + CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock; + JSGlobalObject* globalObject = codeBlock->globalObject(); + unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[4].u.operand]; + Identifier identifier = m_codeBlock->identifier(identifierNumber); + SymbolTableEntry entry = globalObject->symbolTable().get(identifier.impl()); + if (!entry.couldBeWatched()) { + addToGraph( + PutGlobalVar, + OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)), + value); + NEXT_OPCODE(op_put_global_var_check); + } + addToGraph( + PutGlobalVarCheck, + OpInfo(codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)), + OpInfo(identifierNumber), + value); + NEXT_OPCODE(op_put_global_var_check); + } + // === Block terminators. === case op_jmp: { @@ -2433,7 +2586,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call_varargs); - PredictedType prediction = PredictNone; + SpeculatedType prediction = SpecNone; if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { m_currentProfilingIndex = m_currentIndex + OPCODE_LENGTH(op_call_varargs); prediction = getPrediction(); @@ -2471,7 +2624,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) LAST_OPCODE(op_jneq_ptr); case op_resolve: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand]; @@ -2482,7 +2635,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_resolve_base: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand]; @@ -2493,7 +2646,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_resolve_global: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); NodeIndex resolve = addToGraph(ResolveGlobal, OpInfo(m_graph.m_resolveGlobalData.size()), OpInfo(prediction)); m_graph.m_resolveGlobalData.append(ResolveGlobalData()); @@ -2747,7 +2900,7 @@ void ByteCodeParser::processPhiStack() } } -void ByteCodeParser::fixVariableAccessPredictions() +void ByteCodeParser::fixVariableAccessSpeculations() { for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) { VariableAccessData* data = &m_graph.m_variableAccessData[i]; @@ -2843,7 +2996,7 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry( , m_caller(byteCodeParser->m_inlineStackTop) { m_argumentPositions.resize(argumentCountIncludingThis); - for (unsigned i = argumentCountIncludingThis; i--;) { + for (int i = 0; i < argumentCountIncludingThis; ++i) { byteCodeParser->m_graph.m_argumentPositions.append(ArgumentPosition()); ArgumentPosition* argumentPosition = &byteCodeParser->m_graph.m_argumentPositions.last(); m_argumentPositions[i] = argumentPosition; @@ -3073,7 +3226,7 @@ bool ByteCodeParser::parse() m_graph.m_blocks[blockIndex].clear(); } - fixVariableAccessPredictions(); + fixVariableAccessSpeculations(); m_graph.m_preservedVars = m_preservedVars; m_graph.m_localVars = m_numLocals; |