michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_MIRGraph_h michael@0: #define jit_MIRGraph_h michael@0: michael@0: // This file declares the data structures used to build a control-flow graph michael@0: // containing MIR. michael@0: michael@0: #include "jit/FixedList.h" michael@0: #include "jit/IonAllocPolicy.h" michael@0: #include "jit/MIR.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: class BytecodeAnalysis; michael@0: class MBasicBlock; michael@0: class MIRGraph; michael@0: class MStart; michael@0: michael@0: class MDefinitionIterator; michael@0: michael@0: typedef InlineListIterator MInstructionIterator; michael@0: typedef InlineListReverseIterator MInstructionReverseIterator; michael@0: typedef InlineForwardListIterator MPhiIterator; michael@0: typedef InlineForwardListIterator MResumePointIterator; michael@0: michael@0: class LBlock; michael@0: michael@0: class MBasicBlock : public TempObject, public InlineListNode michael@0: { michael@0: public: michael@0: enum Kind { michael@0: NORMAL, michael@0: PENDING_LOOP_HEADER, michael@0: LOOP_HEADER, michael@0: SPLIT_EDGE, michael@0: DEAD michael@0: }; michael@0: michael@0: private: michael@0: MBasicBlock(MIRGraph &graph, CompileInfo &info, jsbytecode *pc, Kind kind); michael@0: bool init(); michael@0: void copySlots(MBasicBlock *from); michael@0: bool inherit(TempAllocator &alloc, BytecodeAnalysis *analysis, MBasicBlock *pred, michael@0: uint32_t popped, unsigned stackPhiCount = 0); michael@0: bool inheritResumePoint(MBasicBlock *pred); michael@0: void assertUsesAreNotWithin(MUseIterator use, MUseIterator end); michael@0: michael@0: // This block cannot be reached by any means. michael@0: bool unreachable_; michael@0: michael@0: // Pushes a copy of a local variable or argument. michael@0: void pushVariable(uint32_t slot); michael@0: michael@0: // Sets a variable slot to the top of the stack, correctly creating copies michael@0: // as needed. michael@0: void setVariable(uint32_t slot); michael@0: michael@0: public: michael@0: /////////////////////////////////////////////////////// michael@0: ////////// BEGIN GRAPH BUILDING INSTRUCTIONS ////////// michael@0: /////////////////////////////////////////////////////// michael@0: michael@0: // Creates a new basic block for a MIR generator. If |pred| is not nullptr, michael@0: // its slots and stack depth are initialized from |pred|. michael@0: static MBasicBlock *New(MIRGraph &graph, BytecodeAnalysis *analysis, CompileInfo &info, michael@0: MBasicBlock *pred, jsbytecode *entryPc, Kind kind); michael@0: static MBasicBlock *NewPopN(MIRGraph &graph, CompileInfo &info, michael@0: MBasicBlock *pred, jsbytecode *entryPc, Kind kind, uint32_t popn); michael@0: static MBasicBlock *NewWithResumePoint(MIRGraph &graph, CompileInfo &info, michael@0: MBasicBlock *pred, jsbytecode *entryPc, michael@0: MResumePoint *resumePoint); michael@0: static MBasicBlock *NewPendingLoopHeader(MIRGraph &graph, CompileInfo &info, michael@0: MBasicBlock *pred, jsbytecode *entryPc, michael@0: unsigned loopStateSlots); michael@0: static MBasicBlock *NewSplitEdge(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred); michael@0: static MBasicBlock *NewAbortPar(MIRGraph &graph, CompileInfo &info, michael@0: MBasicBlock *pred, jsbytecode *entryPc, michael@0: MResumePoint *resumePoint); michael@0: static MBasicBlock *NewAsmJS(MIRGraph &graph, CompileInfo &info, michael@0: MBasicBlock *pred, Kind kind); michael@0: michael@0: bool dominates(const MBasicBlock *other) const; michael@0: michael@0: void setId(uint32_t id) { michael@0: id_ = id; michael@0: } michael@0: michael@0: // Mark the current block and all dominated blocks as unreachable. michael@0: void setUnreachable(); michael@0: bool unreachable() const { michael@0: return unreachable_; michael@0: } michael@0: // Move the definition to the top of the stack. michael@0: void pick(int32_t depth); michael@0: michael@0: // Exchange 2 stack slots at the defined depth michael@0: void swapAt(int32_t depth); michael@0: michael@0: // Gets the instruction associated with various slot types. michael@0: MDefinition *peek(int32_t depth); michael@0: michael@0: MDefinition *scopeChain(); michael@0: MDefinition *argumentsObject(); michael@0: michael@0: // Increase the number of slots available michael@0: bool increaseSlots(size_t num); michael@0: bool ensureHasSlots(size_t num); michael@0: michael@0: // Initializes a slot value; must not be called for normal stack michael@0: // operations, as it will not create new SSA names for copies. michael@0: void initSlot(uint32_t index, MDefinition *ins); michael@0: michael@0: // Discard the slot at the given depth, lowering all slots above. michael@0: void shimmySlots(int discardDepth); michael@0: michael@0: // In an OSR block, set all MOsrValues to use the MResumePoint attached to michael@0: // the MStart. michael@0: void linkOsrValues(MStart *start); michael@0: michael@0: // Sets the instruction associated with various slot types. The michael@0: // instruction must lie at the top of the stack. michael@0: void setLocal(uint32_t local); michael@0: void setArg(uint32_t arg); michael@0: void setSlot(uint32_t slot); michael@0: void setSlot(uint32_t slot, MDefinition *ins); michael@0: michael@0: // Rewrites a slot directly, bypassing the stack transition. This should michael@0: // not be used under most circumstances. michael@0: void rewriteSlot(uint32_t slot, MDefinition *ins); michael@0: michael@0: // Rewrites a slot based on its depth (same as argument to peek()). michael@0: void rewriteAtDepth(int32_t depth, MDefinition *ins); michael@0: michael@0: // Tracks an instruction as being pushed onto the operand stack. michael@0: void push(MDefinition *ins); michael@0: void pushArg(uint32_t arg); michael@0: void pushLocal(uint32_t local); michael@0: void pushSlot(uint32_t slot); michael@0: void setScopeChain(MDefinition *ins); michael@0: void setArgumentsObject(MDefinition *ins); michael@0: michael@0: // Returns the top of the stack, then decrements the virtual stack pointer. michael@0: MDefinition *pop(); michael@0: void popn(uint32_t n); michael@0: michael@0: // Adds an instruction to this block's instruction list. |ins| may be michael@0: // nullptr to simplify OOM checking. michael@0: void add(MInstruction *ins); michael@0: michael@0: // Marks the last instruction of the block; no further instructions michael@0: // can be added. michael@0: void end(MControlInstruction *ins); michael@0: michael@0: // Adds a phi instruction, but does not set successorWithPhis. michael@0: void addPhi(MPhi *phi); michael@0: michael@0: // Adds a resume point to this block. michael@0: void addResumePoint(MResumePoint *resume) { michael@0: resumePoints_.pushFront(resume); michael@0: } michael@0: michael@0: // Adds a predecessor. Every predecessor must have the same exit stack michael@0: // depth as the entry state to this block. Adding a predecessor michael@0: // automatically creates phi nodes and rewrites uses as needed. michael@0: bool addPredecessor(TempAllocator &alloc, MBasicBlock *pred); michael@0: bool addPredecessorPopN(TempAllocator &alloc, MBasicBlock *pred, uint32_t popped); michael@0: michael@0: // Stranger utilities used for inlining. michael@0: bool addPredecessorWithoutPhis(MBasicBlock *pred); michael@0: void inheritSlots(MBasicBlock *parent); michael@0: bool initEntrySlots(TempAllocator &alloc); michael@0: michael@0: // Replaces an edge for a given block with a new block. This is michael@0: // used for critical edge splitting and also for inserting michael@0: // bailouts during ParallelSafetyAnalysis. michael@0: // michael@0: // Note: If successorWithPhis is set, you must not be replacing it. michael@0: void replacePredecessor(MBasicBlock *old, MBasicBlock *split); michael@0: void replaceSuccessor(size_t pos, MBasicBlock *split); michael@0: michael@0: // Removes `pred` from the predecessor list. `pred` should not be michael@0: // the final predecessor. If this block defines phis, removes the michael@0: // entry for `pred` and updates the indices of later entries. michael@0: // This may introduce redundant phis if the new block has fewer michael@0: // than two predecessors. michael@0: void removePredecessor(MBasicBlock *pred); michael@0: michael@0: // Resets all the dominator info so that it can be recomputed. michael@0: void clearDominatorInfo(); michael@0: michael@0: // Sets a back edge. This places phi nodes and rewrites instructions within michael@0: // the current loop as necessary. If the backedge introduces new types for michael@0: // phis at the loop header, returns a disabling abort. michael@0: AbortReason setBackedge(MBasicBlock *block); michael@0: bool setBackedgeAsmJS(MBasicBlock *block); michael@0: michael@0: // Resets a LOOP_HEADER block to a NORMAL block. This is needed when michael@0: // optimizations remove the backedge. michael@0: void clearLoopHeader(); michael@0: michael@0: // Propagates phis placed in a loop header down to this successor block. michael@0: void inheritPhis(MBasicBlock *header); michael@0: michael@0: // Compute the types for phis in this block according to their inputs. michael@0: bool specializePhis(); michael@0: michael@0: void insertBefore(MInstruction *at, MInstruction *ins); michael@0: void insertAfter(MInstruction *at, MInstruction *ins); michael@0: michael@0: // Add an instruction to this block, from elsewhere in the graph. michael@0: void addFromElsewhere(MInstruction *ins); michael@0: michael@0: // Move an instruction. Movement may cross block boundaries. michael@0: void moveBefore(MInstruction *at, MInstruction *ins); michael@0: michael@0: // Removes an instruction with the intention to discard it. michael@0: void discard(MInstruction *ins); michael@0: void discardLastIns(); michael@0: MInstructionIterator discardAt(MInstructionIterator &iter); michael@0: MInstructionReverseIterator discardAt(MInstructionReverseIterator &iter); michael@0: MDefinitionIterator discardDefAt(MDefinitionIterator &iter); michael@0: void discardAllInstructions(); michael@0: void discardAllPhiOperands(); michael@0: void discardAllPhis(); michael@0: void discardAllResumePoints(bool discardEntry = true); michael@0: michael@0: // Discards a phi instruction and updates predecessor successorWithPhis. michael@0: MPhiIterator discardPhiAt(MPhiIterator &at); michael@0: michael@0: // Mark this block as having been removed from the graph. michael@0: void markAsDead() { michael@0: kind_ = DEAD; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////// michael@0: /////////// END GRAPH BUILDING INSTRUCTIONS /////////// michael@0: /////////////////////////////////////////////////////// michael@0: michael@0: MIRGraph &graph() { michael@0: return graph_; michael@0: } michael@0: CompileInfo &info() const { michael@0: return info_; michael@0: } michael@0: jsbytecode *pc() const { michael@0: return pc_; michael@0: } michael@0: uint32_t nslots() const { michael@0: return slots_.length(); michael@0: } michael@0: uint32_t id() const { michael@0: return id_; michael@0: } michael@0: uint32_t numPredecessors() const { michael@0: return predecessors_.length(); michael@0: } michael@0: michael@0: uint32_t domIndex() const { michael@0: JS_ASSERT(!isDead()); michael@0: return domIndex_; michael@0: } michael@0: void setDomIndex(uint32_t d) { michael@0: domIndex_ = d; michael@0: } michael@0: michael@0: MBasicBlock *getPredecessor(uint32_t i) const { michael@0: return predecessors_[i]; michael@0: } michael@0: MControlInstruction *lastIns() const { michael@0: return lastIns_; michael@0: } michael@0: MPhiIterator phisBegin() const { michael@0: return phis_.begin(); michael@0: } michael@0: MPhiIterator phisEnd() const { michael@0: return phis_.end(); michael@0: } michael@0: bool phisEmpty() const { michael@0: return phis_.empty(); michael@0: } michael@0: MResumePointIterator resumePointsBegin() const { michael@0: return resumePoints_.begin(); michael@0: } michael@0: MResumePointIterator resumePointsEnd() const { michael@0: return resumePoints_.end(); michael@0: } michael@0: bool resumePointsEmpty() const { michael@0: return resumePoints_.empty(); michael@0: } michael@0: MInstructionIterator begin() { michael@0: return instructions_.begin(); michael@0: } michael@0: MInstructionIterator begin(MInstruction *at) { michael@0: JS_ASSERT(at->block() == this); michael@0: return instructions_.begin(at); michael@0: } michael@0: MInstructionIterator end() { michael@0: return instructions_.end(); michael@0: } michael@0: MInstructionReverseIterator rbegin() { michael@0: return instructions_.rbegin(); michael@0: } michael@0: MInstructionReverseIterator rbegin(MInstruction *at) { michael@0: JS_ASSERT(at->block() == this); michael@0: return instructions_.rbegin(at); michael@0: } michael@0: MInstructionReverseIterator rend() { michael@0: return instructions_.rend(); michael@0: } michael@0: bool isLoopHeader() const { michael@0: return kind_ == LOOP_HEADER; michael@0: } michael@0: bool hasUniqueBackedge() const { michael@0: JS_ASSERT(isLoopHeader()); michael@0: JS_ASSERT(numPredecessors() >= 2); michael@0: return numPredecessors() == 2; michael@0: } michael@0: MBasicBlock *backedge() const { michael@0: JS_ASSERT(hasUniqueBackedge()); michael@0: return getPredecessor(numPredecessors() - 1); michael@0: } michael@0: MBasicBlock *loopHeaderOfBackedge() const { michael@0: JS_ASSERT(isLoopBackedge()); michael@0: return getSuccessor(numSuccessors() - 1); michael@0: } michael@0: MBasicBlock *loopPredecessor() const { michael@0: JS_ASSERT(isLoopHeader()); michael@0: return getPredecessor(0); michael@0: } michael@0: bool isLoopBackedge() const { michael@0: if (!numSuccessors()) michael@0: return false; michael@0: MBasicBlock *lastSuccessor = getSuccessor(numSuccessors() - 1); michael@0: return lastSuccessor->isLoopHeader() && michael@0: lastSuccessor->hasUniqueBackedge() && michael@0: lastSuccessor->backedge() == this; michael@0: } michael@0: bool isSplitEdge() const { michael@0: return kind_ == SPLIT_EDGE; michael@0: } michael@0: bool isDead() const { michael@0: return kind_ == DEAD; michael@0: } michael@0: michael@0: uint32_t stackDepth() const { michael@0: return stackPosition_; michael@0: } michael@0: void setStackDepth(uint32_t depth) { michael@0: stackPosition_ = depth; michael@0: } michael@0: bool isMarked() const { michael@0: return mark_; michael@0: } michael@0: void mark() { michael@0: mark_ = true; michael@0: } michael@0: void unmark() { michael@0: mark_ = false; michael@0: } michael@0: void makeStart(MStart *start) { michael@0: add(start); michael@0: start_ = start; michael@0: } michael@0: MStart *start() const { michael@0: return start_; michael@0: } michael@0: michael@0: MBasicBlock *immediateDominator() const { michael@0: return immediateDominator_; michael@0: } michael@0: michael@0: void setImmediateDominator(MBasicBlock *dom) { michael@0: immediateDominator_ = dom; michael@0: } michael@0: michael@0: MTest *immediateDominatorBranch(BranchDirection *pdirection); michael@0: michael@0: size_t numImmediatelyDominatedBlocks() const { michael@0: return immediatelyDominated_.length(); michael@0: } michael@0: michael@0: MBasicBlock *getImmediatelyDominatedBlock(size_t i) const { michael@0: return immediatelyDominated_[i]; michael@0: } michael@0: michael@0: MBasicBlock **immediatelyDominatedBlocksBegin() { michael@0: return immediatelyDominated_.begin(); michael@0: } michael@0: michael@0: MBasicBlock **immediatelyDominatedBlocksEnd() { michael@0: return immediatelyDominated_.end(); michael@0: } michael@0: michael@0: size_t numDominated() const { michael@0: return numDominated_; michael@0: } michael@0: michael@0: void addNumDominated(size_t n) { michael@0: numDominated_ += n; michael@0: } michael@0: michael@0: bool addImmediatelyDominatedBlock(MBasicBlock *child); michael@0: michael@0: // This function retrieves the internal instruction associated with a michael@0: // slot, and should not be used for normal stack operations. It is an michael@0: // internal helper that is also used to enhance spew. michael@0: MDefinition *getSlot(uint32_t index); michael@0: michael@0: MResumePoint *entryResumePoint() const { michael@0: return entryResumePoint_; michael@0: } michael@0: MResumePoint *callerResumePoint() { michael@0: return entryResumePoint()->caller(); michael@0: } michael@0: void setCallerResumePoint(MResumePoint *caller) { michael@0: entryResumePoint()->setCaller(caller); michael@0: } michael@0: size_t numEntrySlots() const { michael@0: return entryResumePoint()->numOperands(); michael@0: } michael@0: MDefinition *getEntrySlot(size_t i) const { michael@0: JS_ASSERT(i < numEntrySlots()); michael@0: return entryResumePoint()->getOperand(i); michael@0: } michael@0: michael@0: LBlock *lir() const { michael@0: return lir_; michael@0: } michael@0: void assignLir(LBlock *lir) { michael@0: JS_ASSERT(!lir_); michael@0: lir_ = lir; michael@0: } michael@0: michael@0: MBasicBlock *successorWithPhis() const { michael@0: return successorWithPhis_; michael@0: } michael@0: uint32_t positionInPhiSuccessor() const { michael@0: return positionInPhiSuccessor_; michael@0: } michael@0: void setSuccessorWithPhis(MBasicBlock *successor, uint32_t id) { michael@0: successorWithPhis_ = successor; michael@0: positionInPhiSuccessor_ = id; michael@0: } michael@0: size_t numSuccessors() const; michael@0: MBasicBlock *getSuccessor(size_t index) const; michael@0: size_t getSuccessorIndex(MBasicBlock *) const; michael@0: michael@0: void setLoopDepth(uint32_t loopDepth) { michael@0: loopDepth_ = loopDepth; michael@0: } michael@0: uint32_t loopDepth() const { michael@0: return loopDepth_; michael@0: } michael@0: michael@0: bool strict() const { michael@0: return info_.script()->strict(); michael@0: } michael@0: michael@0: void dumpStack(FILE *fp); michael@0: michael@0: void dump(FILE *fp); michael@0: void dump(); michael@0: michael@0: // Track bailouts by storing the current pc in MIR instruction added at this michael@0: // cycle. This is also used for tracking calls when profiling. michael@0: void updateTrackedPc(jsbytecode *pc) { michael@0: trackedPc_ = pc; michael@0: } michael@0: michael@0: jsbytecode *trackedPc() { michael@0: return trackedPc_; michael@0: } michael@0: michael@0: private: michael@0: MIRGraph &graph_; michael@0: CompileInfo &info_; // Each block originates from a particular script. michael@0: InlineList instructions_; michael@0: Vector predecessors_; michael@0: InlineForwardList phis_; michael@0: InlineForwardList resumePoints_; michael@0: FixedList slots_; michael@0: uint32_t stackPosition_; michael@0: MControlInstruction *lastIns_; michael@0: jsbytecode *pc_; michael@0: uint32_t id_; michael@0: uint32_t domIndex_; // Index in the dominator tree. michael@0: LBlock *lir_; michael@0: MStart *start_; michael@0: MResumePoint *entryResumePoint_; michael@0: MBasicBlock *successorWithPhis_; michael@0: uint32_t positionInPhiSuccessor_; michael@0: Kind kind_; michael@0: uint32_t loopDepth_; michael@0: michael@0: // Utility mark for traversal algorithms. michael@0: bool mark_; michael@0: michael@0: Vector immediatelyDominated_; michael@0: MBasicBlock *immediateDominator_; michael@0: size_t numDominated_; michael@0: michael@0: jsbytecode *trackedPc_; michael@0: michael@0: #if defined (JS_ION_PERF) michael@0: unsigned lineno_; michael@0: unsigned columnIndex_; michael@0: michael@0: public: michael@0: void setLineno(unsigned l) { lineno_ = l; } michael@0: unsigned lineno() const { return lineno_; } michael@0: void setColumnIndex(unsigned c) { columnIndex_ = c; } michael@0: unsigned columnIndex() const { return columnIndex_; } michael@0: #endif michael@0: }; michael@0: michael@0: typedef InlineListIterator MBasicBlockIterator; michael@0: typedef InlineListIterator ReversePostorderIterator; michael@0: typedef InlineListReverseIterator PostorderIterator; michael@0: michael@0: typedef Vector MIRGraphReturns; michael@0: michael@0: class MIRGraph michael@0: { michael@0: InlineList blocks_; michael@0: TempAllocator *alloc_; michael@0: MIRGraphReturns *returnAccumulator_; michael@0: uint32_t blockIdGen_; michael@0: uint32_t idGen_; michael@0: MBasicBlock *osrBlock_; michael@0: MStart *osrStart_; michael@0: michael@0: size_t numBlocks_; michael@0: bool hasTryBlock_; michael@0: michael@0: public: michael@0: MIRGraph(TempAllocator *alloc) michael@0: : alloc_(alloc), michael@0: returnAccumulator_(nullptr), michael@0: blockIdGen_(0), michael@0: idGen_(1), michael@0: osrBlock_(nullptr), michael@0: osrStart_(nullptr), michael@0: numBlocks_(0), michael@0: hasTryBlock_(false) michael@0: { } michael@0: michael@0: TempAllocator &alloc() const { michael@0: return *alloc_; michael@0: } michael@0: michael@0: void addBlock(MBasicBlock *block); michael@0: void insertBlockAfter(MBasicBlock *at, MBasicBlock *block); michael@0: michael@0: void unmarkBlocks(); michael@0: michael@0: void setReturnAccumulator(MIRGraphReturns *accum) { michael@0: returnAccumulator_ = accum; michael@0: } michael@0: MIRGraphReturns *returnAccumulator() const { michael@0: return returnAccumulator_; michael@0: } michael@0: michael@0: bool addReturn(MBasicBlock *returnBlock) { michael@0: if (!returnAccumulator_) michael@0: return true; michael@0: michael@0: return returnAccumulator_->append(returnBlock); michael@0: } michael@0: michael@0: MBasicBlock *entryBlock() { michael@0: return *blocks_.begin(); michael@0: } michael@0: michael@0: void clearBlockList() { michael@0: blocks_.clear(); michael@0: blockIdGen_ = 0; michael@0: numBlocks_ = 0; michael@0: } michael@0: void resetInstructionNumber() { michael@0: // This intentionally starts above 0. The id 0 is in places used to michael@0: // indicate a failure to perform an operation on an instruction. michael@0: idGen_ = 1; michael@0: } michael@0: MBasicBlockIterator begin() { michael@0: return blocks_.begin(); michael@0: } michael@0: MBasicBlockIterator begin(MBasicBlock *at) { michael@0: return blocks_.begin(at); michael@0: } michael@0: MBasicBlockIterator end() { michael@0: return blocks_.end(); michael@0: } michael@0: PostorderIterator poBegin() { michael@0: return blocks_.rbegin(); michael@0: } michael@0: PostorderIterator poEnd() { michael@0: return blocks_.rend(); michael@0: } michael@0: ReversePostorderIterator rpoBegin() { michael@0: return blocks_.begin(); michael@0: } michael@0: ReversePostorderIterator rpoBegin(MBasicBlock *at) { michael@0: return blocks_.begin(at); michael@0: } michael@0: ReversePostorderIterator rpoEnd() { michael@0: return blocks_.end(); michael@0: } michael@0: void removeBlocksAfter(MBasicBlock *block); michael@0: void removeBlock(MBasicBlock *block); michael@0: void moveBlockToEnd(MBasicBlock *block) { michael@0: JS_ASSERT(block->id()); michael@0: blocks_.remove(block); michael@0: blocks_.pushBack(block); michael@0: } michael@0: size_t numBlocks() const { michael@0: return numBlocks_; michael@0: } michael@0: uint32_t numBlockIds() const { michael@0: return blockIdGen_; michael@0: } michael@0: void allocDefinitionId(MDefinition *ins) { michael@0: ins->setId(idGen_++); michael@0: } michael@0: uint32_t getNumInstructionIds() { michael@0: return idGen_; michael@0: } michael@0: MResumePoint *entryResumePoint() { michael@0: return blocks_.begin()->entryResumePoint(); michael@0: } michael@0: michael@0: void copyIds(const MIRGraph &other) { michael@0: idGen_ = other.idGen_; michael@0: blockIdGen_ = other.blockIdGen_; michael@0: numBlocks_ = other.numBlocks_; michael@0: } michael@0: michael@0: void setOsrBlock(MBasicBlock *osrBlock) { michael@0: JS_ASSERT(!osrBlock_); michael@0: osrBlock_ = osrBlock; michael@0: } michael@0: MBasicBlock *osrBlock() { michael@0: return osrBlock_; michael@0: } michael@0: void setOsrStart(MStart *osrStart) { michael@0: osrStart_ = osrStart; michael@0: } michael@0: MStart *osrStart() { michael@0: return osrStart_; michael@0: } michael@0: michael@0: bool hasTryBlock() const { michael@0: return hasTryBlock_; michael@0: } michael@0: void setHasTryBlock() { michael@0: hasTryBlock_ = true; michael@0: } michael@0: michael@0: // The per-thread context. So as not to modify the calling convention for michael@0: // parallel code, we obtain the current ForkJoinContext from thread-local michael@0: // storage. This helper method will lazilly insert an MForkJoinContext michael@0: // instruction in the entry block and return the definition. michael@0: MDefinition *forkJoinContext(); michael@0: michael@0: void dump(FILE *fp); michael@0: void dump(); michael@0: }; michael@0: michael@0: class MDefinitionIterator michael@0: { michael@0: michael@0: friend class MBasicBlock; michael@0: michael@0: private: michael@0: MBasicBlock *block_; michael@0: MPhiIterator phiIter_; michael@0: MInstructionIterator iter_; michael@0: michael@0: bool atPhi() const { michael@0: return phiIter_ != block_->phisEnd(); michael@0: } michael@0: michael@0: MDefinition *getIns() { michael@0: if (atPhi()) michael@0: return *phiIter_; michael@0: return *iter_; michael@0: } michael@0: michael@0: void next() { michael@0: if (atPhi()) michael@0: phiIter_++; michael@0: else michael@0: iter_++; michael@0: } michael@0: michael@0: bool more() const { michael@0: return atPhi() || (*iter_) != block_->lastIns(); michael@0: } michael@0: michael@0: public: michael@0: MDefinitionIterator(MBasicBlock *block) michael@0: : block_(block), michael@0: phiIter_(block->phisBegin()), michael@0: iter_(block->begin()) michael@0: { } michael@0: michael@0: MDefinitionIterator operator ++(int) { michael@0: MDefinitionIterator old(*this); michael@0: if (more()) michael@0: next(); michael@0: return old; michael@0: } michael@0: michael@0: operator bool() const { michael@0: return more(); michael@0: } michael@0: michael@0: MDefinition *operator *() { michael@0: return getIns(); michael@0: } michael@0: michael@0: MDefinition *operator ->() { michael@0: return getIns(); michael@0: } michael@0: michael@0: }; michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif /* jit_MIRGraph_h */