diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-03 09:55:33 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-03 09:55:33 +0100 |
commit | cd44dc59cdfc39534aef4d417e9f3c412e3be139 (patch) | |
tree | 8d89889ba95ed6ec9322e733846cc9cce9d7dff1 /Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp | |
parent | d11f84f5b5cdc0d92a08af01b13472fdd5f9acb9 (diff) | |
download | qtwebkit-cd44dc59cdfc39534aef4d417e9f3c412e3be139.tar.gz |
Imported WebKit commit fce473cb4d55aa9fe9d0b0322a2fffecb731b961 (http://svn.webkit.org/repository/webkit/trunk@106560)
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp | 329 |
1 files changed, 155 insertions, 174 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 964618c43..87c3a23b9 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -28,9 +28,13 @@ #if ENABLE(DFG_JIT) +#include "CallLinkStatus.h" +#include "CodeBlock.h" #include "DFGByteCodeCache.h" #include "DFGCapabilities.h" -#include "CodeBlock.h" +#include "GetByIdStatus.h" +#include "MethodCallLinkStatus.h" +#include "PutByIdStatus.h" #include <wtf/HashMap.h> #include <wtf/MathExtras.h> @@ -48,6 +52,7 @@ public: , m_graph(graph) , m_currentBlock(0) , m_currentIndex(0) + , m_currentProfilingIndex(0) , m_constantUndefined(UINT_MAX) , m_constantNull(UINT_MAX) , m_constantNaN(UINT_MAX) @@ -329,7 +334,8 @@ private: JSValue v = valueOfJSConstant(index); if (v.isInt32()) return getJSConstant(node.constantNumber()); - // FIXME: We could convert the double ToInteger at this point. + if (v.isNumber()) + return getJSConstantForValue(JSValue(JSC::toInt32(v.asNumber()))); } return addToGraph(ValueToInt32, index); @@ -351,6 +357,17 @@ private: return addToGraph(ValueToNumber, OpInfo(NodeUseBottom), index); } + + NodeIndex getJSConstantForValue(JSValue constantValue) + { + unsigned constantIndex = m_codeBlock->addOrFindConstant(constantValue); + if (constantIndex >= m_constants.size()) + m_constants.append(ConstantRecord()); + + ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); + + return getJSConstant(constantIndex); + } NodeIndex getJSConstant(unsigned constant) { @@ -382,16 +399,6 @@ private: { return isJSConstant(nodeIndex) && valueOfJSConstant(nodeIndex).isInt32(); } - bool isSmallInt32Constant(NodeIndex nodeIndex) - { - if (!isJSConstant(nodeIndex)) - return false; - JSValue value = valueOfJSConstant(nodeIndex); - if (!value.isInt32()) - return false; - int32_t intValue = value.asInt32(); - return intValue >= -5 && intValue <= 5; - } // Convenience methods for getting constant values. JSValue valueOfJSConstant(NodeIndex index) { @@ -403,7 +410,7 @@ private: ASSERT(isInt32Constant(nodeIndex)); return valueOfJSConstant(nodeIndex).asInt32(); } - + // This method returns a JSConstant with the value 'undefined'. NodeIndex constantUndefined() { @@ -519,7 +526,7 @@ private: CodeOrigin currentCodeOrigin() { - return CodeOrigin(m_currentIndex, m_inlineStackTop->m_inlineCallFrame); + return CodeOrigin(m_currentIndex, m_inlineStackTop->m_inlineCallFrame, m_currentProfilingIndex - m_currentIndex); } // These methods create a node and add it to the graph. If nodes of this type are @@ -574,8 +581,10 @@ private: Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call); PredictedType prediction = PredictNone; - if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) - prediction = getPrediction(m_graph.size(), m_currentIndex + OPCODE_LENGTH(op_call)); + if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { + m_currentProfilingIndex = m_currentIndex + OPCODE_LENGTH(op_call); + prediction = getPrediction(); + } addVarArgChild(get(currentInstruction[1].u.operand)); int argCount = currentInstruction[2].u.operand; @@ -622,12 +631,12 @@ private: PredictedType getPredictionWithoutOSRExit() { - return getPredictionWithoutOSRExit(m_graph.size(), m_currentIndex); + return getPredictionWithoutOSRExit(m_graph.size(), m_currentProfilingIndex); } PredictedType getPrediction() { - return getPrediction(m_graph.size(), m_currentIndex); + return getPrediction(m_graph.size(), m_currentProfilingIndex); } NodeIndex makeSafe(NodeIndex nodeIndex) @@ -700,6 +709,29 @@ private: return nodeIndex; } + bool willNeedFlush(StructureStubInfo& stubInfo) + { + PolymorphicAccessStructureList* list; + int listSize; + switch (stubInfo.accessType) { + case access_get_by_id_self_list: + list = stubInfo.u.getByIdSelfList.structureList; + listSize = stubInfo.u.getByIdSelfList.listSize; + break; + case access_get_by_id_proto_list: + list = stubInfo.u.getByIdProtoList.structureList; + listSize = stubInfo.u.getByIdProtoList.listSize; + break; + default: + return false; + } + for (int i = 0; i < listSize; ++i) { + if (!list->list[i].isDirect) + return true; + } + return false; + } + bool structureChainIsStillValid(bool direct, Structure* previousStructure, StructureChain* chain) { if (direct) @@ -727,6 +759,8 @@ private: BasicBlock* m_currentBlock; // The bytecode index of the current instruction being generated. unsigned m_currentIndex; + // The bytecode index of the value profile of the current instruction being generated. + unsigned m_currentProfilingIndex; // We use these values during code generation, and to avoid the need for // special handling we make sure they are available as constants in the @@ -890,6 +924,7 @@ private: m_currentIndex += OPCODE_LENGTH(name); \ return shouldContinueParsing + void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentInstruction, NodeType op, CodeSpecializationKind kind) { ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); @@ -898,13 +933,15 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn enum { ConstantFunction, LinkedFunction, UnknownFunction } callType; #if DFG_ENABLE(DEBUG_VERBOSE) - printf("Slow case count for call at @%lu bc#%u: %u/%u; exit profile: %d.\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_profiledBlock->executionEntryCount(), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)); + printf("Slow case count for call at @%zu bc#%u: %u/%u; exit profile: %d.\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_profiledBlock->executionEntryCount(), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)); #endif - + + CallLinkStatus callLinkStatus = CallLinkStatus::computeFor( + m_inlineStackTop->m_profiledBlock, m_currentIndex); + if (m_graph.isFunctionConstant(m_codeBlock, callTarget)) callType = ConstantFunction; - else if (!!m_inlineStackTop->m_profiledBlock->getCallLinkInfo(m_currentIndex).lastSeenCallee - && !m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex) + else if (callLinkStatus.isSet() && !callLinkStatus.couldTakeSlowPath() && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) callType = LinkedFunction; else @@ -922,7 +959,8 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { resultOperand = putInstruction[1].u.operand; usesResult = true; - prediction = getPrediction(m_graph.size(), nextOffset); + m_currentProfilingIndex = nextOffset; + prediction = getPrediction(); nextOffset += OPCODE_LENGTH(op_call_put_result); } JSFunction* expectedFunction; @@ -934,7 +972,7 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn certainAboutExpectedFunction = true; } else { ASSERT(callType == LinkedFunction); - expectedFunction = m_inlineStackTop->m_profiledBlock->getCallLinkInfo(m_currentIndex).lastSeenCallee.get(); + expectedFunction = callLinkStatus.callTarget(); intrinsic = expectedFunction->executable()->intrinsicFor(kind); certainAboutExpectedFunction = false; } @@ -1029,7 +1067,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c int inlineCallFrameStart = m_inlineStackTop->remapOperand(registerOffset) - RegisterFile::CallFrameHeaderSize; // Make sure that the area used by the call frame is reserved. - for (int arg = inlineCallFrameStart + RegisterFile::CallFrameHeaderSize + codeBlock->m_numVars; arg-- > inlineCallFrameStart + 1;) + for (int arg = inlineCallFrameStart + RegisterFile::CallFrameHeaderSize + codeBlock->m_numVars; arg-- > inlineCallFrameStart;) m_preservedVars.set(m_inlineStackTop->remapOperand(arg)); // Make sure that we have enough locals. @@ -1044,13 +1082,16 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c // This is where the actual inlining really happens. unsigned oldIndex = m_currentIndex; + unsigned oldProfilingIndex = m_currentProfilingIndex; m_currentIndex = 0; + m_currentProfilingIndex = 0; addToGraph(InlineStart); parseCodeBlock(); m_currentIndex = oldIndex; + m_currentProfilingIndex = oldProfilingIndex; // If the inlined code created some new basic blocks, then we have linking to do. if (inlineStackEntry.m_callsiteBlockHead != m_graph.m_blocks.size() - 1) { @@ -1129,7 +1170,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c // Need to create a new basic block for the continuation at the caller. OwnPtr<BasicBlock> block = adoptPtr(new BasicBlock(nextOffset, m_graph.size(), m_numArguments, m_numLocals)); #if DFG_ENABLE(DEBUG_VERBOSE) - printf("Creating inline epilogue basic block %p, #%lu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame)); + printf("Creating inline epilogue basic block %p, #%zu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame)); #endif m_currentBlock = block.get(); ASSERT(m_inlineStackTop->m_caller->m_blockLinkingTargets.isEmpty() || m_graph.m_blocks[m_inlineStackTop->m_caller->m_blockLinkingTargets.last()]->bytecodeBegin < nextOffset); @@ -1308,6 +1349,8 @@ bool ByteCodeParser::parseBlock(unsigned limit) } while (true) { + m_currentProfilingIndex = m_currentIndex; + // Don't extend over jump destinations. if (m_currentIndex == limit) { // Ordinarily we want to plant a jump. But refuse to do this if the block is @@ -1680,6 +1723,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_method_check: { + m_currentProfilingIndex += OPCODE_LENGTH(op_method_check); Instruction* getInstruction = currentInstruction + OPCODE_LENGTH(op_method_check); PredictedType prediction = getPrediction(); @@ -1691,23 +1735,26 @@ bool ByteCodeParser::parseBlock(unsigned limit) // Check if the method_check was monomorphic. If so, emit a CheckXYZMethod // node, which is a lot more efficient. - StructureStubInfo& stubInfo = m_inlineStackTop->m_profiledBlock->getStubInfo(m_currentIndex); - MethodCallLinkInfo& methodCall = m_inlineStackTop->m_profiledBlock->getMethodCallLinkInfo(m_currentIndex); + GetByIdStatus getByIdStatus = GetByIdStatus::computeFor( + m_inlineStackTop->m_profiledBlock, + m_currentIndex, + m_codeBlock->identifier(identifier)); + MethodCallLinkStatus methodCallStatus = MethodCallLinkStatus::computeFor( + m_inlineStackTop->m_profiledBlock, m_currentIndex); - if (methodCall.seen - && !!methodCall.cachedStructure - && !stubInfo.seen + if (methodCallStatus.isSet() + && !getByIdStatus.isSet() && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) { // It's monomorphic as far as we can tell, since the method_check was linked // but the slow path (i.e. the normal get_by_id) never fired. - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCall.cachedStructure.get())), base); - if (methodCall.cachedPrototype.get() != m_inlineStackTop->m_profiledBlock->globalObject()->methodCallDummy()) - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCall.cachedPrototypeStructure.get())), cellConstant(methodCall.cachedPrototype.get())); + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCallStatus.structure())), base); + if (methodCallStatus.needsPrototypeCheck()) + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCallStatus.prototypeStructure())), cellConstant(methodCallStatus.prototype())); - set(getInstruction[1].u.operand, cellConstant(methodCall.cachedFunction.get())); + set(getInstruction[1].u.operand, cellConstant(methodCallStatus.function())); } else - set(getInstruction[1].u.operand, addToGraph(GetById, OpInfo(identifier), OpInfo(prediction), base)); + set(getInstruction[1].u.operand, addToGraph(getByIdStatus.makesCalls() ? GetByIdFlush : GetById, OpInfo(identifier), OpInfo(prediction), base)); m_currentIndex += OPCODE_LENGTH(op_method_check) + OPCODE_LENGTH(op_get_by_id); continue; @@ -1737,178 +1784,109 @@ bool ByteCodeParser::parseBlock(unsigned limit) unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand]; Identifier identifier = m_codeBlock->identifier(identifierNumber); - StructureStubInfo& stubInfo = m_inlineStackTop->m_profiledBlock->getStubInfo(m_currentIndex); + GetByIdStatus getByIdStatus = GetByIdStatus::computeFor( + m_inlineStackTop->m_profiledBlock, m_currentIndex, identifier); #if DFG_ENABLE(DEBUG_VERBOSE) - printf("Slow case count for GetById @%lu bc#%u: %u; exit profile: %d\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)); + printf("Slow case count for GetById @%zu bc#%u: %u; exit profile: %d\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)); #endif - size_t offset = notFound; - StructureSet structureSet; - if (stubInfo.seen - && !m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex) + if (getByIdStatus.isSimpleDirect() && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) { - switch (stubInfo.accessType) { - case access_get_by_id_self: { - Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get(); - offset = structure->get(*m_globalData, identifier); - - if (offset != notFound) - structureSet.add(structure); - - if (offset != notFound) - ASSERT(structureSet.size()); - break; - } - - case access_get_by_id_self_list: { - PolymorphicAccessStructureList* list = stubInfo.u.getByIdProtoList.structureList; - unsigned size = stubInfo.u.getByIdProtoList.listSize; - for (unsigned i = 0; i < size; ++i) { - if (!list->list[i].isDirect) { - offset = notFound; - break; - } - - Structure* structure = list->list[i].base.get(); - if (structureSet.contains(structure)) - continue; - - size_t myOffset = structure->get(*m_globalData, identifier); - - if (myOffset == notFound) { - offset = notFound; - break; - } - - if (!i) - offset = myOffset; - else if (offset != myOffset) { - offset = notFound; - break; - } - - structureSet.add(structure); - } - - if (offset != notFound) - ASSERT(structureSet.size()); - break; - } - - default: - ASSERT(offset == notFound); - break; - } - } - - if (offset != notFound) { - ASSERT(structureSet.size()); + 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(structureSet)), base); + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(getByIdStatus.structureSet())), base); set(currentInstruction[1].u.operand, addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), addToGraph(GetPropertyStorage, base))); StorageAccessData storageAccessData; - storageAccessData.offset = offset; + storageAccessData.offset = getByIdStatus.offset(); storageAccessData.identifierNumber = identifierNumber; m_graph.m_storageAccessData.append(storageAccessData); } else - set(currentInstruction[1].u.operand, addToGraph(GetById, OpInfo(identifierNumber), OpInfo(prediction), base)); + set(currentInstruction[1].u.operand, addToGraph(getByIdStatus.makesCalls() ? GetByIdFlush : GetById, OpInfo(identifierNumber), OpInfo(prediction), base)); NEXT_OPCODE(op_get_by_id); } - case op_put_by_id: { NodeIndex value = get(currentInstruction[3].u.operand); NodeIndex base = get(currentInstruction[1].u.operand); unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand]; bool direct = currentInstruction[8].u.operand; - StructureStubInfo& stubInfo = m_inlineStackTop->m_profiledBlock->getStubInfo(m_currentIndex); - if (!stubInfo.seen) + PutByIdStatus putByIdStatus = PutByIdStatus::computeFor( + m_inlineStackTop->m_profiledBlock, + m_currentIndex, + m_codeBlock->identifier(identifierNumber)); + if (!putByIdStatus.isSet()) addToGraph(ForceOSRExit); - bool alreadyGenerated = false; + bool hasExitSite = m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache); #if DFG_ENABLE(DEBUG_VERBOSE) - printf("Slow case count for PutById @%lu bc#%u: %u; exit profile: %d\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)); + printf("Slow case count for PutById @%zu bc#%u: %u; exit profile: %d\n", m_graph.size(), m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)); #endif - if (stubInfo.seen - && !m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex) - && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) { - switch (stubInfo.accessType) { - case access_put_by_id_replace: { - Structure* structure = stubInfo.u.putByIdReplace.baseObjectStructure.get(); - Identifier identifier = m_codeBlock->identifier(identifierNumber); - size_t offset = structure->get(*m_globalData, identifier); - - if (offset != notFound) { - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structure)), base); - addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), base, addToGraph(GetPropertyStorage, base), value); - - StorageAccessData storageAccessData; - storageAccessData.offset = offset; - storageAccessData.identifierNumber = identifierNumber; - m_graph.m_storageAccessData.append(storageAccessData); - - alreadyGenerated = true; - } - break; - } - - case access_put_by_id_transition_normal: - case access_put_by_id_transition_direct: { - Structure* previousStructure = stubInfo.u.putByIdTransition.previousStructure.get(); - Structure* newStructure = stubInfo.u.putByIdTransition.structure.get(); - - if (previousStructure->propertyStorageCapacity() != newStructure->propertyStorageCapacity()) - break; - - StructureChain* structureChain = stubInfo.u.putByIdTransition.chain.get(); - - Identifier identifier = m_codeBlock->identifier(identifierNumber); - size_t offset = newStructure->get(*m_globalData, identifier); + if (!hasExitSite && putByIdStatus.isSimpleReplace()) { + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure())), base); + addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), base, addToGraph(GetPropertyStorage, base), value); + + StorageAccessData storageAccessData; + storageAccessData.offset = putByIdStatus.offset(); + storageAccessData.identifierNumber = identifierNumber; + m_graph.m_storageAccessData.append(storageAccessData); + } else if (!hasExitSite + && putByIdStatus.isSimpleTransition() + && putByIdStatus.oldStructure()->propertyStorageCapacity() == putByIdStatus.newStructure()->propertyStorageCapacity() + && structureChainIsStillValid( + direct, + putByIdStatus.oldStructure(), + putByIdStatus.structureChain())) { + + 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 (offset != notFound && structureChainIsStillValid(direct, previousStructure, structureChain)) { - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(previousStructure)), base); - if (!direct) { - if (!previousStructure->storedPrototype().isNull()) - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(previousStructure->storedPrototype().asCell()->structure())), cellConstant(previousStructure->storedPrototype().asCell())); - - for (WriteBarrier<Structure>* it = 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())); - } - } - addToGraph(PutStructure, OpInfo(m_graph.addStructureTransitionData(StructureTransitionData(previousStructure, newStructure))), base); - - addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), base, addToGraph(GetPropertyStorage, base), value); - - StorageAccessData storageAccessData; - storageAccessData.offset = offset; - storageAccessData.identifierNumber = identifierNumber; - m_graph.m_storageAccessData.append(storageAccessData); - - alreadyGenerated = true; + 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())); } - break; - } - - default: - break; } - } - - if (!alreadyGenerated) { + addToGraph( + PutStructure, + OpInfo( + m_graph.addStructureTransitionData( + StructureTransitionData( + putByIdStatus.oldStructure(), + putByIdStatus.newStructure()))), + base); + + addToGraph( + PutByOffset, + OpInfo(m_graph.m_storageAccessData.size()), + base, + addToGraph(GetPropertyStorage, base), + value); + + StorageAccessData storageAccessData; + storageAccessData.offset = putByIdStatus.offset(); + storageAccessData.identifierNumber = identifierNumber; + m_graph.m_storageAccessData.append(storageAccessData); + } else { if (direct) addToGraph(PutByIdDirect, OpInfo(identifierNumber), base, value); else @@ -2570,7 +2548,7 @@ void ByteCodeParser::parseCodeBlock() } else { OwnPtr<BasicBlock> block = adoptPtr(new BasicBlock(m_currentIndex, m_graph.size(), m_numArguments, m_numLocals)); #if DFG_ENABLE(DEBUG_VERBOSE) - printf("Creating basic block %p, #%lu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame)); + printf("Creating basic block %p, #%zu for %p bc#%u at inline depth %u.\n", block.get(), m_graph.m_blocks.size(), m_inlineStackTop->executable(), m_currentIndex, CodeOrigin::inlineDepthForCallFrame(m_inlineStackTop->m_inlineCallFrame)); #endif m_currentBlock = block.get(); ASSERT(m_inlineStackTop->m_unlinkedBlocks.isEmpty() || m_graph.m_blocks[m_inlineStackTop->m_unlinkedBlocks.last().m_blockIndex]->bytecodeBegin < m_currentIndex); @@ -2620,6 +2598,9 @@ bool ByteCodeParser::parse() #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) printf("Processing local variable phis.\n"); #endif + + m_currentProfilingIndex = m_currentIndex; + processPhiStack<LocalPhiStack>(); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) printf("Processing argument phis.\n"); |