diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp | 488 |
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; } |