void treatRootBlock(BasicBlock* block, InsertionSet& insertionSet) { Operands<VariableAccessData*> initialAccessData(block->variablesAtTail.numberOfArguments(), block->variablesAtTail.numberOfLocals(), nullptr); Operands<Node*> initialAccessNodes(block->variablesAtTail.numberOfArguments(), block->variablesAtTail.numberOfLocals(), nullptr); for (unsigned i = 0; i < block->size(); i++) { Node* node = block->at(i); if (!node->hasVariableAccessData(m_graph)) continue; VirtualRegister operand = node->local(); if (initialAccessData.operand(operand)) continue; DFG_ASSERT(m_graph, node, node->op() != SetLocal); // We should have inserted a Flush before this! initialAccessData.operand(operand) = node->variableAccessData(); initialAccessNodes.operand(operand) = node; } // We want every Flush to be able to reach backwards to // a SetLocal. Doing this in the root block achieves this goal. NodeOrigin origin = block->at(0)->origin; Node* undefined = insertionSet.insertConstant(0, origin, jsUndefined()); for (unsigned i = 0; i < block->variablesAtTail.numberOfLocals(); i++) { VirtualRegister operand = virtualRegisterForLocal(i); VariableAccessData* accessData; DFG_ASSERT(m_graph, nullptr, initialAccessNodes.operand(operand)->op() == Flush); // We should have inserted a Flush before any SetLocal/SetArgument for the local that we are analyzing now. accessData = initialAccessData.operand(operand); DFG_ASSERT(m_graph, nullptr, accessData); insertionSet.insertNode(0, SpecNone, SetLocal, origin, OpInfo(accessData), Edge(undefined)); } }
void treatRegularBlock(BasicBlock* block, InsertionSet& insertionSet) { Operands<VariableAccessData*> currentBlockAccessData(block->variablesAtTail.numberOfArguments(), block->variablesAtTail.numberOfLocals(), nullptr); // Insert a Flush before every SetLocal to properly pattern the graph such that // any range between SetLocal and Flush has access to the local on the stack. { for (unsigned i = 0; i < block->size(); i++) { Node* node = block->at(i); bool isPrimordialSetArgument = node->op() == SetArgument && node->local().isArgument() && node == m_graph.m_arguments[node->local().toArgument()]; if (node->op() == SetLocal || (node->op() == SetArgument && !isPrimordialSetArgument)) { VirtualRegister operand = node->local(); VariableAccessData* flushAccessData = currentBlockAccessData.operand(operand); if (!flushAccessData) flushAccessData = newVariableAccessData(operand); insertionSet.insertNode(i, SpecNone, Flush, node->origin, OpInfo(flushAccessData)); } if (node->hasVariableAccessData(m_graph)) currentBlockAccessData.operand(node->local()) = node->variableAccessData(); } } // Flush everything at the end of the block. { NodeOrigin origin = block->at(block->size() - 1)->origin; auto insertFlushAtEnd = [&] (VirtualRegister operand) { VariableAccessData* accessData = currentBlockAccessData.operand(operand); if (!accessData) accessData = newVariableAccessData(operand); currentBlockAccessData.operand(operand) = accessData; insertionSet.insertNode(block->size(), SpecNone, Flush, origin, OpInfo(accessData)); }; for (unsigned i = 0; i < block->variablesAtTail.numberOfLocals(); i++) insertFlushAtEnd(virtualRegisterForLocal(i)); for (unsigned i = 0; i < block->variablesAtTail.numberOfArguments(); i++) insertFlushAtEnd(virtualRegisterForArgument(i)); } }
void insertInferredTypeCheck( InsertionSet& insertionSet, unsigned nodeIndex, NodeOrigin origin, Node* baseNode, const InferredType::Descriptor& type) { insertionSet.graph().registerInferredType(type); switch (type.kind()) { case InferredType::Bottom: insertionSet.insertNode(nodeIndex, SpecNone, ForceOSRExit, origin); return; case InferredType::Boolean: insertionSet.insertNode(nodeIndex, SpecNone, Check, origin, Edge(baseNode, BooleanUse)); return; case InferredType::Other: insertionSet.insertNode(nodeIndex, SpecNone, Check, origin, Edge(baseNode, OtherUse)); return; case InferredType::Int32: insertionSet.insertNode(nodeIndex, SpecNone, Check, origin, Edge(baseNode, Int32Use)); return; case InferredType::Number: insertionSet.insertNode(nodeIndex, SpecNone, Check, origin, Edge(baseNode, NumberUse)); return; case InferredType::String: insertionSet.insertNode(nodeIndex, SpecNone, Check, origin, Edge(baseNode, StringUse)); return; case InferredType::Symbol: insertionSet.insertNode(nodeIndex, SpecNone, Check, origin, Edge(baseNode, SymbolUse)); return; case InferredType::ObjectWithStructure: insertionSet.insertNode( nodeIndex, SpecNone, CheckStructure, origin, OpInfo(insertionSet.graph().addStructureSet(type.structure())), Edge(baseNode, CellUse)); return; case InferredType::ObjectWithStructureOrOther: insertionSet.insertNode( nodeIndex, SpecNone, CheckStructure, origin, OpInfo(insertionSet.graph().addStructureSet(type.structure())), Edge(baseNode, CellOrOtherUse)); return; case InferredType::Object: insertionSet.insertNode(nodeIndex, SpecNone, Check, origin, Edge(baseNode, ObjectUse)); return; case InferredType::ObjectOrOther: insertionSet.insertNode(nodeIndex, SpecNone, Check, origin, Edge(baseNode, ObjectOrOtherUse)); return; case InferredType::Top: return; } DFG_CRASH(insertionSet.graph(), baseNode, "Bad inferred type"); }
void handleBlockForTryCatch(BasicBlock* block, InsertionSet& insertionSet) { HandlerInfo* currentExceptionHandler = nullptr; FastBitVector liveAtCatchHead; liveAtCatchHead.resize(m_graph.block(0)->variablesAtTail.numberOfLocals()); HandlerInfo* cachedHandlerResult; CodeOrigin cachedCodeOrigin; auto catchHandler = [&] (CodeOrigin origin) -> HandlerInfo* { ASSERT(origin); if (origin == cachedCodeOrigin) return cachedHandlerResult; unsigned bytecodeIndexToCheck = origin.bytecodeIndex; cachedCodeOrigin = origin; while (1) { InlineCallFrame* inlineCallFrame = origin.inlineCallFrame; CodeBlock* codeBlock = m_graph.baselineCodeBlockFor(inlineCallFrame); if (HandlerInfo* handler = codeBlock->handlerForBytecodeOffset(bytecodeIndexToCheck)) { liveAtCatchHead.clearAll(); unsigned catchBytecodeIndex = handler->target; m_graph.forAllLocalsLiveInBytecode(CodeOrigin(catchBytecodeIndex, inlineCallFrame), [&] (VirtualRegister operand) { liveAtCatchHead[operand.toLocal()] = true; }); cachedHandlerResult = handler; break; } if (!inlineCallFrame) { cachedHandlerResult = nullptr; break; } bytecodeIndexToCheck = inlineCallFrame->directCaller.bytecodeIndex; origin = inlineCallFrame->directCaller; } return cachedHandlerResult; }; Operands<VariableAccessData*> currentBlockAccessData(block->variablesAtTail.numberOfArguments(), block->variablesAtTail.numberOfLocals(), nullptr); HashSet<InlineCallFrame*> seenInlineCallFrames; auto flushEverything = [&] (NodeOrigin origin, unsigned index) { RELEASE_ASSERT(currentExceptionHandler); auto flush = [&] (VirtualRegister operand, bool alwaysInsert) { if ((operand.isLocal() && liveAtCatchHead[operand.toLocal()]) || operand.isArgument() || alwaysInsert) { ASSERT(isValidFlushLocation(block, index, operand)); VariableAccessData* accessData = currentBlockAccessData.operand(operand); if (!accessData) accessData = newVariableAccessData(operand); currentBlockAccessData.operand(operand) = accessData; insertionSet.insertNode(index, SpecNone, Flush, origin, OpInfo(accessData)); } }; for (unsigned local = 0; local < block->variablesAtTail.numberOfLocals(); local++) flush(virtualRegisterForLocal(local), false); for (InlineCallFrame* inlineCallFrame : seenInlineCallFrames) flush(VirtualRegister(inlineCallFrame->stackOffset + CallFrame::thisArgumentOffset()), true); flush(VirtualRegister(CallFrame::thisArgumentOffset()), true); seenInlineCallFrames.clear(); }; for (unsigned nodeIndex = 0; nodeIndex < block->size(); nodeIndex++) { Node* node = block->at(nodeIndex); { HandlerInfo* newHandler = catchHandler(node->origin.semantic); if (newHandler != currentExceptionHandler && currentExceptionHandler) flushEverything(node->origin, nodeIndex); currentExceptionHandler = newHandler; } if (currentExceptionHandler && (node->op() == SetLocal || node->op() == SetArgument)) { InlineCallFrame* inlineCallFrame = node->origin.semantic.inlineCallFrame; if (inlineCallFrame) seenInlineCallFrames.add(inlineCallFrame); VirtualRegister operand = node->local(); int stackOffset = inlineCallFrame ? inlineCallFrame->stackOffset : 0; if ((operand.isLocal() && liveAtCatchHead[operand.toLocal()]) || operand.isArgument() || (operand.offset() == stackOffset + CallFrame::thisArgumentOffset())) { ASSERT(isValidFlushLocation(block, nodeIndex, operand)); VariableAccessData* variableAccessData = currentBlockAccessData.operand(operand); if (!variableAccessData) variableAccessData = newVariableAccessData(operand); insertionSet.insertNode(nodeIndex, SpecNone, Flush, node->origin, OpInfo(variableAccessData)); } } if (node->accessesStack(m_graph)) currentBlockAccessData.operand(node->local()) = node->variableAccessData(); } if (currentExceptionHandler) { NodeOrigin origin = block->at(block->size() - 1)->origin; flushEverything(origin, block->size()); } }