Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef jit_MIRGraph_h
8 #define jit_MIRGraph_h
10 // This file declares the data structures used to build a control-flow graph
11 // containing MIR.
13 #include "jit/FixedList.h"
14 #include "jit/IonAllocPolicy.h"
15 #include "jit/MIR.h"
17 namespace js {
18 namespace jit {
20 class BytecodeAnalysis;
21 class MBasicBlock;
22 class MIRGraph;
23 class MStart;
25 class MDefinitionIterator;
27 typedef InlineListIterator<MInstruction> MInstructionIterator;
28 typedef InlineListReverseIterator<MInstruction> MInstructionReverseIterator;
29 typedef InlineForwardListIterator<MPhi> MPhiIterator;
30 typedef InlineForwardListIterator<MResumePoint> MResumePointIterator;
32 class LBlock;
34 class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
35 {
36 public:
37 enum Kind {
38 NORMAL,
39 PENDING_LOOP_HEADER,
40 LOOP_HEADER,
41 SPLIT_EDGE,
42 DEAD
43 };
45 private:
46 MBasicBlock(MIRGraph &graph, CompileInfo &info, jsbytecode *pc, Kind kind);
47 bool init();
48 void copySlots(MBasicBlock *from);
49 bool inherit(TempAllocator &alloc, BytecodeAnalysis *analysis, MBasicBlock *pred,
50 uint32_t popped, unsigned stackPhiCount = 0);
51 bool inheritResumePoint(MBasicBlock *pred);
52 void assertUsesAreNotWithin(MUseIterator use, MUseIterator end);
54 // This block cannot be reached by any means.
55 bool unreachable_;
57 // Pushes a copy of a local variable or argument.
58 void pushVariable(uint32_t slot);
60 // Sets a variable slot to the top of the stack, correctly creating copies
61 // as needed.
62 void setVariable(uint32_t slot);
64 public:
65 ///////////////////////////////////////////////////////
66 ////////// BEGIN GRAPH BUILDING INSTRUCTIONS //////////
67 ///////////////////////////////////////////////////////
69 // Creates a new basic block for a MIR generator. If |pred| is not nullptr,
70 // its slots and stack depth are initialized from |pred|.
71 static MBasicBlock *New(MIRGraph &graph, BytecodeAnalysis *analysis, CompileInfo &info,
72 MBasicBlock *pred, jsbytecode *entryPc, Kind kind);
73 static MBasicBlock *NewPopN(MIRGraph &graph, CompileInfo &info,
74 MBasicBlock *pred, jsbytecode *entryPc, Kind kind, uint32_t popn);
75 static MBasicBlock *NewWithResumePoint(MIRGraph &graph, CompileInfo &info,
76 MBasicBlock *pred, jsbytecode *entryPc,
77 MResumePoint *resumePoint);
78 static MBasicBlock *NewPendingLoopHeader(MIRGraph &graph, CompileInfo &info,
79 MBasicBlock *pred, jsbytecode *entryPc,
80 unsigned loopStateSlots);
81 static MBasicBlock *NewSplitEdge(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred);
82 static MBasicBlock *NewAbortPar(MIRGraph &graph, CompileInfo &info,
83 MBasicBlock *pred, jsbytecode *entryPc,
84 MResumePoint *resumePoint);
85 static MBasicBlock *NewAsmJS(MIRGraph &graph, CompileInfo &info,
86 MBasicBlock *pred, Kind kind);
88 bool dominates(const MBasicBlock *other) const;
90 void setId(uint32_t id) {
91 id_ = id;
92 }
94 // Mark the current block and all dominated blocks as unreachable.
95 void setUnreachable();
96 bool unreachable() const {
97 return unreachable_;
98 }
99 // Move the definition to the top of the stack.
100 void pick(int32_t depth);
102 // Exchange 2 stack slots at the defined depth
103 void swapAt(int32_t depth);
105 // Gets the instruction associated with various slot types.
106 MDefinition *peek(int32_t depth);
108 MDefinition *scopeChain();
109 MDefinition *argumentsObject();
111 // Increase the number of slots available
112 bool increaseSlots(size_t num);
113 bool ensureHasSlots(size_t num);
115 // Initializes a slot value; must not be called for normal stack
116 // operations, as it will not create new SSA names for copies.
117 void initSlot(uint32_t index, MDefinition *ins);
119 // Discard the slot at the given depth, lowering all slots above.
120 void shimmySlots(int discardDepth);
122 // In an OSR block, set all MOsrValues to use the MResumePoint attached to
123 // the MStart.
124 void linkOsrValues(MStart *start);
126 // Sets the instruction associated with various slot types. The
127 // instruction must lie at the top of the stack.
128 void setLocal(uint32_t local);
129 void setArg(uint32_t arg);
130 void setSlot(uint32_t slot);
131 void setSlot(uint32_t slot, MDefinition *ins);
133 // Rewrites a slot directly, bypassing the stack transition. This should
134 // not be used under most circumstances.
135 void rewriteSlot(uint32_t slot, MDefinition *ins);
137 // Rewrites a slot based on its depth (same as argument to peek()).
138 void rewriteAtDepth(int32_t depth, MDefinition *ins);
140 // Tracks an instruction as being pushed onto the operand stack.
141 void push(MDefinition *ins);
142 void pushArg(uint32_t arg);
143 void pushLocal(uint32_t local);
144 void pushSlot(uint32_t slot);
145 void setScopeChain(MDefinition *ins);
146 void setArgumentsObject(MDefinition *ins);
148 // Returns the top of the stack, then decrements the virtual stack pointer.
149 MDefinition *pop();
150 void popn(uint32_t n);
152 // Adds an instruction to this block's instruction list. |ins| may be
153 // nullptr to simplify OOM checking.
154 void add(MInstruction *ins);
156 // Marks the last instruction of the block; no further instructions
157 // can be added.
158 void end(MControlInstruction *ins);
160 // Adds a phi instruction, but does not set successorWithPhis.
161 void addPhi(MPhi *phi);
163 // Adds a resume point to this block.
164 void addResumePoint(MResumePoint *resume) {
165 resumePoints_.pushFront(resume);
166 }
168 // Adds a predecessor. Every predecessor must have the same exit stack
169 // depth as the entry state to this block. Adding a predecessor
170 // automatically creates phi nodes and rewrites uses as needed.
171 bool addPredecessor(TempAllocator &alloc, MBasicBlock *pred);
172 bool addPredecessorPopN(TempAllocator &alloc, MBasicBlock *pred, uint32_t popped);
174 // Stranger utilities used for inlining.
175 bool addPredecessorWithoutPhis(MBasicBlock *pred);
176 void inheritSlots(MBasicBlock *parent);
177 bool initEntrySlots(TempAllocator &alloc);
179 // Replaces an edge for a given block with a new block. This is
180 // used for critical edge splitting and also for inserting
181 // bailouts during ParallelSafetyAnalysis.
182 //
183 // Note: If successorWithPhis is set, you must not be replacing it.
184 void replacePredecessor(MBasicBlock *old, MBasicBlock *split);
185 void replaceSuccessor(size_t pos, MBasicBlock *split);
187 // Removes `pred` from the predecessor list. `pred` should not be
188 // the final predecessor. If this block defines phis, removes the
189 // entry for `pred` and updates the indices of later entries.
190 // This may introduce redundant phis if the new block has fewer
191 // than two predecessors.
192 void removePredecessor(MBasicBlock *pred);
194 // Resets all the dominator info so that it can be recomputed.
195 void clearDominatorInfo();
197 // Sets a back edge. This places phi nodes and rewrites instructions within
198 // the current loop as necessary. If the backedge introduces new types for
199 // phis at the loop header, returns a disabling abort.
200 AbortReason setBackedge(MBasicBlock *block);
201 bool setBackedgeAsmJS(MBasicBlock *block);
203 // Resets a LOOP_HEADER block to a NORMAL block. This is needed when
204 // optimizations remove the backedge.
205 void clearLoopHeader();
207 // Propagates phis placed in a loop header down to this successor block.
208 void inheritPhis(MBasicBlock *header);
210 // Compute the types for phis in this block according to their inputs.
211 bool specializePhis();
213 void insertBefore(MInstruction *at, MInstruction *ins);
214 void insertAfter(MInstruction *at, MInstruction *ins);
216 // Add an instruction to this block, from elsewhere in the graph.
217 void addFromElsewhere(MInstruction *ins);
219 // Move an instruction. Movement may cross block boundaries.
220 void moveBefore(MInstruction *at, MInstruction *ins);
222 // Removes an instruction with the intention to discard it.
223 void discard(MInstruction *ins);
224 void discardLastIns();
225 MInstructionIterator discardAt(MInstructionIterator &iter);
226 MInstructionReverseIterator discardAt(MInstructionReverseIterator &iter);
227 MDefinitionIterator discardDefAt(MDefinitionIterator &iter);
228 void discardAllInstructions();
229 void discardAllPhiOperands();
230 void discardAllPhis();
231 void discardAllResumePoints(bool discardEntry = true);
233 // Discards a phi instruction and updates predecessor successorWithPhis.
234 MPhiIterator discardPhiAt(MPhiIterator &at);
236 // Mark this block as having been removed from the graph.
237 void markAsDead() {
238 kind_ = DEAD;
239 }
241 ///////////////////////////////////////////////////////
242 /////////// END GRAPH BUILDING INSTRUCTIONS ///////////
243 ///////////////////////////////////////////////////////
245 MIRGraph &graph() {
246 return graph_;
247 }
248 CompileInfo &info() const {
249 return info_;
250 }
251 jsbytecode *pc() const {
252 return pc_;
253 }
254 uint32_t nslots() const {
255 return slots_.length();
256 }
257 uint32_t id() const {
258 return id_;
259 }
260 uint32_t numPredecessors() const {
261 return predecessors_.length();
262 }
264 uint32_t domIndex() const {
265 JS_ASSERT(!isDead());
266 return domIndex_;
267 }
268 void setDomIndex(uint32_t d) {
269 domIndex_ = d;
270 }
272 MBasicBlock *getPredecessor(uint32_t i) const {
273 return predecessors_[i];
274 }
275 MControlInstruction *lastIns() const {
276 return lastIns_;
277 }
278 MPhiIterator phisBegin() const {
279 return phis_.begin();
280 }
281 MPhiIterator phisEnd() const {
282 return phis_.end();
283 }
284 bool phisEmpty() const {
285 return phis_.empty();
286 }
287 MResumePointIterator resumePointsBegin() const {
288 return resumePoints_.begin();
289 }
290 MResumePointIterator resumePointsEnd() const {
291 return resumePoints_.end();
292 }
293 bool resumePointsEmpty() const {
294 return resumePoints_.empty();
295 }
296 MInstructionIterator begin() {
297 return instructions_.begin();
298 }
299 MInstructionIterator begin(MInstruction *at) {
300 JS_ASSERT(at->block() == this);
301 return instructions_.begin(at);
302 }
303 MInstructionIterator end() {
304 return instructions_.end();
305 }
306 MInstructionReverseIterator rbegin() {
307 return instructions_.rbegin();
308 }
309 MInstructionReverseIterator rbegin(MInstruction *at) {
310 JS_ASSERT(at->block() == this);
311 return instructions_.rbegin(at);
312 }
313 MInstructionReverseIterator rend() {
314 return instructions_.rend();
315 }
316 bool isLoopHeader() const {
317 return kind_ == LOOP_HEADER;
318 }
319 bool hasUniqueBackedge() const {
320 JS_ASSERT(isLoopHeader());
321 JS_ASSERT(numPredecessors() >= 2);
322 return numPredecessors() == 2;
323 }
324 MBasicBlock *backedge() const {
325 JS_ASSERT(hasUniqueBackedge());
326 return getPredecessor(numPredecessors() - 1);
327 }
328 MBasicBlock *loopHeaderOfBackedge() const {
329 JS_ASSERT(isLoopBackedge());
330 return getSuccessor(numSuccessors() - 1);
331 }
332 MBasicBlock *loopPredecessor() const {
333 JS_ASSERT(isLoopHeader());
334 return getPredecessor(0);
335 }
336 bool isLoopBackedge() const {
337 if (!numSuccessors())
338 return false;
339 MBasicBlock *lastSuccessor = getSuccessor(numSuccessors() - 1);
340 return lastSuccessor->isLoopHeader() &&
341 lastSuccessor->hasUniqueBackedge() &&
342 lastSuccessor->backedge() == this;
343 }
344 bool isSplitEdge() const {
345 return kind_ == SPLIT_EDGE;
346 }
347 bool isDead() const {
348 return kind_ == DEAD;
349 }
351 uint32_t stackDepth() const {
352 return stackPosition_;
353 }
354 void setStackDepth(uint32_t depth) {
355 stackPosition_ = depth;
356 }
357 bool isMarked() const {
358 return mark_;
359 }
360 void mark() {
361 mark_ = true;
362 }
363 void unmark() {
364 mark_ = false;
365 }
366 void makeStart(MStart *start) {
367 add(start);
368 start_ = start;
369 }
370 MStart *start() const {
371 return start_;
372 }
374 MBasicBlock *immediateDominator() const {
375 return immediateDominator_;
376 }
378 void setImmediateDominator(MBasicBlock *dom) {
379 immediateDominator_ = dom;
380 }
382 MTest *immediateDominatorBranch(BranchDirection *pdirection);
384 size_t numImmediatelyDominatedBlocks() const {
385 return immediatelyDominated_.length();
386 }
388 MBasicBlock *getImmediatelyDominatedBlock(size_t i) const {
389 return immediatelyDominated_[i];
390 }
392 MBasicBlock **immediatelyDominatedBlocksBegin() {
393 return immediatelyDominated_.begin();
394 }
396 MBasicBlock **immediatelyDominatedBlocksEnd() {
397 return immediatelyDominated_.end();
398 }
400 size_t numDominated() const {
401 return numDominated_;
402 }
404 void addNumDominated(size_t n) {
405 numDominated_ += n;
406 }
408 bool addImmediatelyDominatedBlock(MBasicBlock *child);
410 // This function retrieves the internal instruction associated with a
411 // slot, and should not be used for normal stack operations. It is an
412 // internal helper that is also used to enhance spew.
413 MDefinition *getSlot(uint32_t index);
415 MResumePoint *entryResumePoint() const {
416 return entryResumePoint_;
417 }
418 MResumePoint *callerResumePoint() {
419 return entryResumePoint()->caller();
420 }
421 void setCallerResumePoint(MResumePoint *caller) {
422 entryResumePoint()->setCaller(caller);
423 }
424 size_t numEntrySlots() const {
425 return entryResumePoint()->numOperands();
426 }
427 MDefinition *getEntrySlot(size_t i) const {
428 JS_ASSERT(i < numEntrySlots());
429 return entryResumePoint()->getOperand(i);
430 }
432 LBlock *lir() const {
433 return lir_;
434 }
435 void assignLir(LBlock *lir) {
436 JS_ASSERT(!lir_);
437 lir_ = lir;
438 }
440 MBasicBlock *successorWithPhis() const {
441 return successorWithPhis_;
442 }
443 uint32_t positionInPhiSuccessor() const {
444 return positionInPhiSuccessor_;
445 }
446 void setSuccessorWithPhis(MBasicBlock *successor, uint32_t id) {
447 successorWithPhis_ = successor;
448 positionInPhiSuccessor_ = id;
449 }
450 size_t numSuccessors() const;
451 MBasicBlock *getSuccessor(size_t index) const;
452 size_t getSuccessorIndex(MBasicBlock *) const;
454 void setLoopDepth(uint32_t loopDepth) {
455 loopDepth_ = loopDepth;
456 }
457 uint32_t loopDepth() const {
458 return loopDepth_;
459 }
461 bool strict() const {
462 return info_.script()->strict();
463 }
465 void dumpStack(FILE *fp);
467 void dump(FILE *fp);
468 void dump();
470 // Track bailouts by storing the current pc in MIR instruction added at this
471 // cycle. This is also used for tracking calls when profiling.
472 void updateTrackedPc(jsbytecode *pc) {
473 trackedPc_ = pc;
474 }
476 jsbytecode *trackedPc() {
477 return trackedPc_;
478 }
480 private:
481 MIRGraph &graph_;
482 CompileInfo &info_; // Each block originates from a particular script.
483 InlineList<MInstruction> instructions_;
484 Vector<MBasicBlock *, 1, IonAllocPolicy> predecessors_;
485 InlineForwardList<MPhi> phis_;
486 InlineForwardList<MResumePoint> resumePoints_;
487 FixedList<MDefinition *> slots_;
488 uint32_t stackPosition_;
489 MControlInstruction *lastIns_;
490 jsbytecode *pc_;
491 uint32_t id_;
492 uint32_t domIndex_; // Index in the dominator tree.
493 LBlock *lir_;
494 MStart *start_;
495 MResumePoint *entryResumePoint_;
496 MBasicBlock *successorWithPhis_;
497 uint32_t positionInPhiSuccessor_;
498 Kind kind_;
499 uint32_t loopDepth_;
501 // Utility mark for traversal algorithms.
502 bool mark_;
504 Vector<MBasicBlock *, 1, IonAllocPolicy> immediatelyDominated_;
505 MBasicBlock *immediateDominator_;
506 size_t numDominated_;
508 jsbytecode *trackedPc_;
510 #if defined (JS_ION_PERF)
511 unsigned lineno_;
512 unsigned columnIndex_;
514 public:
515 void setLineno(unsigned l) { lineno_ = l; }
516 unsigned lineno() const { return lineno_; }
517 void setColumnIndex(unsigned c) { columnIndex_ = c; }
518 unsigned columnIndex() const { return columnIndex_; }
519 #endif
520 };
522 typedef InlineListIterator<MBasicBlock> MBasicBlockIterator;
523 typedef InlineListIterator<MBasicBlock> ReversePostorderIterator;
524 typedef InlineListReverseIterator<MBasicBlock> PostorderIterator;
526 typedef Vector<MBasicBlock *, 1, IonAllocPolicy> MIRGraphReturns;
528 class MIRGraph
529 {
530 InlineList<MBasicBlock> blocks_;
531 TempAllocator *alloc_;
532 MIRGraphReturns *returnAccumulator_;
533 uint32_t blockIdGen_;
534 uint32_t idGen_;
535 MBasicBlock *osrBlock_;
536 MStart *osrStart_;
538 size_t numBlocks_;
539 bool hasTryBlock_;
541 public:
542 MIRGraph(TempAllocator *alloc)
543 : alloc_(alloc),
544 returnAccumulator_(nullptr),
545 blockIdGen_(0),
546 idGen_(1),
547 osrBlock_(nullptr),
548 osrStart_(nullptr),
549 numBlocks_(0),
550 hasTryBlock_(false)
551 { }
553 TempAllocator &alloc() const {
554 return *alloc_;
555 }
557 void addBlock(MBasicBlock *block);
558 void insertBlockAfter(MBasicBlock *at, MBasicBlock *block);
560 void unmarkBlocks();
562 void setReturnAccumulator(MIRGraphReturns *accum) {
563 returnAccumulator_ = accum;
564 }
565 MIRGraphReturns *returnAccumulator() const {
566 return returnAccumulator_;
567 }
569 bool addReturn(MBasicBlock *returnBlock) {
570 if (!returnAccumulator_)
571 return true;
573 return returnAccumulator_->append(returnBlock);
574 }
576 MBasicBlock *entryBlock() {
577 return *blocks_.begin();
578 }
580 void clearBlockList() {
581 blocks_.clear();
582 blockIdGen_ = 0;
583 numBlocks_ = 0;
584 }
585 void resetInstructionNumber() {
586 // This intentionally starts above 0. The id 0 is in places used to
587 // indicate a failure to perform an operation on an instruction.
588 idGen_ = 1;
589 }
590 MBasicBlockIterator begin() {
591 return blocks_.begin();
592 }
593 MBasicBlockIterator begin(MBasicBlock *at) {
594 return blocks_.begin(at);
595 }
596 MBasicBlockIterator end() {
597 return blocks_.end();
598 }
599 PostorderIterator poBegin() {
600 return blocks_.rbegin();
601 }
602 PostorderIterator poEnd() {
603 return blocks_.rend();
604 }
605 ReversePostorderIterator rpoBegin() {
606 return blocks_.begin();
607 }
608 ReversePostorderIterator rpoBegin(MBasicBlock *at) {
609 return blocks_.begin(at);
610 }
611 ReversePostorderIterator rpoEnd() {
612 return blocks_.end();
613 }
614 void removeBlocksAfter(MBasicBlock *block);
615 void removeBlock(MBasicBlock *block);
616 void moveBlockToEnd(MBasicBlock *block) {
617 JS_ASSERT(block->id());
618 blocks_.remove(block);
619 blocks_.pushBack(block);
620 }
621 size_t numBlocks() const {
622 return numBlocks_;
623 }
624 uint32_t numBlockIds() const {
625 return blockIdGen_;
626 }
627 void allocDefinitionId(MDefinition *ins) {
628 ins->setId(idGen_++);
629 }
630 uint32_t getNumInstructionIds() {
631 return idGen_;
632 }
633 MResumePoint *entryResumePoint() {
634 return blocks_.begin()->entryResumePoint();
635 }
637 void copyIds(const MIRGraph &other) {
638 idGen_ = other.idGen_;
639 blockIdGen_ = other.blockIdGen_;
640 numBlocks_ = other.numBlocks_;
641 }
643 void setOsrBlock(MBasicBlock *osrBlock) {
644 JS_ASSERT(!osrBlock_);
645 osrBlock_ = osrBlock;
646 }
647 MBasicBlock *osrBlock() {
648 return osrBlock_;
649 }
650 void setOsrStart(MStart *osrStart) {
651 osrStart_ = osrStart;
652 }
653 MStart *osrStart() {
654 return osrStart_;
655 }
657 bool hasTryBlock() const {
658 return hasTryBlock_;
659 }
660 void setHasTryBlock() {
661 hasTryBlock_ = true;
662 }
664 // The per-thread context. So as not to modify the calling convention for
665 // parallel code, we obtain the current ForkJoinContext from thread-local
666 // storage. This helper method will lazilly insert an MForkJoinContext
667 // instruction in the entry block and return the definition.
668 MDefinition *forkJoinContext();
670 void dump(FILE *fp);
671 void dump();
672 };
674 class MDefinitionIterator
675 {
677 friend class MBasicBlock;
679 private:
680 MBasicBlock *block_;
681 MPhiIterator phiIter_;
682 MInstructionIterator iter_;
684 bool atPhi() const {
685 return phiIter_ != block_->phisEnd();
686 }
688 MDefinition *getIns() {
689 if (atPhi())
690 return *phiIter_;
691 return *iter_;
692 }
694 void next() {
695 if (atPhi())
696 phiIter_++;
697 else
698 iter_++;
699 }
701 bool more() const {
702 return atPhi() || (*iter_) != block_->lastIns();
703 }
705 public:
706 MDefinitionIterator(MBasicBlock *block)
707 : block_(block),
708 phiIter_(block->phisBegin()),
709 iter_(block->begin())
710 { }
712 MDefinitionIterator operator ++(int) {
713 MDefinitionIterator old(*this);
714 if (more())
715 next();
716 return old;
717 }
719 operator bool() const {
720 return more();
721 }
723 MDefinition *operator *() {
724 return getIns();
725 }
727 MDefinition *operator ->() {
728 return getIns();
729 }
731 };
733 } // namespace jit
734 } // namespace js
736 #endif /* jit_MIRGraph_h */