Line data Source code
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/. */
6 :
7 : #include "jit/MIRGraph.h"
8 :
9 : #include "jit/BytecodeAnalysis.h"
10 : #include "jit/Ion.h"
11 : #include "jit/JitSpewer.h"
12 : #include "jit/MIR.h"
13 : #include "jit/MIRGenerator.h"
14 : #include "wasm/WasmTypes.h"
15 :
16 : using namespace js;
17 : using namespace js::jit;
18 : using mozilla::Swap;
19 :
20 179 : MIRGenerator::MIRGenerator(CompileCompartment* compartment, const JitCompileOptions& options,
21 : TempAllocator* alloc, MIRGraph* graph, const CompileInfo* info,
22 179 : const OptimizationInfo* optimizationInfo)
23 : : compartment(compartment),
24 : info_(info),
25 : optimizationInfo_(optimizationInfo),
26 : alloc_(alloc),
27 : graph_(graph),
28 179 : offThreadStatus_(Ok()),
29 179 : abortedPreliminaryGroups_(*alloc_),
30 : pauseBuild_(nullptr),
31 : cancelBuild_(false),
32 : wasmMaxStackArgBytes_(0),
33 : needsOverrecursedCheck_(false),
34 : needsStaticStackAlignment_(false),
35 : usesSimd_(false),
36 : cachedUsesSimd_(false),
37 : modifiesFrameArguments_(false),
38 : instrumentedProfiling_(false),
39 : instrumentedProfilingIsCached_(false),
40 : safeForMinorGC_(true),
41 : minWasmHeapLength_(0),
42 : options(options),
43 358 : gs_(alloc)
44 179 : { }
45 :
46 : bool
47 0 : MIRGenerator::usesSimd()
48 : {
49 0 : if (cachedUsesSimd_)
50 0 : return usesSimd_;
51 :
52 0 : cachedUsesSimd_ = true;
53 0 : for (ReversePostorderIterator block = graph_->rpoBegin(),
54 0 : end = graph_->rpoEnd();
55 : block != end;
56 : block++)
57 : {
58 : // It's fine to use MInstructionIterator here because we don't have to
59 : // worry about Phis, since any reachable phi (or phi cycle) will have at
60 : // least one instruction as an input.
61 0 : for (MInstructionIterator inst = block->begin(); inst != block->end(); inst++) {
62 : // Instructions that have SIMD inputs but not a SIMD type are fine
63 : // to ignore, as their inputs are also reached at some point. By
64 : // induction, at least one instruction with a SIMD type is reached
65 : // at some point.
66 0 : if (IsSimdType(inst->type())) {
67 : MOZ_ASSERT(SupportsSimd);
68 0 : usesSimd_ = true;
69 0 : return true;
70 : }
71 : }
72 : }
73 0 : usesSimd_ = false;
74 0 : return false;
75 : }
76 :
77 : mozilla::GenericErrorResult<AbortReason>
78 2 : MIRGenerator::abort(AbortReason r)
79 : {
80 2 : if (JitSpewEnabled(JitSpew_IonAbort)) {
81 0 : switch (r) {
82 : case AbortReason::Alloc:
83 0 : JitSpew(JitSpew_IonAbort, "AbortReason::Alloc");
84 0 : break;
85 : case AbortReason::Inlining:
86 0 : JitSpew(JitSpew_IonAbort, "AbortReason::Inlining");
87 0 : break;
88 : case AbortReason::PreliminaryObjects:
89 0 : JitSpew(JitSpew_IonAbort, "AbortReason::PreliminaryObjects");
90 0 : break;
91 : case AbortReason::Disable:
92 0 : JitSpew(JitSpew_IonAbort, "AbortReason::Disable");
93 0 : break;
94 : case AbortReason::Error:
95 0 : JitSpew(JitSpew_IonAbort, "AbortReason::Error");
96 0 : break;
97 : case AbortReason::NoAbort:
98 0 : MOZ_CRASH("Abort with AbortReason::NoAbort");
99 : break;
100 : }
101 : }
102 2 : return Err(mozilla::Move(r));
103 : }
104 :
105 : mozilla::GenericErrorResult<AbortReason>
106 3 : MIRGenerator::abortFmt(AbortReason r, const char* message, va_list ap)
107 : {
108 3 : JitSpewVA(JitSpew_IonAbort, message, ap);
109 3 : return Err(mozilla::Move(r));
110 : }
111 :
112 : mozilla::GenericErrorResult<AbortReason>
113 0 : MIRGenerator::abort(AbortReason r, const char* message, ...)
114 : {
115 : va_list ap;
116 0 : va_start(ap, message);
117 0 : auto forward = abortFmt(r, message, ap);
118 0 : va_end(ap);
119 0 : return forward;
120 : }
121 :
122 : void
123 13 : MIRGenerator::addAbortedPreliminaryGroup(ObjectGroup* group)
124 : {
125 13 : for (size_t i = 0; i < abortedPreliminaryGroups_.length(); i++) {
126 8 : if (group == abortedPreliminaryGroups_[i])
127 16 : return;
128 : }
129 10 : AutoEnterOOMUnsafeRegion oomUnsafe;
130 5 : if (!abortedPreliminaryGroups_.append(group))
131 0 : oomUnsafe.crash("addAbortedPreliminaryGroup");
132 : }
133 :
134 : void
135 4879 : MIRGraph::addBlock(MBasicBlock* block)
136 : {
137 4879 : MOZ_ASSERT(block);
138 4879 : block->setId(blockIdGen_++);
139 4879 : blocks_.pushBack(block);
140 4879 : numBlocks_++;
141 4879 : }
142 :
143 : void
144 18 : MIRGraph::insertBlockAfter(MBasicBlock* at, MBasicBlock* block)
145 : {
146 18 : block->setId(blockIdGen_++);
147 18 : blocks_.insertAfter(at, block);
148 18 : numBlocks_++;
149 18 : }
150 :
151 : void
152 0 : MIRGraph::insertBlockBefore(MBasicBlock* at, MBasicBlock* block)
153 : {
154 0 : block->setId(blockIdGen_++);
155 0 : blocks_.insertBefore(at, block);
156 0 : numBlocks_++;
157 0 : }
158 :
159 : void
160 0 : MIRGraph::renumberBlocksAfter(MBasicBlock* at)
161 : {
162 0 : MBasicBlockIterator iter = begin(at);
163 0 : iter++;
164 :
165 0 : uint32_t id = at->id();
166 0 : for (; iter != end(); iter++)
167 0 : iter->setId(++id);
168 0 : }
169 :
170 : bool
171 1 : MIRGraph::removeSuccessorBlocks(MBasicBlock* start)
172 : {
173 1 : if (!start->hasLastIns())
174 0 : return true;
175 :
176 1 : start->mark();
177 :
178 : // Mark all successors.
179 2 : Vector<MBasicBlock*, 4, SystemAllocPolicy> blocks;
180 3 : for (size_t i = 0; i < start->numSuccessors(); i++) {
181 2 : if (start->getSuccessor(i)->isMarked())
182 0 : continue;
183 2 : if (!blocks.append(start->getSuccessor(i)))
184 0 : return false;
185 2 : start->getSuccessor(i)->mark();
186 : }
187 138 : for (size_t i = 0; i < blocks.length(); i++) {
188 137 : MBasicBlock* block = blocks[i];
189 137 : if (!block->hasLastIns())
190 2 : continue;
191 :
192 305 : for (size_t j = 0; j < block->numSuccessors(); j++) {
193 170 : if (block->getSuccessor(j)->isMarked())
194 35 : continue;
195 135 : if (!blocks.append(block->getSuccessor(j)))
196 0 : return false;
197 135 : block->getSuccessor(j)->mark();
198 : }
199 : }
200 :
201 1 : if (osrBlock()) {
202 0 : if (osrBlock()->getSuccessor(0)->isMarked())
203 0 : osrBlock()->mark();
204 : }
205 :
206 : // Remove blocks.
207 : // If they don't have any predecessor
208 138 : for (size_t i = 0; i < blocks.length(); i++) {
209 137 : MBasicBlock* block = blocks[i];
210 137 : bool allMarked = true;
211 308 : for (size_t i = 0; i < block->numPredecessors(); i++) {
212 171 : if (block->getPredecessor(i)->isMarked())
213 171 : continue;
214 0 : allMarked = false;
215 0 : break;
216 : }
217 137 : if (allMarked) {
218 137 : removeBlock(block);
219 : } else {
220 0 : MOZ_ASSERT(block != osrBlock());
221 0 : for (size_t j = 0; j < block->numPredecessors(); ) {
222 0 : if (!block->getPredecessor(j)->isMarked()) {
223 0 : j++;
224 0 : continue;
225 : }
226 0 : block->removePredecessor(block->getPredecessor(j));
227 : }
228 : // This shouldn't have any instructions yet.
229 0 : MOZ_ASSERT(block->begin() == block->end());
230 : }
231 : }
232 :
233 1 : if (osrBlock()) {
234 0 : if (osrBlock()->getSuccessor(0)->isDead())
235 0 : removeBlock(osrBlock());
236 : }
237 :
238 138 : for (size_t i = 0; i < blocks.length(); i++)
239 137 : blocks[i]->unmark();
240 1 : start->unmark();
241 :
242 1 : return true;
243 : }
244 :
245 : void
246 392 : MIRGraph::removeBlock(MBasicBlock* block)
247 : {
248 : // Remove a block from the graph. It will also cleanup the block.
249 :
250 392 : if (block == osrBlock_)
251 0 : osrBlock_ = nullptr;
252 :
253 392 : if (returnAccumulator_) {
254 0 : size_t i = 0;
255 0 : while (i < returnAccumulator_->length()) {
256 0 : if ((*returnAccumulator_)[i] == block)
257 0 : returnAccumulator_->erase(returnAccumulator_->begin() + i);
258 : else
259 0 : i++;
260 : }
261 : }
262 :
263 392 : block->clear();
264 392 : block->markAsDead();
265 :
266 392 : if (block->isInList()) {
267 390 : blocks_.remove(block);
268 390 : numBlocks_--;
269 : }
270 392 : }
271 :
272 : void
273 0 : MIRGraph::removeBlockIncludingPhis(MBasicBlock* block)
274 : {
275 : // removeBlock doesn't clear phis because of IonBuilder constraints. Here,
276 : // we want to totally clear everything.
277 0 : removeBlock(block);
278 0 : block->discardAllPhis();
279 0 : }
280 :
281 : void
282 214 : MIRGraph::unmarkBlocks()
283 : {
284 11571 : for (MBasicBlockIterator i(blocks_.begin()); i != blocks_.end(); i++)
285 11357 : i->unmark();
286 214 : }
287 :
288 : MBasicBlock*
289 3828 : MBasicBlock::New(MIRGraph& graph, BytecodeAnalysis* analysis, const CompileInfo& info,
290 : MBasicBlock* pred, BytecodeSite* site, Kind kind)
291 : {
292 3828 : MOZ_ASSERT(site->pc() != nullptr);
293 :
294 3828 : MBasicBlock* block = new(graph.alloc()) MBasicBlock(graph, info, site, kind);
295 3828 : if (!block->init())
296 0 : return nullptr;
297 :
298 3828 : if (!block->inherit(graph.alloc(), analysis, pred, 0))
299 0 : return nullptr;
300 :
301 3828 : return block;
302 : }
303 :
304 : MBasicBlock*
305 0 : MBasicBlock::NewPopN(MIRGraph& graph, const CompileInfo& info,
306 : MBasicBlock* pred, BytecodeSite* site, Kind kind, uint32_t popped)
307 : {
308 0 : MBasicBlock* block = new(graph.alloc()) MBasicBlock(graph, info, site, kind);
309 0 : if (!block->init())
310 0 : return nullptr;
311 :
312 0 : if (!block->inherit(graph.alloc(), nullptr, pred, popped))
313 0 : return nullptr;
314 :
315 0 : return block;
316 : }
317 :
318 : MBasicBlock*
319 0 : MBasicBlock::NewWithResumePoint(MIRGraph& graph, const CompileInfo& info,
320 : MBasicBlock* pred, BytecodeSite* site,
321 : MResumePoint* resumePoint)
322 : {
323 0 : MBasicBlock* block = new(graph.alloc()) MBasicBlock(graph, info, site, NORMAL);
324 :
325 0 : MOZ_ASSERT(!resumePoint->instruction());
326 0 : resumePoint->block()->discardResumePoint(resumePoint, RefType_None);
327 0 : resumePoint->block_ = block;
328 0 : block->addResumePoint(resumePoint);
329 0 : block->entryResumePoint_ = resumePoint;
330 :
331 0 : if (!block->init())
332 0 : return nullptr;
333 :
334 0 : if (!block->inheritResumePoint(pred))
335 0 : return nullptr;
336 :
337 0 : return block;
338 : }
339 :
340 : MBasicBlock*
341 118 : MBasicBlock::NewPendingLoopHeader(MIRGraph& graph, const CompileInfo& info,
342 : MBasicBlock* pred, BytecodeSite* site,
343 : unsigned stackPhiCount)
344 : {
345 118 : MOZ_ASSERT(site->pc() != nullptr);
346 :
347 118 : MBasicBlock* block = new(graph.alloc()) MBasicBlock(graph, info, site, PENDING_LOOP_HEADER);
348 118 : if (!block->init())
349 0 : return nullptr;
350 :
351 118 : if (!block->inherit(graph.alloc(), nullptr, pred, 0, stackPhiCount))
352 0 : return nullptr;
353 :
354 118 : return block;
355 : }
356 :
357 : MBasicBlock*
358 14 : MBasicBlock::NewSplitEdge(MIRGraph& graph, MBasicBlock* pred, size_t predEdgeIdx, MBasicBlock* succ)
359 : {
360 14 : MBasicBlock* split = nullptr;
361 14 : if (!succ->pc()) {
362 : // The predecessor does not have a PC, this is a Wasm compilation.
363 0 : split = MBasicBlock::New(graph, succ->info(), pred, SPLIT_EDGE);
364 0 : if (!split)
365 0 : return nullptr;
366 : } else {
367 : // The predecessor has a PC, this is an IonBuilder compilation.
368 14 : MResumePoint* succEntry = succ->entryResumePoint();
369 :
370 14 : BytecodeSite* site = new(graph.alloc()) BytecodeSite(succ->trackedTree(), succEntry->pc());
371 14 : split = new(graph.alloc()) MBasicBlock(graph, succ->info(), site, SPLIT_EDGE);
372 :
373 14 : if (!split->init())
374 0 : return nullptr;
375 :
376 : // A split edge is used to simplify the graph to avoid having a
377 : // predecessor with multiple successors as well as a successor with
378 : // multiple predecessors. As instructions can be moved in this
379 : // split-edge block, we need to give this block a resume point. To do
380 : // so, we copy the entry resume points of the successor and filter the
381 : // phis to keep inputs from the current edge.
382 :
383 : // Propagate the caller resume point from the inherited block.
384 14 : split->callerResumePoint_ = succ->callerResumePoint();
385 :
386 : // Split-edge are created after the interpreter stack emulation. Thus,
387 : // there is no need for creating slots.
388 14 : split->stackPosition_ = succEntry->stackDepth();
389 :
390 : // Create a resume point using our initial stack position.
391 14 : MResumePoint* splitEntry = new(graph.alloc()) MResumePoint(split, succEntry->pc(),
392 14 : MResumePoint::ResumeAt);
393 14 : if (!splitEntry->init(graph.alloc()))
394 0 : return nullptr;
395 14 : split->entryResumePoint_ = splitEntry;
396 :
397 : // The target entry resume point might have phi operands, keep the
398 : // operands of the phi coming from our edge.
399 14 : size_t succEdgeIdx = succ->indexForPredecessor(pred);
400 :
401 254 : for (size_t i = 0, e = splitEntry->numOperands(); i < e; i++) {
402 240 : MDefinition* def = succEntry->getOperand(i);
403 : // This early in the pipeline, we have no recover instructions in
404 : // any entry resume point.
405 240 : MOZ_ASSERT_IF(def->block() == succ, def->isPhi());
406 240 : if (def->block() == succ)
407 3 : def = def->toPhi()->getOperand(succEdgeIdx);
408 :
409 240 : splitEntry->initOperand(i, def);
410 : }
411 :
412 : // This is done in the New variant for wasm, so we cannot keep this
413 : // line below, where the rest of the graph is modified.
414 14 : if (!split->predecessors_.append(pred))
415 0 : return nullptr;
416 : }
417 :
418 14 : split->setLoopDepth(succ->loopDepth());
419 :
420 : // Insert the split edge block in-between.
421 14 : split->end(MGoto::New(graph.alloc(), succ));
422 :
423 14 : graph.insertBlockAfter(pred, split);
424 :
425 14 : pred->replaceSuccessor(predEdgeIdx, split);
426 14 : succ->replacePredecessor(pred, split);
427 14 : return split;
428 : }
429 :
430 : MBasicBlock*
431 0 : MBasicBlock::New(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pred, Kind kind)
432 : {
433 0 : BytecodeSite* site = new(graph.alloc()) BytecodeSite();
434 0 : MBasicBlock* block = new(graph.alloc()) MBasicBlock(graph, info, site, kind);
435 0 : if (!block->init())
436 0 : return nullptr;
437 :
438 0 : if (pred) {
439 0 : block->stackPosition_ = pred->stackPosition_;
440 :
441 0 : if (block->kind_ == PENDING_LOOP_HEADER) {
442 0 : size_t nphis = block->stackPosition_;
443 :
444 0 : size_t nfree = graph.phiFreeListLength();
445 :
446 0 : TempAllocator& alloc = graph.alloc();
447 0 : MPhi* phis = nullptr;
448 0 : if (nphis > nfree) {
449 0 : phis = alloc.allocateArray<MPhi>(nphis - nfree);
450 0 : if (!phis)
451 0 : return nullptr;
452 : }
453 :
454 : // Note: Phis are inserted in the same order as the slots.
455 0 : for (size_t i = 0; i < nphis; i++) {
456 0 : MDefinition* predSlot = pred->getSlot(i);
457 :
458 0 : MOZ_ASSERT(predSlot->type() != MIRType::Value);
459 :
460 : MPhi* phi;
461 0 : if (i < nfree)
462 0 : phi = graph.takePhiFromFreeList();
463 : else
464 0 : phi = phis + (i - nfree);
465 0 : new(phi) MPhi(alloc, predSlot->type());
466 :
467 0 : phi->addInlineInput(predSlot);
468 :
469 : // Add append Phis in the block.
470 0 : block->addPhi(phi);
471 0 : block->setSlot(i, phi);
472 : }
473 : } else {
474 0 : block->copySlots(pred);
475 : }
476 :
477 0 : if (!block->predecessors_.append(pred))
478 0 : return nullptr;
479 : }
480 :
481 0 : return block;
482 : }
483 :
484 3960 : MBasicBlock::MBasicBlock(MIRGraph& graph, const CompileInfo& info, BytecodeSite* site, Kind kind)
485 : : unreachable_(false),
486 : specialized_(false),
487 : graph_(graph),
488 : info_(info),
489 : predecessors_(graph.alloc()),
490 3960 : stackPosition_(info_.firstStackSlot()),
491 : numDominated_(0),
492 3960 : pc_(site->pc()),
493 : lir_(nullptr),
494 : callerResumePoint_(nullptr),
495 : entryResumePoint_(nullptr),
496 : outerResumePoint_(nullptr),
497 : successorWithPhis_(nullptr),
498 : positionInPhiSuccessor_(0),
499 : loopDepth_(0),
500 : kind_(kind),
501 : mark_(false),
502 : immediatelyDominated_(graph.alloc()),
503 : immediateDominator_(nullptr),
504 : trackedSite_(site),
505 : hitCount_(0),
506 11880 : hitState_(HitState::NotDefined)
507 : #if defined (JS_ION_PERF)
508 : , lineno_(0u),
509 : columnIndex_(0u)
510 : #endif
511 : {
512 3960 : }
513 :
514 : bool
515 3960 : MBasicBlock::init()
516 : {
517 3960 : return slots_.init(graph_.alloc(), info_.nslots());
518 : }
519 :
520 : bool
521 0 : MBasicBlock::increaseSlots(size_t num)
522 : {
523 0 : return slots_.growBy(graph_.alloc(), num);
524 : }
525 :
526 : bool
527 0 : MBasicBlock::ensureHasSlots(size_t num)
528 : {
529 0 : size_t depth = stackDepth() + num;
530 0 : if (depth > nslots()) {
531 0 : if (!increaseSlots(depth - nslots()))
532 0 : return false;
533 : }
534 0 : return true;
535 : }
536 :
537 : void
538 3645 : MBasicBlock::copySlots(MBasicBlock* from)
539 : {
540 3645 : MOZ_ASSERT(stackPosition_ <= from->stackPosition_);
541 :
542 3645 : MDefinition** thisSlots = slots_.begin();
543 3645 : MDefinition** fromSlots = from->slots_.begin();
544 49807 : for (size_t i = 0, e = stackPosition_; i < e; ++i)
545 46162 : thisSlots[i] = fromSlots[i];
546 3645 : }
547 :
548 : bool
549 3946 : MBasicBlock::inherit(TempAllocator& alloc, BytecodeAnalysis* analysis, MBasicBlock* pred,
550 : uint32_t popped, unsigned stackPhiCount)
551 : {
552 3946 : if (pred) {
553 3729 : stackPosition_ = pred->stackPosition_;
554 3729 : MOZ_ASSERT(stackPosition_ >= popped);
555 3729 : stackPosition_ -= popped;
556 3729 : if (kind_ != PENDING_LOOP_HEADER)
557 3611 : copySlots(pred);
558 : } else {
559 217 : uint32_t stackDepth = analysis->info(pc()).stackDepth;
560 217 : stackPosition_ = info().firstStackSlot() + stackDepth;
561 217 : MOZ_ASSERT(stackPosition_ >= popped);
562 217 : stackPosition_ -= popped;
563 : }
564 :
565 3946 : MOZ_ASSERT(info_.nslots() >= stackPosition_);
566 3946 : MOZ_ASSERT(!entryResumePoint_);
567 :
568 : // Propagate the caller resume point from the inherited block.
569 3946 : callerResumePoint_ = pred ? pred->callerResumePoint() : nullptr;
570 :
571 : // Create a resume point using our initial stack state.
572 3946 : entryResumePoint_ = new(alloc) MResumePoint(this, pc(), MResumePoint::ResumeAt);
573 3946 : if (!entryResumePoint_->init(alloc))
574 0 : return false;
575 :
576 3946 : if (pred) {
577 3729 : if (!predecessors_.append(pred))
578 0 : return false;
579 :
580 3729 : if (kind_ == PENDING_LOOP_HEADER) {
581 118 : size_t i = 0;
582 1647 : for (i = 0; i < info().firstStackSlot(); i++) {
583 1529 : MPhi* phi = MPhi::New(alloc.fallible());
584 1529 : if (!phi)
585 0 : return false;
586 1529 : phi->addInlineInput(pred->getSlot(i));
587 1529 : addPhi(phi);
588 1529 : setSlot(i, phi);
589 1529 : entryResumePoint()->initOperand(i, phi);
590 : }
591 :
592 118 : MOZ_ASSERT(stackPhiCount <= stackDepth());
593 118 : MOZ_ASSERT(info().firstStackSlot() <= stackDepth() - stackPhiCount);
594 :
595 : // Avoid creating new phis for stack values that aren't part of the
596 : // loop. Note that for loop headers that can OSR, all values on the
597 : // stack are part of the loop.
598 118 : for (; i < stackDepth() - stackPhiCount; i++) {
599 0 : MDefinition* val = pred->getSlot(i);
600 0 : setSlot(i, val);
601 0 : entryResumePoint()->initOperand(i, val);
602 : }
603 :
604 130 : for (; i < stackDepth(); i++) {
605 6 : MPhi* phi = MPhi::New(alloc.fallible());
606 6 : if (!phi)
607 0 : return false;
608 6 : phi->addInlineInput(pred->getSlot(i));
609 6 : addPhi(phi);
610 6 : setSlot(i, phi);
611 6 : entryResumePoint()->initOperand(i, phi);
612 : }
613 : } else {
614 49275 : for (size_t i = 0; i < stackDepth(); i++)
615 45664 : entryResumePoint()->initOperand(i, getSlot(i));
616 : }
617 : } else {
618 : /*
619 : * Don't leave the operands uninitialized for the caller, as it may not
620 : * initialize them later on.
621 : */
622 2571 : for (size_t i = 0; i < stackDepth(); i++)
623 2354 : entryResumePoint()->clearOperand(i);
624 : }
625 :
626 3946 : return true;
627 : }
628 :
629 : bool
630 0 : MBasicBlock::inheritResumePoint(MBasicBlock* pred)
631 : {
632 : // Copy slots from the resume point.
633 0 : stackPosition_ = entryResumePoint_->stackDepth();
634 0 : for (uint32_t i = 0; i < stackPosition_; i++)
635 0 : slots_[i] = entryResumePoint_->getOperand(i);
636 :
637 0 : MOZ_ASSERT(info_.nslots() >= stackPosition_);
638 0 : MOZ_ASSERT(kind_ != PENDING_LOOP_HEADER);
639 0 : MOZ_ASSERT(pred != nullptr);
640 :
641 0 : callerResumePoint_ = pred->callerResumePoint();
642 :
643 0 : if (!predecessors_.append(pred))
644 0 : return false;
645 :
646 0 : return true;
647 : }
648 :
649 : void
650 34 : MBasicBlock::inheritSlots(MBasicBlock* parent)
651 : {
652 34 : stackPosition_ = parent->stackPosition_;
653 34 : copySlots(parent);
654 34 : }
655 :
656 : bool
657 34 : MBasicBlock::initEntrySlots(TempAllocator& alloc)
658 : {
659 : // Remove the previous resume point.
660 34 : discardResumePoint(entryResumePoint_);
661 :
662 : // Create a resume point using our initial stack state.
663 34 : entryResumePoint_ = MResumePoint::New(alloc, this, pc(), MResumePoint::ResumeAt);
664 34 : if (!entryResumePoint_)
665 0 : return false;
666 34 : return true;
667 : }
668 :
669 : MDefinition*
670 155031 : MBasicBlock::getSlot(uint32_t index)
671 : {
672 155031 : MOZ_ASSERT(index < stackPosition_);
673 155031 : return slots_[index];
674 : }
675 :
676 : void
677 1872 : MBasicBlock::initSlot(uint32_t slot, MDefinition* ins)
678 : {
679 1872 : slots_[slot] = ins;
680 1872 : if (entryResumePoint())
681 1872 : entryResumePoint()->initOperand(slot, ins);
682 1872 : }
683 :
684 : void
685 0 : MBasicBlock::shimmySlots(int discardDepth)
686 : {
687 : // Move all slots above the given depth down by one,
688 : // overwriting the MDefinition at discardDepth.
689 :
690 0 : MOZ_ASSERT(discardDepth < 0);
691 0 : MOZ_ASSERT(stackPosition_ + discardDepth >= info_.firstStackSlot());
692 :
693 0 : for (int i = discardDepth; i < -1; i++)
694 0 : slots_[stackPosition_ + i] = slots_[stackPosition_ + i + 1];
695 :
696 0 : --stackPosition_;
697 0 : }
698 :
699 : bool
700 4 : MBasicBlock::linkOsrValues(MStart* start)
701 : {
702 4 : MResumePoint* res = start->resumePoint();
703 :
704 88 : for (uint32_t i = 0; i < stackDepth(); i++) {
705 84 : MDefinition* def = slots_[i];
706 84 : MInstruction* cloneRp = nullptr;
707 84 : if (i == info().environmentChainSlot()) {
708 4 : if (def->isOsrEnvironmentChain())
709 3 : cloneRp = def->toOsrEnvironmentChain();
710 80 : } else if (i == info().returnValueSlot()) {
711 4 : if (def->isOsrReturnValue())
712 4 : cloneRp = def->toOsrReturnValue();
713 76 : } else if (info().hasArguments() && i == info().argsObjSlot()) {
714 1 : MOZ_ASSERT(def->isConstant() || def->isOsrArgumentsObject());
715 1 : MOZ_ASSERT_IF(def->isConstant(), def->toConstant()->type() == MIRType::Undefined);
716 1 : if (def->isOsrArgumentsObject())
717 0 : cloneRp = def->toOsrArgumentsObject();
718 : } else {
719 75 : MOZ_ASSERT(def->isOsrValue() || def->isGetArgumentsObjectArg() || def->isConstant() ||
720 : def->isParameter());
721 :
722 : // A constant Undefined can show up here for an argument slot when
723 : // the function has an arguments object, but the argument in
724 : // question is stored on the scope chain.
725 75 : MOZ_ASSERT_IF(def->isConstant(), def->toConstant()->type() == MIRType::Undefined);
726 :
727 75 : if (def->isOsrValue())
728 58 : cloneRp = def->toOsrValue();
729 17 : else if (def->isGetArgumentsObjectArg())
730 0 : cloneRp = def->toGetArgumentsObjectArg();
731 17 : else if (def->isParameter())
732 17 : cloneRp = def->toParameter();
733 : }
734 :
735 84 : if (cloneRp) {
736 82 : MResumePoint* clone = MResumePoint::Copy(graph().alloc(), res);
737 82 : if (!clone)
738 0 : return false;
739 82 : cloneRp->setResumePoint(clone);
740 : }
741 : }
742 :
743 4 : return true;
744 : }
745 :
746 : void
747 5918 : MBasicBlock::setSlot(uint32_t slot, MDefinition* ins)
748 : {
749 5918 : slots_[slot] = ins;
750 5918 : }
751 :
752 : void
753 1315 : MBasicBlock::setVariable(uint32_t index)
754 : {
755 1315 : MOZ_ASSERT(stackPosition_ > info_.firstStackSlot());
756 1315 : setSlot(index, slots_[stackPosition_ - 1]);
757 1315 : }
758 :
759 : void
760 18 : MBasicBlock::setArg(uint32_t arg)
761 : {
762 18 : setVariable(info_.argSlot(arg));
763 18 : }
764 :
765 : void
766 1297 : MBasicBlock::setLocal(uint32_t local)
767 : {
768 1297 : setVariable(info_.localSlot(local));
769 1297 : }
770 :
771 : void
772 0 : MBasicBlock::setSlot(uint32_t slot)
773 : {
774 0 : setVariable(slot);
775 0 : }
776 :
777 : void
778 111 : MBasicBlock::rewriteSlot(uint32_t slot, MDefinition* ins)
779 : {
780 111 : setSlot(slot, ins);
781 111 : }
782 :
783 : void
784 0 : MBasicBlock::rewriteAtDepth(int32_t depth, MDefinition* ins)
785 : {
786 0 : MOZ_ASSERT(depth < 0);
787 0 : MOZ_ASSERT(stackPosition_ + depth >= info_.firstStackSlot());
788 0 : rewriteSlot(stackPosition_ + depth, ins);
789 0 : }
790 :
791 : void
792 17241 : MBasicBlock::push(MDefinition* ins)
793 : {
794 17241 : MOZ_ASSERT(stackPosition_ < nslots());
795 17241 : slots_[stackPosition_++] = ins;
796 17241 : }
797 :
798 : void
799 4177 : MBasicBlock::pushVariable(uint32_t slot)
800 : {
801 4177 : push(slots_[slot]);
802 4177 : }
803 :
804 : void
805 380 : MBasicBlock::pushArg(uint32_t arg)
806 : {
807 380 : pushVariable(info_.argSlot(arg));
808 380 : }
809 :
810 : void
811 3418 : MBasicBlock::pushLocal(uint32_t local)
812 : {
813 3418 : pushVariable(info_.localSlot(local));
814 3418 : }
815 :
816 : void
817 379 : MBasicBlock::pushSlot(uint32_t slot)
818 : {
819 379 : pushVariable(slot);
820 379 : }
821 :
822 : MDefinition*
823 14599 : MBasicBlock::pop()
824 : {
825 14599 : MOZ_ASSERT(stackPosition_ > info_.firstStackSlot());
826 14599 : return slots_[--stackPosition_];
827 : }
828 :
829 : void
830 2271 : MBasicBlock::popn(uint32_t n)
831 : {
832 2271 : MOZ_ASSERT(stackPosition_ - n >= info_.firstStackSlot());
833 2271 : MOZ_ASSERT(stackPosition_ >= stackPosition_ - n);
834 2271 : stackPosition_ -= n;
835 2271 : }
836 :
837 : MDefinition*
838 175 : MBasicBlock::environmentChain()
839 : {
840 175 : return getSlot(info().environmentChainSlot());
841 : }
842 :
843 : MDefinition*
844 147 : MBasicBlock::argumentsObject()
845 : {
846 147 : return getSlot(info().argsObjSlot());
847 : }
848 :
849 : void
850 151 : MBasicBlock::setEnvironmentChain(MDefinition* scopeObj)
851 : {
852 151 : setSlot(info().environmentChainSlot(), scopeObj);
853 151 : }
854 :
855 : void
856 135 : MBasicBlock::setArgumentsObject(MDefinition* argsObj)
857 : {
858 135 : setSlot(info().argsObjSlot(), argsObj);
859 135 : }
860 :
861 : void
862 9 : MBasicBlock::pick(int32_t depth)
863 : {
864 : // pick take an element and move it to the top.
865 : // pick(-2):
866 : // A B C D E
867 : // A B D C E [ swapAt(-2) ]
868 : // A B D E C [ swapAt(-1) ]
869 15 : for (; depth < 0; depth++)
870 6 : swapAt(depth);
871 3 : }
872 :
873 : void
874 6 : MBasicBlock::unpick(int32_t depth)
875 : {
876 : // unpick take the top of the stack element and move it under the depth-th
877 : // element;
878 : // unpick(-2):
879 : // A B C D E
880 : // A B C E D [ swapAt(-1) ]
881 : // A B E C D [ swapAt(-2) ]
882 16 : for (int32_t n = -1; n >= depth; n--)
883 10 : swapAt(n);
884 6 : }
885 :
886 : void
887 87 : MBasicBlock::swapAt(int32_t depth)
888 : {
889 87 : uint32_t lhsDepth = stackPosition_ + depth - 1;
890 87 : uint32_t rhsDepth = stackPosition_ + depth;
891 :
892 87 : MDefinition* temp = slots_[lhsDepth];
893 87 : slots_[lhsDepth] = slots_[rhsDepth];
894 87 : slots_[rhsDepth] = temp;
895 87 : }
896 :
897 : MDefinition*
898 21973 : MBasicBlock::peek(int32_t depth)
899 : {
900 21973 : MOZ_ASSERT(depth < 0);
901 21973 : MOZ_ASSERT(stackPosition_ + depth >= info_.firstStackSlot());
902 21973 : return getSlot(stackPosition_ + depth);
903 : }
904 :
905 : void
906 86 : MBasicBlock::discardLastIns()
907 : {
908 86 : discard(lastIns());
909 86 : }
910 :
911 : MConstant*
912 4464 : MBasicBlock::optimizedOutConstant(TempAllocator& alloc)
913 : {
914 : // If the first instruction is a MConstant(MagicValue(JS_OPTIMIZED_OUT))
915 : // then reuse it.
916 4464 : MInstruction* ins = *begin();
917 4464 : if (ins->type() == MIRType::MagicOptimizedOut)
918 3656 : return ins->toConstant();
919 :
920 808 : MConstant* constant = MConstant::New(alloc, MagicValue(JS_OPTIMIZED_OUT));
921 808 : insertBefore(ins, constant);
922 808 : return constant;
923 : }
924 :
925 : void
926 0 : MBasicBlock::addFromElsewhere(MInstruction* ins)
927 : {
928 0 : MOZ_ASSERT(ins->block() != this);
929 :
930 : // Remove |ins| from its containing block.
931 0 : ins->block()->instructions_.remove(ins);
932 :
933 : // Add it to this block.
934 0 : add(ins);
935 0 : }
936 :
937 : void
938 35 : MBasicBlock::moveBefore(MInstruction* at, MInstruction* ins)
939 : {
940 : // Remove |ins| from the current block.
941 35 : MOZ_ASSERT(ins->block() == this);
942 35 : instructions_.remove(ins);
943 :
944 : // Insert into new block, which may be distinct.
945 : // Uses and operands are untouched.
946 35 : ins->setBlock(at->block());
947 35 : at->block()->instructions_.insertBefore(at, ins);
948 35 : ins->setTrackedSite(at->trackedSite());
949 35 : }
950 :
951 : MInstruction*
952 14913 : MBasicBlock::safeInsertTop(MDefinition* ins, IgnoreTop ignore)
953 : {
954 14913 : MOZ_ASSERT(graph().osrBlock() != this,
955 : "We are not supposed to add any instruction in OSR blocks.");
956 :
957 : // Beta nodes and interrupt checks are required to be located at the
958 : // beginnings of basic blocks, so we must insert new instructions after any
959 : // such instructions.
960 0 : MInstructionIterator insertIter = !ins || ins->isPhi()
961 14913 : ? begin()
962 14913 : : begin(ins->toInstruction());
963 87271 : while (insertIter->isBeta() ||
964 50771 : insertIter->isInterruptCheck() ||
965 42016 : insertIter->isConstant() ||
966 68874 : insertIter->isParameter() ||
967 31858 : (!(ignore & IgnoreRecover) && insertIter->isRecoveredOnBailout()))
968 : {
969 10658 : insertIter++;
970 : }
971 :
972 14913 : return *insertIter;
973 : }
974 :
975 : void
976 811 : MBasicBlock::discardResumePoint(MResumePoint* rp, ReferencesType refType /* = RefType_Default */)
977 : {
978 811 : if (refType & RefType_DiscardOperands)
979 811 : rp->releaseUses();
980 : #ifdef DEBUG
981 811 : MResumePointIterator iter = resumePointsBegin();
982 1605 : while (*iter != rp) {
983 : // We should reach it before reaching the end.
984 397 : MOZ_ASSERT(iter != resumePointsEnd());
985 397 : iter++;
986 : }
987 811 : resumePoints_.removeAt(iter);
988 : #endif
989 811 : }
990 :
991 : void
992 2549 : MBasicBlock::prepareForDiscard(MInstruction* ins, ReferencesType refType /* = RefType_Default */)
993 : {
994 : // Only remove instructions from the same basic block. This is needed for
995 : // correctly removing the resume point if any.
996 2549 : MOZ_ASSERT(ins->block() == this);
997 :
998 2549 : MResumePoint* rp = ins->resumePoint();
999 2549 : if ((refType & RefType_DiscardResumePoint) && rp)
1000 327 : discardResumePoint(rp, refType);
1001 :
1002 : // We need to assert that instructions have no uses after removing the their
1003 : // resume points operands as they could be captured by their own resume
1004 : // point.
1005 2549 : MOZ_ASSERT_IF(refType & RefType_AssertNoUses, !ins->hasUses());
1006 :
1007 2549 : const uint32_t InstructionOperands = RefType_DiscardOperands | RefType_DiscardInstruction;
1008 2549 : if ((refType & InstructionOperands) == InstructionOperands) {
1009 2362 : for (size_t i = 0, e = ins->numOperands(); i < e; i++)
1010 880 : ins->releaseOperand(i);
1011 : }
1012 :
1013 2549 : ins->setDiscarded();
1014 2549 : }
1015 :
1016 : void
1017 248 : MBasicBlock::discard(MInstruction* ins)
1018 : {
1019 248 : prepareForDiscard(ins);
1020 248 : instructions_.remove(ins);
1021 248 : }
1022 :
1023 : void
1024 1067 : MBasicBlock::discardIgnoreOperands(MInstruction* ins)
1025 : {
1026 : #ifdef DEBUG
1027 1397 : for (size_t i = 0, e = ins->numOperands(); i < e; i++)
1028 330 : MOZ_ASSERT(!ins->hasOperand(i));
1029 : #endif
1030 :
1031 1067 : prepareForDiscard(ins, RefType_IgnoreOperands);
1032 1067 : instructions_.remove(ins);
1033 1067 : }
1034 :
1035 : void
1036 50 : MBasicBlock::discardDef(MDefinition* at)
1037 : {
1038 50 : if (at->isPhi())
1039 0 : at->block_->discardPhi(at->toPhi());
1040 : else
1041 50 : at->block_->discard(at->toInstruction());
1042 50 : }
1043 :
1044 : void
1045 393 : MBasicBlock::discardAllInstructions()
1046 : {
1047 393 : MInstructionIterator iter = begin();
1048 393 : discardAllInstructionsStartingAt(iter);
1049 393 : }
1050 :
1051 : void
1052 1662 : MBasicBlock::discardAllInstructionsStartingAt(MInstructionIterator iter)
1053 : {
1054 2896 : while (iter != end()) {
1055 : // Discard operands and resume point operands and flag the instruction
1056 : // as discarded. Also we do not assert that we have no uses as blocks
1057 : // might be removed in reverse post order.
1058 1234 : MInstruction* ins = *iter++;
1059 1234 : prepareForDiscard(ins, RefType_DefaultNoAssert);
1060 1234 : instructions_.remove(ins);
1061 : }
1062 428 : }
1063 :
1064 : void
1065 392 : MBasicBlock::discardAllPhiOperands()
1066 : {
1067 431 : for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++)
1068 39 : iter->removeAllOperands();
1069 :
1070 773 : for (MBasicBlock** pred = predecessors_.begin(); pred != predecessors_.end(); pred++)
1071 381 : (*pred)->clearSuccessorWithPhis();
1072 392 : }
1073 :
1074 : void
1075 0 : MBasicBlock::discardAllPhis()
1076 : {
1077 0 : discardAllPhiOperands();
1078 0 : phis_.clear();
1079 0 : }
1080 :
1081 : void
1082 393 : MBasicBlock::discardAllResumePoints(bool discardEntry)
1083 : {
1084 393 : if (outerResumePoint_)
1085 9 : clearOuterResumePoint();
1086 :
1087 393 : if (discardEntry && entryResumePoint_)
1088 392 : clearEntryResumePoint();
1089 :
1090 : #ifdef DEBUG
1091 393 : if (!entryResumePoint()) {
1092 392 : MOZ_ASSERT(resumePointsEmpty());
1093 : } else {
1094 1 : MResumePointIterator iter(resumePointsBegin());
1095 1 : MOZ_ASSERT(iter != resumePointsEnd());
1096 1 : iter++;
1097 1 : MOZ_ASSERT(iter == resumePointsEnd());
1098 : }
1099 : #endif
1100 393 : }
1101 :
1102 : void
1103 392 : MBasicBlock::clear()
1104 : {
1105 392 : discardAllInstructions();
1106 392 : discardAllResumePoints();
1107 :
1108 : // Note: phis are disconnected from the rest of the graph, but are not
1109 : // removed entirely. If the block being removed is a loop header then
1110 : // IonBuilder may need to access these phis to more quickly converge on the
1111 : // possible types in the graph. See IonBuilder::analyzeNewLoopTypes.
1112 392 : discardAllPhiOperands();
1113 392 : }
1114 :
1115 : void
1116 1272 : MBasicBlock::insertBefore(MInstruction* at, MInstruction* ins)
1117 : {
1118 1272 : MOZ_ASSERT(at->block() == this);
1119 1272 : ins->setBlock(this);
1120 1272 : graph().allocDefinitionId(ins);
1121 1272 : instructions_.insertBefore(at, ins);
1122 1272 : ins->setTrackedSite(at->trackedSite());
1123 1272 : }
1124 :
1125 : void
1126 32 : MBasicBlock::insertAfter(MInstruction* at, MInstruction* ins)
1127 : {
1128 32 : MOZ_ASSERT(at->block() == this);
1129 32 : ins->setBlock(this);
1130 32 : graph().allocDefinitionId(ins);
1131 32 : instructions_.insertAfter(at, ins);
1132 32 : ins->setTrackedSite(at->trackedSite());
1133 32 : }
1134 :
1135 : void
1136 0 : MBasicBlock::insertAtEnd(MInstruction* ins)
1137 : {
1138 0 : if (hasLastIns())
1139 0 : insertBefore(lastIns(), ins);
1140 : else
1141 0 : add(ins);
1142 0 : }
1143 :
1144 : void
1145 20304 : MBasicBlock::add(MInstruction* ins)
1146 : {
1147 20304 : MOZ_ASSERT(!hasLastIns());
1148 20304 : ins->setBlock(this);
1149 20304 : graph().allocDefinitionId(ins);
1150 20304 : instructions_.pushBack(ins);
1151 20304 : ins->setTrackedSite(trackedSite_);
1152 20304 : }
1153 :
1154 : void
1155 4111 : MBasicBlock::end(MControlInstruction* ins)
1156 : {
1157 4111 : MOZ_ASSERT(!hasLastIns()); // Existing control instructions should be removed first.
1158 4111 : MOZ_ASSERT(ins);
1159 4111 : add(ins);
1160 4111 : }
1161 :
1162 : void
1163 2728 : MBasicBlock::addPhi(MPhi* phi)
1164 : {
1165 2728 : phis_.pushBack(phi);
1166 2728 : phi->setBlock(this);
1167 2728 : graph().allocDefinitionId(phi);
1168 2728 : }
1169 :
1170 : void
1171 1952 : MBasicBlock::discardPhi(MPhi* phi)
1172 : {
1173 1952 : MOZ_ASSERT(!phis_.empty());
1174 :
1175 1952 : phi->removeAllOperands();
1176 1952 : phi->setDiscarded();
1177 :
1178 1952 : phis_.remove(phi);
1179 :
1180 1952 : if (phis_.empty()) {
1181 122 : for (MBasicBlock* pred : predecessors_)
1182 77 : pred->clearSuccessorWithPhis();
1183 : }
1184 1952 : }
1185 :
1186 : void
1187 115 : MBasicBlock::flagOperandsOfPrunedBranches(MInstruction* ins)
1188 : {
1189 : // Find the previous resume point which would be used for bailing out.
1190 115 : MResumePoint* rp = nullptr;
1191 764 : for (MInstructionReverseIterator iter = rbegin(ins); iter != rend(); iter++) {
1192 715 : rp = iter->resumePoint();
1193 715 : if (rp)
1194 66 : break;
1195 : }
1196 :
1197 : // If none, take the entry resume point.
1198 115 : if (!rp)
1199 49 : rp = entryResumePoint();
1200 :
1201 : // The only blocks which do not have any entryResumePoint in Ion, are the
1202 : // SplitEdge blocks. SplitEdge blocks only have a Goto instruction before
1203 : // Range Analysis phase. In adjustInputs, we are manipulating instructions
1204 : // which have a TypePolicy. So, as a Goto has no operand and no type
1205 : // policy, the entry resume point should exists.
1206 115 : MOZ_ASSERT(rp);
1207 :
1208 : // Flag all operand as being potentially used.
1209 154 : while (rp) {
1210 2501 : for (size_t i = 0, end = rp->numOperands(); i < end; i++)
1211 2347 : rp->getOperand(i)->setUseRemovedUnchecked();
1212 154 : rp = rp->caller();
1213 : }
1214 115 : }
1215 :
1216 : bool
1217 669 : MBasicBlock::addPredecessor(TempAllocator& alloc, MBasicBlock* pred)
1218 : {
1219 669 : return addPredecessorPopN(alloc, pred, 0);
1220 : }
1221 :
1222 : bool
1223 669 : MBasicBlock::addPredecessorPopN(TempAllocator& alloc, MBasicBlock* pred, uint32_t popped)
1224 : {
1225 669 : MOZ_ASSERT(pred);
1226 669 : MOZ_ASSERT(predecessors_.length() > 0);
1227 :
1228 : // Predecessors must be finished, and at the correct stack depth.
1229 669 : MOZ_ASSERT(pred->hasLastIns());
1230 669 : MOZ_ASSERT(pred->stackPosition_ == stackPosition_ + popped);
1231 :
1232 10188 : for (uint32_t i = 0, e = stackPosition_; i < e; ++i) {
1233 9519 : MDefinition* mine = getSlot(i);
1234 9519 : MDefinition* other = pred->getSlot(i);
1235 :
1236 9519 : if (mine != other) {
1237 : // If the current instruction is a phi, and it was created in this
1238 : // basic block, then we have already placed this phi and should
1239 : // instead append to its operands.
1240 1312 : if (mine->isPhi() && mine->block() == this) {
1241 222 : MOZ_ASSERT(predecessors_.length());
1242 222 : if (!mine->toPhi()->addInputSlow(other))
1243 0 : return false;
1244 : } else {
1245 : // Otherwise, create a new phi node.
1246 : MPhi* phi;
1247 1090 : if (mine->type() == other->type())
1248 773 : phi = MPhi::New(alloc.fallible(), mine->type());
1249 : else
1250 317 : phi = MPhi::New(alloc.fallible());
1251 1090 : if (!phi)
1252 0 : return false;
1253 1090 : addPhi(phi);
1254 :
1255 : // Prime the phi for each predecessor, so input(x) comes from
1256 : // predecessor(x).
1257 1090 : if (!phi->reserveLength(predecessors_.length() + 1))
1258 0 : return false;
1259 :
1260 2228 : for (size_t j = 0, numPreds = predecessors_.length(); j < numPreds; ++j) {
1261 1138 : MOZ_ASSERT(predecessors_[j]->getSlot(i) == mine);
1262 1138 : phi->addInput(mine);
1263 : }
1264 1090 : phi->addInput(other);
1265 :
1266 1090 : setSlot(i, phi);
1267 1090 : if (entryResumePoint())
1268 1090 : entryResumePoint()->replaceOperand(i, phi);
1269 : }
1270 : }
1271 : }
1272 :
1273 669 : return predecessors_.append(pred);
1274 : }
1275 :
1276 : void
1277 161 : MBasicBlock::addPredecessorSameInputsAs(MBasicBlock* pred, MBasicBlock* existingPred)
1278 : {
1279 161 : MOZ_ASSERT(pred);
1280 161 : MOZ_ASSERT(predecessors_.length() > 0);
1281 :
1282 : // Predecessors must be finished, and at the correct stack depth.
1283 161 : MOZ_ASSERT(pred->hasLastIns());
1284 161 : MOZ_ASSERT(!pred->successorWithPhis());
1285 :
1286 322 : AutoEnterOOMUnsafeRegion oomUnsafe;
1287 :
1288 161 : if (!phisEmpty()) {
1289 2 : size_t existingPosition = indexForPredecessor(existingPred);
1290 4 : for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++) {
1291 2 : if (!iter->addInputSlow(iter->getOperand(existingPosition)))
1292 0 : oomUnsafe.crash("MBasicBlock::addPredecessorAdjustPhis");
1293 : }
1294 : }
1295 :
1296 161 : if (!predecessors_.append(pred))
1297 0 : oomUnsafe.crash("MBasicBlock::addPredecessorAdjustPhis");
1298 161 : }
1299 :
1300 : bool
1301 101 : MBasicBlock::addPredecessorWithoutPhis(MBasicBlock* pred)
1302 : {
1303 : // Predecessors must be finished.
1304 101 : MOZ_ASSERT(pred && pred->hasLastIns());
1305 101 : return predecessors_.append(pred);
1306 : }
1307 :
1308 : bool
1309 3592 : MBasicBlock::addImmediatelyDominatedBlock(MBasicBlock* child)
1310 : {
1311 3592 : return immediatelyDominated_.append(child);
1312 : }
1313 :
1314 : void
1315 50 : MBasicBlock::removeImmediatelyDominatedBlock(MBasicBlock* child)
1316 : {
1317 95 : for (size_t i = 0; ; ++i) {
1318 95 : MOZ_ASSERT(i < immediatelyDominated_.length(),
1319 : "Dominated block to remove not present");
1320 95 : if (immediatelyDominated_[i] == child) {
1321 50 : immediatelyDominated_[i] = immediatelyDominated_.back();
1322 50 : immediatelyDominated_.popBack();
1323 50 : return;
1324 : }
1325 : }
1326 : }
1327 :
1328 : void
1329 0 : MBasicBlock::assertUsesAreNotWithin(MUseIterator use, MUseIterator end)
1330 : {
1331 : #ifdef DEBUG
1332 0 : for (; use != end; use++) {
1333 0 : MOZ_ASSERT_IF(use->consumer()->isDefinition(),
1334 : use->consumer()->toDefinition()->block()->id() < id());
1335 : }
1336 : #endif
1337 0 : }
1338 :
1339 : AbortReason
1340 117 : MBasicBlock::setBackedge(TempAllocator& alloc, MBasicBlock* pred)
1341 : {
1342 : // Predecessors must be finished, and at the correct stack depth.
1343 117 : MOZ_ASSERT(hasLastIns());
1344 117 : MOZ_ASSERT(pred->hasLastIns());
1345 117 : MOZ_ASSERT(pred->stackDepth() == entryResumePoint()->stackDepth());
1346 :
1347 : // We must be a pending loop header
1348 117 : MOZ_ASSERT(kind_ == PENDING_LOOP_HEADER);
1349 :
1350 117 : bool hadTypeChange = false;
1351 :
1352 : // Add exit definitions to each corresponding phi at the entry.
1353 117 : if (!inheritPhisFromBackedge(alloc, pred, &hadTypeChange))
1354 0 : return AbortReason::Alloc;
1355 :
1356 117 : if (hadTypeChange) {
1357 11 : for (MPhiIterator phi = phisBegin(); phi != phisEnd(); phi++)
1358 10 : phi->removeOperand(phi->numOperands() - 1);
1359 1 : return AbortReason::Disable;
1360 : }
1361 :
1362 : // We are now a loop header proper
1363 116 : kind_ = LOOP_HEADER;
1364 :
1365 116 : if (!predecessors_.append(pred))
1366 0 : return AbortReason::Alloc;
1367 :
1368 116 : return AbortReason::NoAbort;
1369 : }
1370 :
1371 : bool
1372 0 : MBasicBlock::setBackedgeWasm(MBasicBlock* pred)
1373 : {
1374 : // Predecessors must be finished, and at the correct stack depth.
1375 0 : MOZ_ASSERT(hasLastIns());
1376 0 : MOZ_ASSERT(pred->hasLastIns());
1377 0 : MOZ_ASSERT(stackDepth() == pred->stackDepth());
1378 :
1379 : // We must be a pending loop header
1380 0 : MOZ_ASSERT(kind_ == PENDING_LOOP_HEADER);
1381 :
1382 : // Add exit definitions to each corresponding phi at the entry.
1383 : // Note: Phis are inserted in the same order as the slots. (see
1384 : // MBasicBlock::New)
1385 0 : size_t slot = 0;
1386 0 : for (MPhiIterator phi = phisBegin(); phi != phisEnd(); phi++, slot++) {
1387 0 : MPhi* entryDef = *phi;
1388 0 : MDefinition* exitDef = pred->getSlot(slot);
1389 :
1390 : // Assert that we already placed phis for each slot.
1391 0 : MOZ_ASSERT(entryDef->block() == this);
1392 :
1393 : // Assert that the phi already has the correct type.
1394 0 : MOZ_ASSERT(entryDef->type() == exitDef->type());
1395 0 : MOZ_ASSERT(entryDef->type() != MIRType::Value);
1396 :
1397 0 : if (entryDef == exitDef) {
1398 : // If the exit def is the same as the entry def, make a redundant
1399 : // phi. Since loop headers have exactly two incoming edges, we
1400 : // know that that's just the first input.
1401 : //
1402 : // Note that we eliminate later rather than now, to avoid any
1403 : // weirdness around pending continue edges which might still hold
1404 : // onto phis.
1405 0 : exitDef = entryDef->getOperand(0);
1406 : }
1407 :
1408 : // Phis always have room for 2 operands, so this can't fail.
1409 0 : MOZ_ASSERT(phi->numOperands() == 1);
1410 0 : entryDef->addInlineInput(exitDef);
1411 :
1412 0 : MOZ_ASSERT(slot < pred->stackDepth());
1413 0 : setSlot(slot, entryDef);
1414 : }
1415 :
1416 : // We are now a loop header proper
1417 0 : kind_ = LOOP_HEADER;
1418 :
1419 0 : return predecessors_.append(pred);
1420 : }
1421 :
1422 : void
1423 0 : MBasicBlock::clearLoopHeader()
1424 : {
1425 0 : MOZ_ASSERT(isLoopHeader());
1426 0 : kind_ = NORMAL;
1427 0 : }
1428 :
1429 : void
1430 0 : MBasicBlock::setLoopHeader(MBasicBlock* newBackedge)
1431 : {
1432 0 : MOZ_ASSERT(!isLoopHeader());
1433 0 : kind_ = LOOP_HEADER;
1434 :
1435 0 : size_t numPreds = numPredecessors();
1436 0 : MOZ_ASSERT(numPreds != 0);
1437 :
1438 0 : size_t lastIndex = numPreds - 1;
1439 0 : size_t oldIndex = 0;
1440 0 : for (; ; ++oldIndex) {
1441 0 : MOZ_ASSERT(oldIndex < numPreds);
1442 0 : MBasicBlock* pred = getPredecessor(oldIndex);
1443 0 : if (pred == newBackedge)
1444 0 : break;
1445 0 : }
1446 :
1447 : // Set the loop backedge to be the last element in predecessors_.
1448 0 : Swap(predecessors_[oldIndex], predecessors_[lastIndex]);
1449 :
1450 : // If we have phis, reorder their operands accordingly.
1451 0 : if (!phisEmpty()) {
1452 0 : getPredecessor(oldIndex)->setSuccessorWithPhis(this, oldIndex);
1453 0 : getPredecessor(lastIndex)->setSuccessorWithPhis(this, lastIndex);
1454 0 : for (MPhiIterator iter(phisBegin()), end(phisEnd()); iter != end; ++iter) {
1455 0 : MPhi* phi = *iter;
1456 0 : MDefinition* last = phi->getOperand(oldIndex);
1457 0 : MDefinition* old = phi->getOperand(lastIndex);
1458 0 : phi->replaceOperand(oldIndex, old);
1459 0 : phi->replaceOperand(lastIndex, last);
1460 : }
1461 : }
1462 :
1463 0 : MOZ_ASSERT(newBackedge->loopHeaderOfBackedge() == this);
1464 0 : MOZ_ASSERT(backedge() == newBackedge);
1465 0 : }
1466 :
1467 : size_t
1468 109839 : MBasicBlock::numSuccessors() const
1469 : {
1470 109839 : MOZ_ASSERT(lastIns());
1471 109834 : return lastIns()->numSuccessors();
1472 : }
1473 :
1474 : MBasicBlock*
1475 58731 : MBasicBlock::getSuccessor(size_t index) const
1476 : {
1477 58731 : MOZ_ASSERT(lastIns());
1478 58729 : return lastIns()->getSuccessor(index);
1479 : }
1480 :
1481 : size_t
1482 122 : MBasicBlock::getSuccessorIndex(MBasicBlock* block) const
1483 : {
1484 122 : MOZ_ASSERT(lastIns());
1485 239 : for (size_t i = 0; i < numSuccessors(); i++) {
1486 239 : if (getSuccessor(i) == block)
1487 244 : return i;
1488 : }
1489 0 : MOZ_CRASH("Invalid successor");
1490 : }
1491 :
1492 : size_t
1493 395 : MBasicBlock::getPredecessorIndex(MBasicBlock* block) const
1494 : {
1495 543 : for (size_t i = 0, e = numPredecessors(); i < e; ++i) {
1496 543 : if (getPredecessor(i) == block)
1497 790 : return i;
1498 : }
1499 0 : MOZ_CRASH("Invalid predecessor");
1500 : }
1501 :
1502 : void
1503 14 : MBasicBlock::replaceSuccessor(size_t pos, MBasicBlock* split)
1504 : {
1505 14 : MOZ_ASSERT(lastIns());
1506 :
1507 : // Note, during split-critical-edges, successors-with-phis is not yet set.
1508 : // During PAA, this case is handled before we enter.
1509 14 : MOZ_ASSERT_IF(successorWithPhis_, successorWithPhis_ != getSuccessor(pos));
1510 :
1511 14 : lastIns()->replaceSuccessor(pos, split);
1512 14 : }
1513 :
1514 : void
1515 14 : MBasicBlock::replacePredecessor(MBasicBlock* old, MBasicBlock* split)
1516 : {
1517 20 : for (size_t i = 0; i < numPredecessors(); i++) {
1518 20 : if (getPredecessor(i) == old) {
1519 14 : predecessors_[i] = split;
1520 :
1521 : #ifdef DEBUG
1522 : // The same block should not appear twice in the predecessor list.
1523 36 : for (size_t j = i; j < numPredecessors(); j++)
1524 22 : MOZ_ASSERT(predecessors_[j] != old);
1525 : #endif
1526 :
1527 28 : return;
1528 : }
1529 : }
1530 :
1531 0 : MOZ_CRASH("predecessor was not found");
1532 : }
1533 :
1534 : void
1535 382 : MBasicBlock::clearDominatorInfo()
1536 : {
1537 382 : setImmediateDominator(nullptr);
1538 382 : immediatelyDominated_.clear();
1539 382 : numDominated_ = 0;
1540 382 : }
1541 :
1542 : void
1543 276 : MBasicBlock::removePredecessorWithoutPhiOperands(MBasicBlock* pred, size_t predIndex)
1544 : {
1545 : // If we're removing the last backedge, this is no longer a loop.
1546 276 : if (isLoopHeader() && hasUniqueBackedge() && backedge() == pred)
1547 0 : clearLoopHeader();
1548 :
1549 : // Adjust phis. Note that this can leave redundant phis behind.
1550 : // Don't adjust successorWithPhis() if we haven't constructed this
1551 : // information yet.
1552 276 : if (pred->successorWithPhis()) {
1553 11 : MOZ_ASSERT(pred->positionInPhiSuccessor() == predIndex);
1554 11 : pred->clearSuccessorWithPhis();
1555 23 : for (size_t j = predIndex+1; j < numPredecessors(); j++)
1556 12 : getPredecessor(j)->setSuccessorWithPhis(this, j - 1);
1557 : }
1558 :
1559 : // Remove from pred list.
1560 276 : predecessors_.erase(predecessors_.begin() + predIndex);
1561 276 : }
1562 :
1563 : void
1564 205 : MBasicBlock::removePredecessor(MBasicBlock* pred)
1565 : {
1566 205 : size_t predIndex = getPredecessorIndex(pred);
1567 :
1568 : // Remove the phi operands.
1569 315 : for (MPhiIterator iter(phisBegin()), end(phisEnd()); iter != end; ++iter)
1570 110 : iter->removeOperand(predIndex);
1571 :
1572 : // Now we can call the underlying function, which expects that phi
1573 : // operands have been removed.
1574 205 : removePredecessorWithoutPhiOperands(pred, predIndex);
1575 205 : }
1576 :
1577 : void
1578 0 : MBasicBlock::inheritPhis(MBasicBlock* header)
1579 : {
1580 0 : MResumePoint* headerRp = header->entryResumePoint();
1581 0 : size_t stackDepth = headerRp->stackDepth();
1582 0 : for (size_t slot = 0; slot < stackDepth; slot++) {
1583 0 : MDefinition* exitDef = getSlot(slot);
1584 0 : MDefinition* loopDef = headerRp->getOperand(slot);
1585 0 : if (loopDef->block() != header) {
1586 0 : MOZ_ASSERT(loopDef->block()->id() < header->id());
1587 0 : MOZ_ASSERT(loopDef == exitDef);
1588 0 : continue;
1589 : }
1590 :
1591 : // Phis are allocated by NewPendingLoopHeader.
1592 0 : MPhi* phi = loopDef->toPhi();
1593 0 : MOZ_ASSERT(phi->numOperands() == 2);
1594 :
1595 : // The entry definition is always the leftmost input to the phi.
1596 0 : MDefinition* entryDef = phi->getOperand(0);
1597 :
1598 0 : if (entryDef != exitDef)
1599 0 : continue;
1600 :
1601 : // If the entryDef is the same as exitDef, then we must propagate the
1602 : // phi down to this successor. This chance was missed as part of
1603 : // setBackedge() because exits are not captured in resume points.
1604 0 : setSlot(slot, phi);
1605 : }
1606 0 : }
1607 :
1608 : bool
1609 117 : MBasicBlock::inheritPhisFromBackedge(TempAllocator& alloc, MBasicBlock* backedge, bool* hadTypeChange)
1610 : {
1611 : // We must be a pending loop header
1612 117 : MOZ_ASSERT(kind_ == PENDING_LOOP_HEADER);
1613 :
1614 117 : size_t stackDepth = entryResumePoint()->stackDepth();
1615 1636 : for (size_t slot = 0; slot < stackDepth; slot++) {
1616 : // Get the value stack-slot of the back edge.
1617 1519 : MDefinition* exitDef = backedge->getSlot(slot);
1618 :
1619 : // Get the value of the loop header.
1620 1519 : MDefinition* loopDef = entryResumePoint()->getOperand(slot);
1621 1519 : if (loopDef->block() != this) {
1622 : // If we are finishing a pending loop header, then we need to ensure
1623 : // that all operands are phis. This is usualy the case, except for
1624 : // object/arrays build with generators, in which case we share the
1625 : // same allocations across all blocks.
1626 0 : MOZ_ASSERT(loopDef->block()->id() < id());
1627 0 : MOZ_ASSERT(loopDef == exitDef);
1628 0 : continue;
1629 : }
1630 :
1631 : // Phis are allocated by NewPendingLoopHeader.
1632 1519 : MPhi* entryDef = loopDef->toPhi();
1633 1519 : MOZ_ASSERT(entryDef->block() == this);
1634 :
1635 1519 : if (entryDef == exitDef) {
1636 : // If the exit def is the same as the entry def, make a redundant
1637 : // phi. Since loop headers have exactly two incoming edges, we
1638 : // know that that's just the first input.
1639 : //
1640 : // Note that we eliminate later rather than now, to avoid any
1641 : // weirdness around pending continue edges which might still hold
1642 : // onto phis.
1643 1157 : exitDef = entryDef->getOperand(0);
1644 : }
1645 :
1646 1519 : bool typeChange = false;
1647 :
1648 1519 : if (!entryDef->addInputSlow(exitDef))
1649 0 : return false;
1650 1519 : if (!entryDef->checkForTypeChange(alloc, exitDef, &typeChange))
1651 0 : return false;
1652 1519 : *hadTypeChange |= typeChange;
1653 1519 : setSlot(slot, entryDef);
1654 : }
1655 :
1656 117 : return true;
1657 : }
1658 :
1659 : bool
1660 4762 : MBasicBlock::specializePhis(TempAllocator& alloc)
1661 : {
1662 4762 : if (specialized_)
1663 1089 : return true;
1664 :
1665 3673 : specialized_ = true;
1666 6308 : for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++) {
1667 2635 : MPhi* phi = *iter;
1668 2635 : if (!phi->specializeType(alloc))
1669 0 : return false;
1670 : }
1671 3673 : return true;
1672 : }
1673 :
1674 : MTest*
1675 456 : MBasicBlock::immediateDominatorBranch(BranchDirection* pdirection)
1676 : {
1677 456 : *pdirection = FALSE_BRANCH;
1678 :
1679 456 : if (numPredecessors() != 1)
1680 96 : return nullptr;
1681 :
1682 360 : MBasicBlock* dom = immediateDominator();
1683 360 : if (dom != getPredecessor(0))
1684 0 : return nullptr;
1685 :
1686 : // Look for a trailing MTest branching to this block.
1687 360 : MInstruction* ins = dom->lastIns();
1688 360 : if (ins->isTest()) {
1689 229 : MTest* test = ins->toTest();
1690 :
1691 229 : MOZ_ASSERT(test->ifTrue() == this || test->ifFalse() == this);
1692 229 : if (test->ifTrue() == this && test->ifFalse() == this)
1693 0 : return nullptr;
1694 :
1695 229 : *pdirection = (test->ifTrue() == this) ? TRUE_BRANCH : FALSE_BRANCH;
1696 229 : return test;
1697 : }
1698 :
1699 131 : return nullptr;
1700 : }
1701 :
1702 33 : MBasicBlock::BackupPoint::BackupPoint(MBasicBlock* current)
1703 : : current_(current),
1704 95 : lastIns_(current->hasAnyIns() ? *current->rbegin() : nullptr),
1705 33 : stackPosition_(current->stackDepth()),
1706 : slots_()
1707 : #ifdef DEBUG
1708 67 : , lastPhi_(!current->phisEmpty() ? *current->phis_.rbegin() : nullptr),
1709 33 : predecessorsCheckSum_(computePredecessorsCheckSum(current)),
1710 33 : instructionsCheckSum_(computeInstructionsCheckSum(current)),
1711 33 : id_(current->id()),
1712 33 : callerResumePoint_(current->callerResumePoint()),
1713 300 : entryResumePoint_(current->entryResumePoint())
1714 : #endif
1715 : {
1716 : // The block is not yet jumping into a block of an inlined function yet.
1717 33 : MOZ_ASSERT(current->outerResumePoint_ == nullptr);
1718 33 : }
1719 :
1720 : bool
1721 33 : MBasicBlock::BackupPoint::init(TempAllocator& alloc)
1722 : {
1723 33 : if (!slots_.init(alloc, stackPosition_))
1724 0 : return false;
1725 406 : for (size_t i = 0, e = stackPosition_; i < e; ++i)
1726 373 : slots_[i] = current_->slots_[i];
1727 33 : return true;
1728 : }
1729 :
1730 : #ifdef DEBUG
1731 : uintptr_t
1732 33 : MBasicBlock::BackupPoint::computePredecessorsCheckSum(MBasicBlock* block)
1733 : {
1734 33 : uintptr_t hash = 0;
1735 65 : for (size_t i = 0; i < block->numPredecessors(); i++) {
1736 32 : MBasicBlock* pred = block->getPredecessor(i);
1737 32 : uintptr_t data = reinterpret_cast<uintptr_t>(pred);
1738 32 : hash = data + (hash << 6) + (hash << 16) - hash;
1739 : }
1740 33 : return hash;
1741 : }
1742 :
1743 : HashNumber
1744 33 : MBasicBlock::BackupPoint::computeInstructionsCheckSum(MBasicBlock* block)
1745 : {
1746 33 : HashNumber h = 0;
1747 33 : MOZ_ASSERT_IF(lastIns_, lastIns_->block() == block);
1748 204 : for (MInstructionIterator ins = block->begin(); ins != block->end(); ++ins) {
1749 171 : h += ins->valueHash();
1750 171 : h += h << 10;
1751 171 : h ^= h >> 6;
1752 : }
1753 33 : return h;
1754 : }
1755 : #endif
1756 :
1757 : MBasicBlock*
1758 0 : MBasicBlock::BackupPoint::restore()
1759 : {
1760 : // No extra Phi got added.
1761 0 : MOZ_ASSERT((!current_->phisEmpty() ? *current_->phis_.rbegin() : nullptr) == lastPhi_);
1762 :
1763 0 : MOZ_ASSERT_IF(lastIns_, lastIns_->block() == current_);
1764 0 : MOZ_ASSERT_IF(lastIns_, !lastIns_->isDiscarded());
1765 :
1766 0 : if (!current_->graph().removeSuccessorBlocks(current_))
1767 0 : return nullptr;
1768 :
1769 0 : MInstructionIterator lastIns(lastIns_ ? ++(current_->begin(lastIns_)) : current_->begin());
1770 0 : current_->discardAllInstructionsStartingAt(lastIns);
1771 0 : current_->clearOuterResumePoint();
1772 :
1773 0 : MOZ_ASSERT(current_->slots_.length() >= stackPosition_);
1774 0 : if (current_->stackPosition_ != stackPosition_)
1775 0 : current_->setStackDepth(stackPosition_);
1776 0 : for (size_t i = 0, e = stackPosition_; i < e; ++i)
1777 0 : current_->slots_[i] = slots_[i];
1778 :
1779 0 : MOZ_ASSERT(current_->id() == id_);
1780 0 : MOZ_ASSERT(predecessorsCheckSum_ == computePredecessorsCheckSum(current_));
1781 0 : MOZ_ASSERT(instructionsCheckSum_ == computeInstructionsCheckSum(current_));
1782 0 : MOZ_ASSERT(current_->callerResumePoint() == callerResumePoint_);
1783 0 : MOZ_ASSERT(current_->entryResumePoint() == entryResumePoint_);
1784 :
1785 0 : return current_;
1786 : }
1787 :
1788 : void
1789 0 : MBasicBlock::dumpStack(GenericPrinter& out)
1790 : {
1791 : #ifdef DEBUG
1792 0 : out.printf(" %-3s %-16s %-6s %-10s\n", "#", "name", "copyOf", "first/next");
1793 0 : out.printf("-------------------------------------------\n");
1794 0 : for (uint32_t i = 0; i < stackPosition_; i++) {
1795 0 : out.printf(" %-3d", i);
1796 0 : out.printf(" %-16p\n", (void*)slots_[i]);
1797 : }
1798 : #endif
1799 0 : }
1800 :
1801 : void
1802 0 : MBasicBlock::dumpStack()
1803 : {
1804 0 : Fprinter out(stderr);
1805 0 : dumpStack(out);
1806 0 : out.finish();
1807 0 : }
1808 :
1809 : void
1810 0 : MIRGraph::dump(GenericPrinter& out)
1811 : {
1812 : #ifdef DEBUG
1813 0 : for (MBasicBlockIterator iter(begin()); iter != end(); iter++) {
1814 0 : iter->dump(out);
1815 0 : out.printf("\n");
1816 : }
1817 : #endif
1818 0 : }
1819 :
1820 : void
1821 0 : MIRGraph::dump()
1822 : {
1823 0 : Fprinter out(stderr);
1824 0 : dump(out);
1825 0 : out.finish();
1826 0 : }
1827 :
1828 : void
1829 0 : MBasicBlock::dump(GenericPrinter& out)
1830 : {
1831 : #ifdef DEBUG
1832 0 : out.printf("block%u:%s%s%s\n", id(),
1833 0 : isLoopHeader() ? " (loop header)" : "",
1834 0 : unreachable() ? " (unreachable)" : "",
1835 0 : isMarked() ? " (marked)" : "");
1836 0 : if (MResumePoint* resume = entryResumePoint())
1837 0 : resume->dump(out);
1838 0 : for (MPhiIterator iter(phisBegin()); iter != phisEnd(); iter++)
1839 0 : iter->dump(out);
1840 0 : for (MInstructionIterator iter(begin()); iter != end(); iter++)
1841 0 : iter->dump(out);
1842 : #endif
1843 0 : }
1844 :
1845 : void
1846 0 : MBasicBlock::dump()
1847 : {
1848 0 : Fprinter out(stderr);
1849 0 : dump(out);
1850 0 : out.finish();
1851 0 : }
|