summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-06-20 13:01:08 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-06-20 13:01:08 +0200
commit49233e234e5c787396cadb2cea33b31ae0cd65c1 (patch)
tree5410cb9a8fd53168bb60d62c54b654d86f03c38d /Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
parentb211c645d8ab690f713515dfdc84d80b11c27d2c (diff)
downloadqtwebkit-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.cpp319
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;