summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp488
1 files changed, 353 insertions, 135 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 4869cf8c1..36d18d7b3 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -169,12 +169,17 @@ private:
// 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, SpeculatedType prediction);
bool handleConstantInternalFunction(bool usesResult, int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind);
+ NodeIndex handleGetByOffset(SpeculatedType, NodeIndex base, unsigned identifierNumber, PropertyOffset);
void handleGetByOffset(
int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber,
PropertyOffset);
void handleGetById(
int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber,
const GetByIdStatus&);
+
+ // Convert a set of ResolveOperations into graph nodes
+ bool parseResolveOperations(SpeculatedType, unsigned identifierNumber, unsigned operations, unsigned putToBaseOperation, NodeIndex* base, NodeIndex* value);
+
// Prepare to parse a block.
void prepareToParseBlock();
// Parse a single basic block of bytecode instructions.
@@ -1143,6 +1148,8 @@ private:
Vector<unsigned> m_identifierRemap;
Vector<unsigned> m_constantRemap;
Vector<unsigned> m_constantBufferRemap;
+ Vector<unsigned> m_resolveOperationRemap;
+ Vector<unsigned> m_putToBaseOperationRemap;
// Blocks introduced by this code block, which need successor linking.
// May include up to one basic block that includes the continuation after
@@ -1779,24 +1786,28 @@ bool ByteCodeParser::handleConstantInternalFunction(
return false;
}
-void ByteCodeParser::handleGetByOffset(
- int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber,
- PropertyOffset offset)
+NodeIndex ByteCodeParser::handleGetByOffset(SpeculatedType prediction, NodeIndex base, unsigned identifierNumber, PropertyOffset offset)
{
NodeIndex propertyStorage;
if (isInlineOffset(offset))
propertyStorage = base;
else
propertyStorage = addToGraph(GetButterfly, base);
- set(destinationOperand,
- addToGraph(
- GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction),
- propertyStorage));
-
+ NodeIndex getByOffset = addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), propertyStorage);
+
StorageAccessData storageAccessData;
storageAccessData.offset = indexRelativeToBase(offset);
storageAccessData.identifierNumber = identifierNumber;
m_graph.m_storageAccessData.append(storageAccessData);
+
+ return getByOffset;
+}
+
+void ByteCodeParser::handleGetByOffset(
+ int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber,
+ PropertyOffset offset)
+{
+ set(destinationOperand, handleGetByOffset(prediction, base, identifierNumber, offset));
}
void ByteCodeParser::handleGetById(
@@ -1860,10 +1871,174 @@ void ByteCodeParser::prepareToParseBlock()
m_cellConstantNodes.clear();
}
+bool ByteCodeParser::parseResolveOperations(SpeculatedType prediction, unsigned identifier, unsigned operations, unsigned putToBaseOperation, NodeIndex* base, NodeIndex* value)
+{
+ ResolveOperations* resolveOperations = m_codeBlock->resolveOperations(operations);
+ if (resolveOperations->isEmpty()) {
+ addToGraph(ForceOSRExit);
+ return false;
+ }
+ JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
+ int skipCount = 0;
+ bool skippedScopes = false;
+ bool setBase = false;
+ ResolveOperation* pc = resolveOperations->data();
+ NodeIndex localBase = 0;
+ bool resolvingBase = true;
+ while (resolvingBase) {
+ switch (pc->m_operation) {
+ case ResolveOperation::ReturnGlobalObjectAsBase:
+ *base = get(m_codeBlock->globalObjectConstant());
+ ASSERT(!value);
+ return true;
+
+ case ResolveOperation::SetBaseToGlobal:
+ *base = get(m_codeBlock->globalObjectConstant());
+ setBase = true;
+ resolvingBase = false;
+ ++pc;
+ break;
+
+ case ResolveOperation::SetBaseToUndefined:
+ *base = constantUndefined();
+ setBase = true;
+ resolvingBase = false;
+ ++pc;
+ break;
+
+ case ResolveOperation::SetBaseToScope:
+ localBase = addToGraph(GetScope, OpInfo(skipCount));
+ *base = localBase;
+ setBase = true;
+
+ resolvingBase = false;
+
+ // Reset the scope skipping as we've already loaded it
+ skippedScopes = false;
+ ++pc;
+ break;
+ case ResolveOperation::ReturnScopeAsBase:
+ *base = addToGraph(GetScope, OpInfo(skipCount));
+ ASSERT(!value);
+ return true;
+
+ case ResolveOperation::SkipTopScopeNode:
+ if (m_inlineStackTop->m_inlineCallFrame)
+ return false;
+ skipCount = 1;
+ skippedScopes = true;
+ ++pc;
+ break;
+
+ case ResolveOperation::SkipScopes:
+ if (m_inlineStackTop->m_inlineCallFrame)
+ return false;
+ skipCount += pc->m_scopesToSkip;
+ skippedScopes = true;
+ ++pc;
+ break;
+
+ case ResolveOperation::CheckForDynamicEntriesBeforeGlobalScope:
+ return false;
+
+ case ResolveOperation::Fail:
+ return false;
+
+ default:
+ resolvingBase = false;
+ }
+ }
+ if (skippedScopes)
+ localBase = addToGraph(GetScope, OpInfo(skipCount));
+
+ if (base && !setBase)
+ *base = localBase;
+
+ ASSERT(value);
+ ResolveOperation* resolveValueOperation = pc;
+ switch (resolveValueOperation->m_operation) {
+ case ResolveOperation::GetAndReturnGlobalProperty: {
+ ResolveGlobalStatus status = ResolveGlobalStatus::computeFor(m_inlineStackTop->m_profiledBlock, m_currentIndex, resolveValueOperation, m_codeBlock->identifier(identifier));
+ if (status.isSimple()) {
+ ASSERT(status.structure());
+
+ NodeIndex globalObjectNode = addStructureTransitionCheck(globalObject, status.structure());
+
+ if (status.specificValue()) {
+ ASSERT(status.specificValue().isCell());
+ *value = cellConstant(status.specificValue().asCell());
+ } else
+ *value = handleGetByOffset(prediction, globalObjectNode, identifier, status.offset());
+ return true;
+ }
+
+ NodeIndex resolve = addToGraph(ResolveGlobal, OpInfo(m_graph.m_resolveGlobalData.size()), OpInfo(prediction));
+ m_graph.m_resolveGlobalData.append(ResolveGlobalData());
+ ResolveGlobalData& data = m_graph.m_resolveGlobalData.last();
+ data.identifierNumber = identifier;
+ data.resolveOperationsIndex = operations;
+ data.putToBaseOperationIndex = putToBaseOperation;
+ data.resolvePropertyIndex = resolveValueOperation - resolveOperations->data();
+ *value = resolve;
+ return true;
+ }
+ case ResolveOperation::GetAndReturnGlobalVar: {
+ *value = addToGraph(GetGlobalVar,
+ OpInfo(globalObject->assertRegisterIsInThisObject(pc->m_registerAddress)),
+ OpInfo(prediction));
+ return true;
+ }
+ case ResolveOperation::GetAndReturnGlobalVarWatchable: {
+ SpeculatedType prediction = getPrediction();
+
+ JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
+
+ Identifier ident = m_codeBlock->identifier(identifier);
+ SymbolTableEntry entry = globalObject->symbolTable()->get(ident.impl());
+ if (!entry.couldBeWatched()) {
+ *value = addToGraph(GetGlobalVar, OpInfo(globalObject->assertRegisterIsInThisObject(pc->m_registerAddress)), OpInfo(prediction));
+ return true;
+ }
+
+ // 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(pc->m_registerAddress)), OpInfo(identifier));
+
+ JSValue specificValue = globalObject->registerAt(entry.getIndex()).get();
+ ASSERT(specificValue.isCell());
+ *value = cellConstant(specificValue.asCell());
+ return true;
+ }
+ case ResolveOperation::GetAndReturnScopedVar: {
+ NodeIndex getScopeRegisters = addToGraph(GetScopeRegisters, localBase);
+ *value = addToGraph(GetScopedVar, OpInfo(resolveValueOperation->m_offset), OpInfo(prediction), getScopeRegisters);
+ return true;
+ }
+ default:
+ CRASH();
+ return false;
+ }
+
+}
+
bool ByteCodeParser::parseBlock(unsigned limit)
{
bool shouldContinueParsing = true;
-
+
Interpreter* interpreter = m_globalData->interpreter;
Instruction* instructionsBegin = m_inlineStackTop->m_codeBlock->instructions().begin();
unsigned blockBegin = m_currentIndex;
@@ -2364,26 +2539,6 @@ bool ByteCodeParser::parseBlock(unsigned limit)
m_currentIndex += OPCODE_LENGTH(op_method_check) + OPCODE_LENGTH(op_get_by_id);
continue;
}
- case op_get_scoped_var: {
- SpeculatedType prediction = getPrediction();
- int dst = currentInstruction[1].u.operand;
- int slot = currentInstruction[2].u.operand;
- int depth = currentInstruction[3].u.operand;
- 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);
- }
- case op_put_scoped_var: {
- int slot = currentInstruction[1].u.operand;
- int depth = currentInstruction[2].u.operand;
- int source = currentInstruction[3].u.operand;
- 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:
case op_get_by_id_out_of_line:
case op_get_array_length: {
@@ -2510,75 +2665,15 @@ bool ByteCodeParser::parseBlock(unsigned limit)
NEXT_OPCODE(op_put_by_id);
}
- case op_get_global_var: {
- SpeculatedType prediction = getPrediction();
-
- 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:
case op_init_global_const: {
NodeIndex value = get(currentInstruction[2].u.operand);
addToGraph(
PutGlobalVar,
OpInfo(m_inlineStackTop->m_codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)),
value);
- NEXT_OPCODE(op_put_global_var);
+ NEXT_OPCODE(op_init_global_const);
}
- case op_put_global_var_check:
case op_init_global_const_check: {
NodeIndex value = get(currentInstruction[2].u.operand);
CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock;
@@ -2591,16 +2686,17 @@ bool ByteCodeParser::parseBlock(unsigned limit)
PutGlobalVar,
OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)),
value);
- NEXT_OPCODE(op_put_global_var_check);
+ NEXT_OPCODE(op_init_global_const_check);
}
addToGraph(
PutGlobalVarCheck,
OpInfo(codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)),
OpInfo(identifierNumber),
value);
- NEXT_OPCODE(op_put_global_var_check);
+ NEXT_OPCODE(op_init_global_const_check);
}
+
// === Block terminators. ===
case op_jmp: {
@@ -2869,69 +2965,175 @@ bool ByteCodeParser::parseBlock(unsigned limit)
addToGraph(Jump, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jneq_ptr)));
LAST_OPCODE(op_jneq_ptr);
- case op_resolve: {
+ case op_resolve:
+ case op_resolve_global_property:
+ case op_resolve_global_var:
+ case op_resolve_scoped_var:
+ case op_resolve_scoped_var_on_top_scope:
+ case op_resolve_scoped_var_with_top_scope_check: {
SpeculatedType prediction = getPrediction();
unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand];
+ unsigned operations = m_inlineStackTop->m_resolveOperationRemap[currentInstruction[3].u.operand];
+ NodeIndex value = 0;
+ if (parseResolveOperations(prediction, identifier, operations, 0, 0, &value)) {
+ set(currentInstruction[1].u.operand, value);
+ NEXT_OPCODE(op_resolve);
+ }
+
+ NodeIndex resolve = addToGraph(Resolve, OpInfo(m_graph.m_resolveOperationsData.size()), OpInfo(prediction));
+ m_graph.m_resolveOperationsData.append(ResolveOperationData());
+ ResolveOperationData& data = m_graph.m_resolveOperationsData.last();
+ data.identifierNumber = identifier;
+ data.resolveOperationsIndex = operations;
- NodeIndex resolve = addToGraph(Resolve, OpInfo(identifier), OpInfo(prediction));
set(currentInstruction[1].u.operand, resolve);
NEXT_OPCODE(op_resolve);
}
+ case op_put_to_base_variable:
+ case op_put_to_base: {
+ unsigned base = currentInstruction[1].u.operand;
+ unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand];
+ unsigned value = currentInstruction[3].u.operand;
+ unsigned operation = m_inlineStackTop->m_putToBaseOperationRemap[currentInstruction[4].u.operand];
+ PutToBaseOperation* putToBase = m_codeBlock->putToBaseOperation(operation);
+
+ if (putToBase->m_isDynamic) {
+ addToGraph(Phantom, get(base));
+ addToGraph(PutById, OpInfo(identifier), get(base), get(value));
+ NEXT_OPCODE(op_put_to_base);
+ }
+
+ switch (putToBase->m_kind) {
+ case PutToBaseOperation::Uninitialised:
+ addToGraph(Phantom, get(base));
+ addToGraph(ForceOSRExit);
+ break;
+
+ case PutToBaseOperation::GlobalVariablePutChecked: {
+ CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock;
+ JSGlobalObject* globalObject = codeBlock->globalObject();
+ SymbolTableEntry entry = globalObject->symbolTable()->get(m_codeBlock->identifier(identifier).impl());
+ if (entry.couldBeWatched()) {
+ addToGraph(PutGlobalVarCheck,
+ OpInfo(codeBlock->globalObject()->assertRegisterIsInThisObject(putToBase->m_registerAddress)),
+ OpInfo(identifier),
+ get(value));
+ break;
+ }
+ }
+ case PutToBaseOperation::GlobalVariablePut:
+ addToGraph(PutGlobalVar,
+ OpInfo(m_inlineStackTop->m_codeBlock->globalObject()->assertRegisterIsInThisObject(putToBase->m_registerAddress)),
+ get(value));
+ break;
+ case PutToBaseOperation::VariablePut: {
+ addToGraph(Phantom, get(base));
+ NodeIndex getScope = addToGraph(GetScope, OpInfo(putToBase->m_scopeDepth));
+ NodeIndex getScopeRegisters = addToGraph(GetScopeRegisters, getScope);
+ addToGraph(PutScopedVar, OpInfo(putToBase->m_offset), getScope, getScopeRegisters, get(value));
+ break;
+ }
+ case PutToBaseOperation::GlobalPropertyPut: {
+ if (!putToBase->m_structure) {
+ addToGraph(Phantom, get(base));
+ addToGraph(ForceOSRExit);
+ NEXT_OPCODE(op_put_to_base);
+ }
+ NodeIndex baseNode = get(base);
+ addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putToBase->m_structure.get())), baseNode);
+ NodeIndex propertyStorage;
+ if (isInlineOffset(putToBase->m_offset))
+ propertyStorage = baseNode;
+ else
+ propertyStorage = addToGraph(GetButterfly, baseNode);
+ addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), propertyStorage, baseNode, get(value));
+
+ StorageAccessData storageAccessData;
+ storageAccessData.offset = indexRelativeToBase(putToBase->m_offset);
+ storageAccessData.identifierNumber = identifier;
+ m_graph.m_storageAccessData.append(storageAccessData);
+ break;
+ }
+ case PutToBaseOperation::Readonly:
+ case PutToBaseOperation::Generic:
+ addToGraph(Phantom, get(base));
+ addToGraph(PutById, OpInfo(identifier), get(base), get(value));
+ }
+ NEXT_OPCODE(op_put_to_base);
+ }
+
+ case op_resolve_base_to_global:
+ case op_resolve_base_to_global_dynamic:
+ case op_resolve_base_to_scope:
+ case op_resolve_base_to_scope_with_top_scope_check:
case op_resolve_base: {
SpeculatedType prediction = getPrediction();
unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand];
+ unsigned operations = m_inlineStackTop->m_resolveOperationRemap[currentInstruction[4].u.operand];
+ unsigned putToBaseOperation = m_inlineStackTop->m_putToBaseOperationRemap[currentInstruction[5].u.operand];
- NodeIndex resolve = addToGraph(currentInstruction[3].u.operand ? ResolveBaseStrictPut : ResolveBase, OpInfo(identifier), OpInfo(prediction));
+ NodeIndex base = 0;
+ if (parseResolveOperations(prediction, identifier, operations, 0, &base, 0)) {
+ set(currentInstruction[1].u.operand, base);
+ NEXT_OPCODE(op_resolve_base);
+ }
+
+ NodeIndex resolve = addToGraph(currentInstruction[3].u.operand ? ResolveBaseStrictPut : ResolveBase, OpInfo(m_graph.m_resolveOperationsData.size()), OpInfo(prediction));
+ m_graph.m_resolveOperationsData.append(ResolveOperationData());
+ ResolveOperationData& data = m_graph.m_resolveOperationsData.last();
+ data.identifierNumber = identifier;
+ data.resolveOperationsIndex = operations;
+ data.putToBaseOperationIndex = putToBaseOperation;
+
set(currentInstruction[1].u.operand, resolve);
NEXT_OPCODE(op_resolve_base);
}
-
- case op_resolve_global: {
+ case op_resolve_with_base: {
SpeculatedType prediction = getPrediction();
-
- unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[
- currentInstruction[2].u.operand];
-
- ResolveGlobalStatus status = ResolveGlobalStatus::computeFor(
- m_inlineStackTop->m_profiledBlock, m_currentIndex,
- m_codeBlock->identifier(identifierNumber));
- if (status.isSimple()) {
- ASSERT(status.structure());
-
- NodeIndex globalObject = addStructureTransitionCheck(
- m_inlineStackTop->m_codeBlock->globalObject(), status.structure());
-
- if (status.specificValue()) {
- ASSERT(status.specificValue().isCell());
-
- set(currentInstruction[1].u.operand,
- cellConstant(status.specificValue().asCell()));
- } else {
- handleGetByOffset(
- currentInstruction[1].u.operand, prediction, globalObject,
- identifierNumber, status.offset());
- }
-
- m_globalResolveNumber++; // Skip over the unused global resolve info.
-
- NEXT_OPCODE(op_resolve_global);
+ unsigned baseDst = currentInstruction[1].u.operand;
+ unsigned valueDst = currentInstruction[2].u.operand;
+ unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
+ unsigned operations = m_inlineStackTop->m_resolveOperationRemap[currentInstruction[4].u.operand];
+ unsigned putToBaseOperation = m_inlineStackTop->m_putToBaseOperationRemap[currentInstruction[5].u.operand];
+
+ NodeIndex base = 0;
+ NodeIndex value = 0;
+ if (parseResolveOperations(prediction, identifier, operations, putToBaseOperation, &base, &value)) {
+ set(baseDst, base);
+ set(valueDst, value);
+ } else {
+ addToGraph(ForceOSRExit);
+ set(baseDst, addToGraph(GarbageValue));
+ set(valueDst, addToGraph(GarbageValue));
}
-
- NodeIndex resolve = addToGraph(ResolveGlobal, OpInfo(m_graph.m_resolveGlobalData.size()), OpInfo(prediction));
- m_graph.m_resolveGlobalData.append(ResolveGlobalData());
- ResolveGlobalData& data = m_graph.m_resolveGlobalData.last();
- data.identifierNumber = identifierNumber;
- data.resolveInfoIndex = m_globalResolveNumber++;
- set(currentInstruction[1].u.operand, resolve);
- NEXT_OPCODE(op_resolve_global);
+ NEXT_OPCODE(op_resolve_with_base);
}
+ case op_resolve_with_this: {
+ SpeculatedType prediction = getPrediction();
+ unsigned baseDst = currentInstruction[1].u.operand;
+ unsigned valueDst = currentInstruction[2].u.operand;
+ unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
+ unsigned operations = m_inlineStackTop->m_resolveOperationRemap[currentInstruction[4].u.operand];
+
+ NodeIndex base = 0;
+ NodeIndex value = 0;
+ if (parseResolveOperations(prediction, identifier, operations, 0, &base, &value)) {
+ set(baseDst, base);
+ set(valueDst, value);
+ } else {
+ addToGraph(ForceOSRExit);
+ set(baseDst, addToGraph(GarbageValue));
+ set(valueDst, addToGraph(GarbageValue));
+ }
+ NEXT_OPCODE(op_resolve_with_this);
+ }
case op_loop_hint: {
// Baseline->DFG OSR jumps between loop hints. The DFG assumes that Baseline->DFG
// OSR can only happen at basic block boundaries. Assert that these two statements
@@ -2943,7 +3145,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
// block. Hence, machine code block = true code block = not inline code block.
if (!m_inlineStackTop->m_caller)
m_currentBlock->isOSRTarget = true;
-
+
// Emit a phantom node to ensure that there is a placeholder node for this bytecode
// op.
addToGraph(Phantom);
@@ -3331,6 +3533,8 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
m_identifierRemap.resize(codeBlock->numberOfIdentifiers());
m_constantRemap.resize(codeBlock->numberOfConstantRegisters());
m_constantBufferRemap.resize(codeBlock->numberOfConstantBuffers());
+ m_resolveOperationRemap.resize(codeBlock->numberOfResolveOperations());
+ m_putToBaseOperationRemap.resize(codeBlock->numberOfPutToBaseOperations());
for (size_t i = 0; i < codeBlock->numberOfIdentifiers(); ++i) {
StringImpl* rep = codeBlock->identifier(i).impl();
@@ -3357,8 +3561,11 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
}
m_constantRemap[i] = result.iterator->value;
}
- for (unsigned i = 0; i < codeBlock->numberOfGlobalResolveInfos(); ++i)
- byteCodeParser->m_codeBlock->addGlobalResolveInfo(std::numeric_limits<unsigned>::max());
+ for (size_t i = 0; i < codeBlock->numberOfResolveOperations(); i++) {
+ uint32_t newResolve = byteCodeParser->m_codeBlock->addResolve();
+ m_resolveOperationRemap[i] = newResolve;
+ byteCodeParser->m_codeBlock->resolveOperations(newResolve)->append(*codeBlock->resolveOperations(i));
+ }
for (unsigned i = 0; i < codeBlock->numberOfConstantBuffers(); ++i) {
// If we inline the same code block multiple times, we don't want to needlessly
// duplicate its constant buffers.
@@ -3373,6 +3580,11 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
m_constantBufferRemap[i] = newIndex;
byteCodeParser->m_constantBufferCache.add(ConstantBufferKey(codeBlock, i), newIndex);
}
+ for (size_t i = 0; i < codeBlock->numberOfPutToBaseOperations(); i++) {
+ uint32_t putToBaseResolve = byteCodeParser->m_codeBlock->addPutToBase();
+ m_putToBaseOperationRemap[i] = putToBaseResolve;
+ *byteCodeParser->m_codeBlock->putToBaseOperation(putToBaseResolve) = *codeBlock->putToBaseOperation(i);
+ }
m_callsiteBlockHeadNeedsLinking = true;
} else {
@@ -3389,6 +3601,8 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
m_identifierRemap.resize(codeBlock->numberOfIdentifiers());
m_constantRemap.resize(codeBlock->numberOfConstantRegisters());
m_constantBufferRemap.resize(codeBlock->numberOfConstantBuffers());
+ m_resolveOperationRemap.resize(codeBlock->numberOfResolveOperations());
+ m_putToBaseOperationRemap.resize(codeBlock->numberOfPutToBaseOperations());
for (size_t i = 0; i < codeBlock->numberOfIdentifiers(); ++i)
m_identifierRemap[i] = i;
@@ -3396,6 +3610,10 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
m_constantRemap[i] = i + FirstConstantRegisterIndex;
for (size_t i = 0; i < codeBlock->numberOfConstantBuffers(); ++i)
m_constantBufferRemap[i] = i;
+ for (size_t i = 0; i < codeBlock->numberOfResolveOperations(); ++i)
+ m_resolveOperationRemap[i] = i;
+ for (size_t i = 0; i < codeBlock->numberOfPutToBaseOperations(); ++i)
+ m_putToBaseOperationRemap[i] = i;
m_callsiteBlockHeadNeedsLinking = false;
}