1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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/WarpBuilder.h"
8 
9 #include "mozilla/DebugOnly.h"
10 
11 #include "jit/BaselineFrame.h"
12 #include "jit/CacheIR.h"
13 #include "jit/CompileInfo.h"
14 #include "jit/InlineScriptTree.h"
15 #include "jit/MIR.h"
16 #include "jit/MIRGenerator.h"
17 #include "jit/MIRGraph.h"
18 #include "jit/WarpCacheIRTranspiler.h"
19 #include "jit/WarpSnapshot.h"
20 #include "js/friend/ErrorMessages.h"  // JSMSG_BAD_CONST_ASSIGN
21 #include "vm/GeneratorObject.h"
22 #include "vm/Opcodes.h"
23 
24 #include "gc/ObjectKind-inl.h"
25 #include "jit/JitScript-inl.h"
26 #include "vm/BytecodeIterator-inl.h"
27 #include "vm/BytecodeLocation-inl.h"
28 
29 using namespace js;
30 using namespace js::jit;
31 
32 // Used for building the outermost script.
WarpBuilder(WarpSnapshot & snapshot,MIRGenerator & mirGen,WarpCompilation * warpCompilation)33 WarpBuilder::WarpBuilder(WarpSnapshot& snapshot, MIRGenerator& mirGen,
34                          WarpCompilation* warpCompilation)
35     : WarpBuilderShared(snapshot, mirGen, nullptr),
36       warpCompilation_(warpCompilation),
37       graph_(mirGen.graph()),
38       info_(mirGen.outerInfo()),
39       scriptSnapshot_(snapshot.rootScript()),
40       script_(snapshot.rootScript()->script()),
41       loopStack_(mirGen.alloc()) {
42   opSnapshotIter_ = scriptSnapshot_->opSnapshots().getFirst();
43 }
44 
45 // Used for building inlined scripts.
WarpBuilder(WarpBuilder * caller,WarpScriptSnapshot * snapshot,CompileInfo & compileInfo,CallInfo * inlineCallInfo,MResumePoint * callerResumePoint)46 WarpBuilder::WarpBuilder(WarpBuilder* caller, WarpScriptSnapshot* snapshot,
47                          CompileInfo& compileInfo, CallInfo* inlineCallInfo,
48                          MResumePoint* callerResumePoint)
49     : WarpBuilderShared(caller->snapshot(), caller->mirGen(), nullptr),
50       warpCompilation_(caller->warpCompilation()),
51       graph_(caller->mirGen().graph()),
52       info_(compileInfo),
53       scriptSnapshot_(snapshot),
54       script_(snapshot->script()),
55       loopStack_(caller->mirGen().alloc()),
56       callerBuilder_(caller),
57       callerResumePoint_(callerResumePoint),
58       inlineCallInfo_(inlineCallInfo) {
59   opSnapshotIter_ = snapshot->opSnapshots().getFirst();
60 }
61 
newBytecodeSite(BytecodeLocation loc)62 BytecodeSite* WarpBuilder::newBytecodeSite(BytecodeLocation loc) {
63   jsbytecode* pc = loc.toRawBytecode();
64   MOZ_ASSERT(info().inlineScriptTree()->script()->containsPC(pc));
65   return new (alloc()) BytecodeSite(info().inlineScriptTree(), pc);
66 }
67 
getOpSnapshotImpl(BytecodeLocation loc,WarpOpSnapshot::Kind kind)68 const WarpOpSnapshot* WarpBuilder::getOpSnapshotImpl(
69     BytecodeLocation loc, WarpOpSnapshot::Kind kind) {
70   uint32_t offset = loc.bytecodeToOffset(script_);
71 
72   // Skip snapshots until we get to a snapshot with offset >= offset. This is
73   // a loop because WarpBuilder can skip unreachable bytecode ops.
74   while (opSnapshotIter_ && opSnapshotIter_->offset() < offset) {
75     opSnapshotIter_ = opSnapshotIter_->getNext();
76   }
77 
78   if (!opSnapshotIter_ || opSnapshotIter_->offset() != offset ||
79       opSnapshotIter_->kind() != kind) {
80     return nullptr;
81   }
82 
83   return opSnapshotIter_;
84 }
85 
initBlock(MBasicBlock * block)86 void WarpBuilder::initBlock(MBasicBlock* block) {
87   graph().addBlock(block);
88 
89   block->setLoopDepth(loopDepth());
90 
91   current = block;
92 }
93 
startNewBlock(MBasicBlock * predecessor,BytecodeLocation loc,size_t numToPop)94 bool WarpBuilder::startNewBlock(MBasicBlock* predecessor, BytecodeLocation loc,
95                                 size_t numToPop) {
96   MBasicBlock* block =
97       MBasicBlock::NewPopN(graph(), info(), predecessor, newBytecodeSite(loc),
98                            MBasicBlock::NORMAL, numToPop);
99   if (!block) {
100     return false;
101   }
102 
103   initBlock(block);
104   return true;
105 }
106 
startNewEntryBlock(size_t stackDepth,BytecodeLocation loc)107 bool WarpBuilder::startNewEntryBlock(size_t stackDepth, BytecodeLocation loc) {
108   MBasicBlock* block =
109       MBasicBlock::New(graph(), stackDepth, info(), /* maybePred = */ nullptr,
110                        newBytecodeSite(loc), MBasicBlock::NORMAL);
111   if (!block) {
112     return false;
113   }
114 
115   initBlock(block);
116   return true;
117 }
118 
startNewLoopHeaderBlock(BytecodeLocation loopHead)119 bool WarpBuilder::startNewLoopHeaderBlock(BytecodeLocation loopHead) {
120   MBasicBlock* header = MBasicBlock::NewPendingLoopHeader(
121       graph(), info(), current, newBytecodeSite(loopHead));
122   if (!header) {
123     return false;
124   }
125 
126   initBlock(header);
127   return loopStack_.emplaceBack(header);
128 }
129 
startNewOsrPreHeaderBlock(BytecodeLocation loopHead)130 bool WarpBuilder::startNewOsrPreHeaderBlock(BytecodeLocation loopHead) {
131   MOZ_ASSERT(loopHead.is(JSOp::LoopHead));
132   MOZ_ASSERT(loopHead.toRawBytecode() == info().osrPc());
133 
134   // Create two blocks:
135   // * The OSR entry block. This is always the graph's second block and has no
136   //   predecessors. This is the entry point for OSR from the Baseline JIT.
137   // * The OSR preheader block. This has two predecessors: the OSR entry block
138   //   and the current block.
139 
140   MBasicBlock* pred = current;
141 
142   // Create the OSR entry block.
143   if (!startNewEntryBlock(pred->stackDepth(), loopHead)) {
144     return false;
145   }
146 
147   MBasicBlock* osrBlock = current;
148   graph().setOsrBlock(osrBlock);
149   graph().moveBlockAfter(*graph().begin(), osrBlock);
150 
151   MOsrEntry* entry = MOsrEntry::New(alloc());
152   osrBlock->add(entry);
153 
154   // Initialize environment chain.
155   {
156     uint32_t slot = info().environmentChainSlot();
157     MInstruction* envv;
158     if (usesEnvironmentChain()) {
159       envv = MOsrEnvironmentChain::New(alloc(), entry);
160     } else {
161       // Use an undefined value if the script does not need its environment
162       // chain, to match the main entry point.
163       envv = MConstant::New(alloc(), UndefinedValue());
164     }
165     osrBlock->add(envv);
166     osrBlock->initSlot(slot, envv);
167   }
168 
169   // Initialize return value.
170   {
171     MInstruction* returnValue;
172     if (!script_->noScriptRval()) {
173       returnValue = MOsrReturnValue::New(alloc(), entry);
174     } else {
175       returnValue = MConstant::New(alloc(), UndefinedValue());
176     }
177     osrBlock->add(returnValue);
178     osrBlock->initSlot(info().returnValueSlot(), returnValue);
179   }
180 
181   // Initialize arguments object.
182   MInstruction* argsObj = nullptr;
183   if (info().needsArgsObj()) {
184     argsObj = MOsrArgumentsObject::New(alloc(), entry);
185     osrBlock->add(argsObj);
186     osrBlock->initSlot(info().argsObjSlot(), argsObj);
187   }
188 
189   if (info().funMaybeLazy()) {
190     // Initialize |this| parameter.
191     MParameter* thisv = MParameter::New(alloc(), MParameter::THIS_SLOT);
192     osrBlock->add(thisv);
193     osrBlock->initSlot(info().thisSlot(), thisv);
194 
195     // Initialize arguments. There are three cases:
196     //
197     // 1) There's no ArgumentsObject or it doesn't alias formals. In this case
198     //    we can just use the frame's argument slot.
199     // 2) The ArgumentsObject aliases formals and the argument is stored in the
200     //    CallObject. Use |undefined| because we can't load from the arguments
201     //    object and code will use the CallObject anyway.
202     // 3) The ArgumentsObject aliases formals and the argument isn't stored in
203     //    the CallObject. We have to load it from the ArgumentsObject.
204     for (uint32_t i = 0; i < info().nargs(); i++) {
205       uint32_t slot = info().argSlotUnchecked(i);
206       MInstruction* osrv;
207       if (!info().argsObjAliasesFormals()) {
208         osrv = MParameter::New(alloc().fallible(), i);
209       } else if (script_->formalIsAliased(i)) {
210         osrv = MConstant::New(alloc().fallible(), UndefinedValue());
211       } else {
212         osrv = MGetArgumentsObjectArg::New(alloc().fallible(), argsObj, i);
213       }
214       if (!osrv) {
215         return false;
216       }
217       current->add(osrv);
218       current->initSlot(slot, osrv);
219     }
220   }
221 
222   // Initialize locals.
223   uint32_t nlocals = info().nlocals();
224   for (uint32_t i = 0; i < nlocals; i++) {
225     uint32_t slot = info().localSlot(i);
226     ptrdiff_t offset = BaselineFrame::reverseOffsetOfLocal(i);
227     MOsrValue* osrv = MOsrValue::New(alloc().fallible(), entry, offset);
228     if (!osrv) {
229       return false;
230     }
231     current->add(osrv);
232     current->initSlot(slot, osrv);
233   }
234 
235   // Initialize expression stack slots.
236   uint32_t numStackSlots = current->stackDepth() - info().firstStackSlot();
237   for (uint32_t i = 0; i < numStackSlots; i++) {
238     uint32_t slot = info().stackSlot(i);
239     ptrdiff_t offset = BaselineFrame::reverseOffsetOfLocal(nlocals + i);
240     MOsrValue* osrv = MOsrValue::New(alloc().fallible(), entry, offset);
241     if (!osrv) {
242       return false;
243     }
244     current->add(osrv);
245     current->initSlot(slot, osrv);
246   }
247 
248   MStart* start = MStart::New(alloc());
249   current->add(start);
250 
251   // Note: phi specialization can add type guard instructions to the OSR entry
252   // block if needed. See TypeAnalyzer::shouldSpecializeOsrPhis.
253 
254   // Create the preheader block, with the predecessor block and OSR block as
255   // predecessors.
256   if (!startNewBlock(pred, loopHead)) {
257     return false;
258   }
259 
260   pred->end(MGoto::New(alloc(), current));
261   osrBlock->end(MGoto::New(alloc(), current));
262 
263   if (!current->addPredecessor(alloc(), osrBlock)) {
264     return false;
265   }
266 
267   return true;
268 }
269 
addPendingEdge(const PendingEdge & edge,BytecodeLocation target)270 bool WarpBuilder::addPendingEdge(const PendingEdge& edge,
271                                  BytecodeLocation target) {
272   jsbytecode* targetPC = target.toRawBytecode();
273   PendingEdgesMap::AddPtr p = pendingEdges_.lookupForAdd(targetPC);
274   if (p) {
275     return p->value().append(edge);
276   }
277 
278   PendingEdges edges;
279   static_assert(PendingEdges::InlineLength >= 1,
280                 "Appending one element should be infallible");
281   MOZ_ALWAYS_TRUE(edges.append(edge));
282 
283   return pendingEdges_.add(p, targetPC, std::move(edges));
284 }
285 
build()286 bool WarpBuilder::build() {
287   if (!buildPrologue()) {
288     return false;
289   }
290 
291   if (!buildBody()) {
292     return false;
293   }
294 
295   if (!MPhi::markIteratorPhis(*iterators())) {
296     return false;
297   }
298 
299   MOZ_ASSERT_IF(info().osrPc(), graph().osrBlock());
300   MOZ_ASSERT(loopStack_.empty());
301   MOZ_ASSERT(loopDepth() == 0);
302 
303   return true;
304 }
305 
buildInline()306 bool WarpBuilder::buildInline() {
307   if (!buildInlinePrologue()) {
308     return false;
309   }
310 
311   if (!buildBody()) {
312     return false;
313   }
314 
315   MOZ_ASSERT(loopStack_.empty());
316   return true;
317 }
318 
buildNamedLambdaEnv(MDefinition * callee,MDefinition * env,NamedLambdaObject * templateObj)319 MInstruction* WarpBuilder::buildNamedLambdaEnv(MDefinition* callee,
320                                                MDefinition* env,
321                                                NamedLambdaObject* templateObj) {
322   MOZ_ASSERT(!templateObj->hasDynamicSlots());
323 
324   MInstruction* namedLambda = MNewNamedLambdaObject::New(alloc(), templateObj);
325   current->add(namedLambda);
326 
327   // Initialize the object's reserved slots. No post barrier is needed here:
328   // the object will be allocated in the nursery if possible, and if the
329   // tenured heap is used instead, a minor collection will have been performed
330   // that moved env/callee to the tenured heap.
331   size_t enclosingSlot = NamedLambdaObject::enclosingEnvironmentSlot();
332   size_t lambdaSlot = NamedLambdaObject::lambdaSlot();
333   current->add(MStoreFixedSlot::NewUnbarriered(alloc(), namedLambda,
334                                                enclosingSlot, env));
335   current->add(MStoreFixedSlot::NewUnbarriered(alloc(), namedLambda, lambdaSlot,
336                                                callee));
337 
338   return namedLambda;
339 }
340 
buildCallObject(MDefinition * callee,MDefinition * env,CallObject * templateObj)341 MInstruction* WarpBuilder::buildCallObject(MDefinition* callee,
342                                            MDefinition* env,
343                                            CallObject* templateObj) {
344   MConstant* templateCst = constant(ObjectValue(*templateObj));
345 
346   MNewCallObject* callObj = MNewCallObject::New(alloc(), templateCst);
347   current->add(callObj);
348 
349   // Initialize the object's reserved slots. No post barrier is needed here,
350   // for the same reason as in buildNamedLambdaEnv.
351   size_t enclosingSlot = CallObject::enclosingEnvironmentSlot();
352   size_t calleeSlot = CallObject::calleeSlot();
353   current->add(
354       MStoreFixedSlot::NewUnbarriered(alloc(), callObj, enclosingSlot, env));
355   current->add(
356       MStoreFixedSlot::NewUnbarriered(alloc(), callObj, calleeSlot, callee));
357 
358   // Copy closed-over argument slots if there aren't parameter expressions.
359   MSlots* slots = nullptr;
360   for (PositionalFormalParameterIter fi(script_); fi; fi++) {
361     if (!fi.closedOver()) {
362       continue;
363     }
364 
365     if (!alloc().ensureBallast()) {
366       return nullptr;
367     }
368 
369     uint32_t slot = fi.location().slot();
370     uint32_t formal = fi.argumentSlot();
371     uint32_t numFixedSlots = templateObj->numFixedSlots();
372     MDefinition* param;
373     if (script_->functionHasParameterExprs()) {
374       param = constant(MagicValue(JS_UNINITIALIZED_LEXICAL));
375     } else {
376       param = current->getSlot(info().argSlotUnchecked(formal));
377     }
378 
379     if (slot >= numFixedSlots) {
380       if (!slots) {
381         slots = MSlots::New(alloc(), callObj);
382         current->add(slots);
383       }
384       uint32_t dynamicSlot = slot - numFixedSlots;
385       current->add(MStoreDynamicSlot::NewUnbarriered(alloc(), slots,
386                                                      dynamicSlot, param));
387     } else {
388       current->add(
389           MStoreFixedSlot::NewUnbarriered(alloc(), callObj, slot, param));
390     }
391   }
392 
393   return callObj;
394 }
395 
buildEnvironmentChain()396 bool WarpBuilder::buildEnvironmentChain() {
397   const WarpEnvironment& env = scriptSnapshot()->environment();
398 
399   if (env.is<NoEnvironment>()) {
400     return true;
401   }
402 
403   MInstruction* envDef = env.match(
404       [](const NoEnvironment&) -> MInstruction* {
405         MOZ_CRASH("Already handled");
406       },
407       [this](JSObject* obj) -> MInstruction* {
408         return constant(ObjectValue(*obj));
409       },
410       [this](const FunctionEnvironment& env) -> MInstruction* {
411         MDefinition* callee = getCallee();
412         MInstruction* envDef = MFunctionEnvironment::New(alloc(), callee);
413         current->add(envDef);
414         if (NamedLambdaObject* obj = env.namedLambdaTemplate) {
415           envDef = buildNamedLambdaEnv(callee, envDef, obj);
416         }
417         if (CallObject* obj = env.callObjectTemplate) {
418           envDef = buildCallObject(callee, envDef, obj);
419           if (!envDef) {
420             return nullptr;
421           }
422         }
423         return envDef;
424       });
425   if (!envDef) {
426     return false;
427   }
428 
429   // Update the environment slot from UndefinedValue only after the initial
430   // environment is created so that bailout doesn't see a partial environment.
431   // See: |BaselineStackBuilder::buildBaselineFrame|
432   current->setEnvironmentChain(envDef);
433   return true;
434 }
435 
buildPrologue()436 bool WarpBuilder::buildPrologue() {
437   BytecodeLocation startLoc(script_, script_->code());
438   if (!startNewEntryBlock(info().firstStackSlot(), startLoc)) {
439     return false;
440   }
441 
442   if (info().funMaybeLazy()) {
443     // Initialize |this|.
444     MParameter* param = MParameter::New(alloc(), MParameter::THIS_SLOT);
445     current->add(param);
446     current->initSlot(info().thisSlot(), param);
447 
448     // Initialize arguments.
449     for (uint32_t i = 0; i < info().nargs(); i++) {
450       MParameter* param = MParameter::New(alloc().fallible(), i);
451       if (!param) {
452         return false;
453       }
454       current->add(param);
455       current->initSlot(info().argSlotUnchecked(i), param);
456     }
457   }
458 
459   MConstant* undef = constant(UndefinedValue());
460 
461   // Initialize local slots.
462   for (uint32_t i = 0; i < info().nlocals(); i++) {
463     current->initSlot(info().localSlot(i), undef);
464   }
465 
466   // Initialize the environment chain, return value, and arguments object slots.
467   current->initSlot(info().environmentChainSlot(), undef);
468   current->initSlot(info().returnValueSlot(), undef);
469   if (info().needsArgsObj()) {
470     current->initSlot(info().argsObjSlot(), undef);
471   }
472 
473   current->add(MStart::New(alloc()));
474 
475   // Guard against over-recursion.
476   MCheckOverRecursed* check = MCheckOverRecursed::New(alloc());
477   current->add(check);
478 
479   if (!buildEnvironmentChain()) {
480     return false;
481   }
482 
483 #ifdef JS_CACHEIR_SPEW
484   if (snapshot().needsFinalWarmUpCount()) {
485     MIncrementWarmUpCounter* ins =
486         MIncrementWarmUpCounter::New(alloc(), script_);
487     current->add(ins);
488   }
489 #endif
490 
491   return true;
492 }
493 
buildInlinePrologue()494 bool WarpBuilder::buildInlinePrologue() {
495   // Generate entry block.
496   BytecodeLocation startLoc(script_, script_->code());
497   if (!startNewEntryBlock(info().firstStackSlot(), startLoc)) {
498     return false;
499   }
500   current->setCallerResumePoint(callerResumePoint());
501 
502   // Connect the entry block to the last block in the caller's graph.
503   MBasicBlock* pred = callerBuilder()->current;
504   MOZ_ASSERT(pred == callerResumePoint()->block());
505 
506   pred->end(MGoto::New(alloc(), current));
507   if (!current->addPredecessorWithoutPhis(pred)) {
508     return false;
509   }
510 
511   MConstant* undef = constant(UndefinedValue());
512 
513   // Initialize env chain slot to Undefined.  It's set later by
514   // |buildEnvironmentChain|.
515   current->initSlot(info().environmentChainSlot(), undef);
516 
517   // Initialize |return value| slot.
518   current->initSlot(info().returnValueSlot(), undef);
519 
520   // Initialize |arguments| slot if needed.
521   if (info().needsArgsObj()) {
522     current->initSlot(info().argsObjSlot(), undef);
523   }
524 
525   // Initialize |this| slot.
526   current->initSlot(info().thisSlot(), inlineCallInfo()->thisArg());
527 
528   uint32_t callerArgs = inlineCallInfo()->argc();
529   uint32_t actualArgs = info().nargs();
530   uint32_t passedArgs = std::min<uint32_t>(callerArgs, actualArgs);
531 
532   // Initialize actually set arguments.
533   for (uint32_t i = 0; i < passedArgs; i++) {
534     MDefinition* arg = inlineCallInfo()->getArg(i);
535     current->initSlot(info().argSlotUnchecked(i), arg);
536   }
537 
538   // Pass undefined for missing arguments.
539   for (uint32_t i = passedArgs; i < actualArgs; i++) {
540     current->initSlot(info().argSlotUnchecked(i), undef);
541   }
542 
543   // Initialize local slots.
544   for (uint32_t i = 0; i < info().nlocals(); i++) {
545     current->initSlot(info().localSlot(i), undef);
546   }
547 
548   MOZ_ASSERT(current->entryResumePoint()->stackDepth() == info().totalSlots());
549 
550   if (!buildEnvironmentChain()) {
551     return false;
552   }
553 
554   return true;
555 }
556 
557 #ifdef DEBUG
558 // In debug builds, after compiling a bytecode op, this class is used to check
559 // that all values popped by this opcode either:
560 //
561 //   (1) Have the ImplicitlyUsed flag set on them.
562 //   (2) Have more uses than before compiling this op (the value is
563 //       used as operand of a new MIR instruction).
564 //
565 // This is used to catch problems where WarpBuilder pops a value without
566 // adding any SSA uses and doesn't call setImplicitlyUsedUnchecked on it.
567 class MOZ_RAII WarpPoppedValueUseChecker {
568   Vector<MDefinition*, 4, SystemAllocPolicy> popped_;
569   Vector<size_t, 4, SystemAllocPolicy> poppedUses_;
570   MBasicBlock* current_;
571   BytecodeLocation loc_;
572 
573  public:
WarpPoppedValueUseChecker(MBasicBlock * current,BytecodeLocation loc)574   WarpPoppedValueUseChecker(MBasicBlock* current, BytecodeLocation loc)
575       : current_(current), loc_(loc) {}
576 
init()577   [[nodiscard]] bool init() {
578     // Don't require SSA uses for values popped by these ops.
579     switch (loc_.getOp()) {
580       case JSOp::Pop:
581       case JSOp::PopN:
582       case JSOp::DupAt:
583       case JSOp::Dup:
584       case JSOp::Dup2:
585       case JSOp::Pick:
586       case JSOp::Unpick:
587       case JSOp::Swap:
588       case JSOp::SetArg:
589       case JSOp::SetLocal:
590       case JSOp::InitLexical:
591       case JSOp::SetRval:
592       case JSOp::Void:
593         // Basic stack/local/argument management opcodes.
594         return true;
595 
596       case JSOp::Case:
597       case JSOp::Default:
598         // These ops have to pop the switch value when branching but don't
599         // actually use it.
600         return true;
601 
602       default:
603         break;
604     }
605 
606     unsigned nuses = loc_.useCount();
607 
608     for (unsigned i = 0; i < nuses; i++) {
609       MDefinition* def = current_->peek(-int32_t(i + 1));
610       if (!popped_.append(def) || !poppedUses_.append(def->defUseCount())) {
611         return false;
612       }
613     }
614 
615     return true;
616   }
617 
checkAfterOp()618   void checkAfterOp() {
619     for (size_t i = 0; i < popped_.length(); i++) {
620       // First value popped by JSOp::EndIter is not used at all, it's similar
621       // to JSOp::Pop above.
622       if (loc_.is(JSOp::EndIter) && i == 0) {
623         continue;
624       }
625       MOZ_ASSERT(popped_[i]->isImplicitlyUsed() ||
626                  popped_[i]->defUseCount() > poppedUses_[i]);
627     }
628   }
629 };
630 #endif
631 
buildBody()632 bool WarpBuilder::buildBody() {
633   for (BytecodeLocation loc : AllBytecodesIterable(script_)) {
634     if (mirGen().shouldCancel("WarpBuilder (opcode loop)")) {
635       return false;
636     }
637 
638     // Skip unreachable ops (for example code after a 'return' or 'throw') until
639     // we get to the next jump target.
640     if (hasTerminatedBlock()) {
641       // Finish any "broken" loops with an unreachable backedge. For example:
642       //
643       //   do {
644       //     ...
645       //     return;
646       //     ...
647       //   } while (x);
648       //
649       // This loop never actually loops.
650       if (loc.isBackedge() && !loopStack_.empty()) {
651         BytecodeLocation loopHead(script_, loopStack_.back().header()->pc());
652         if (loc.isBackedgeForLoophead(loopHead)) {
653           decLoopDepth();
654           loopStack_.popBack();
655         }
656       }
657       if (!loc.isJumpTarget()) {
658         continue;
659       }
660     }
661 
662     if (!alloc().ensureBallast()) {
663       return false;
664     }
665 
666 #ifdef DEBUG
667     WarpPoppedValueUseChecker useChecker(current, loc);
668     if (!useChecker.init()) {
669       return false;
670     }
671 #endif
672 
673     JSOp op = loc.getOp();
674 
675 #define BUILD_OP(OP, ...)                       \
676   case JSOp::OP:                                \
677     if (MOZ_UNLIKELY(!this->build_##OP(loc))) { \
678       return false;                             \
679     }                                           \
680     break;
681     switch (op) { FOR_EACH_OPCODE(BUILD_OP) }
682 #undef BUILD_OP
683 
684 #ifdef DEBUG
685     useChecker.checkAfterOp();
686 #endif
687   }
688 
689   return true;
690 }
691 
692 #define DEF_OP(OP)                                 \
693   bool WarpBuilder::build_##OP(BytecodeLocation) { \
694     MOZ_CRASH("Unsupported op");                   \
695   }
WARP_UNSUPPORTED_OPCODE_LIST(DEF_OP)696 WARP_UNSUPPORTED_OPCODE_LIST(DEF_OP)
697 #undef DEF_OP
698 
699 bool WarpBuilder::build_Nop(BytecodeLocation) { return true; }
700 
build_NopDestructuring(BytecodeLocation)701 bool WarpBuilder::build_NopDestructuring(BytecodeLocation) { return true; }
702 
build_TryDestructuring(BytecodeLocation)703 bool WarpBuilder::build_TryDestructuring(BytecodeLocation) {
704   // Set the hasTryBlock flag to turn off optimizations that eliminate dead
705   // resume points operands because the exception handler code for
706   // TryNoteKind::Destructuring is effectively a (specialized) catch-block.
707   graph().setHasTryBlock();
708   return true;
709 }
710 
build_Lineno(BytecodeLocation)711 bool WarpBuilder::build_Lineno(BytecodeLocation) { return true; }
712 
build_DebugLeaveLexicalEnv(BytecodeLocation)713 bool WarpBuilder::build_DebugLeaveLexicalEnv(BytecodeLocation) { return true; }
714 
build_Undefined(BytecodeLocation)715 bool WarpBuilder::build_Undefined(BytecodeLocation) {
716   pushConstant(UndefinedValue());
717   return true;
718 }
719 
build_Void(BytecodeLocation)720 bool WarpBuilder::build_Void(BytecodeLocation) {
721   current->pop();
722   pushConstant(UndefinedValue());
723   return true;
724 }
725 
build_Null(BytecodeLocation)726 bool WarpBuilder::build_Null(BytecodeLocation) {
727   pushConstant(NullValue());
728   return true;
729 }
730 
build_Hole(BytecodeLocation)731 bool WarpBuilder::build_Hole(BytecodeLocation) {
732   pushConstant(MagicValue(JS_ELEMENTS_HOLE));
733   return true;
734 }
735 
build_Uninitialized(BytecodeLocation)736 bool WarpBuilder::build_Uninitialized(BytecodeLocation) {
737   pushConstant(MagicValue(JS_UNINITIALIZED_LEXICAL));
738   return true;
739 }
740 
build_IsConstructing(BytecodeLocation)741 bool WarpBuilder::build_IsConstructing(BytecodeLocation) {
742   pushConstant(MagicValue(JS_IS_CONSTRUCTING));
743   return true;
744 }
745 
build_False(BytecodeLocation)746 bool WarpBuilder::build_False(BytecodeLocation) {
747   pushConstant(BooleanValue(false));
748   return true;
749 }
750 
build_True(BytecodeLocation)751 bool WarpBuilder::build_True(BytecodeLocation) {
752   pushConstant(BooleanValue(true));
753   return true;
754 }
755 
build_Pop(BytecodeLocation)756 bool WarpBuilder::build_Pop(BytecodeLocation) {
757   current->pop();
758   return true;
759 }
760 
build_PopN(BytecodeLocation loc)761 bool WarpBuilder::build_PopN(BytecodeLocation loc) {
762   for (uint32_t i = 0, n = loc.getPopCount(); i < n; i++) {
763     current->pop();
764   }
765   return true;
766 }
767 
build_Dup(BytecodeLocation)768 bool WarpBuilder::build_Dup(BytecodeLocation) {
769   current->pushSlot(current->stackDepth() - 1);
770   return true;
771 }
772 
build_Dup2(BytecodeLocation)773 bool WarpBuilder::build_Dup2(BytecodeLocation) {
774   uint32_t lhsSlot = current->stackDepth() - 2;
775   uint32_t rhsSlot = current->stackDepth() - 1;
776   current->pushSlot(lhsSlot);
777   current->pushSlot(rhsSlot);
778   return true;
779 }
780 
build_DupAt(BytecodeLocation loc)781 bool WarpBuilder::build_DupAt(BytecodeLocation loc) {
782   current->pushSlot(current->stackDepth() - 1 - loc.getDupAtIndex());
783   return true;
784 }
785 
build_Swap(BytecodeLocation)786 bool WarpBuilder::build_Swap(BytecodeLocation) {
787   current->swapAt(-1);
788   return true;
789 }
790 
build_Pick(BytecodeLocation loc)791 bool WarpBuilder::build_Pick(BytecodeLocation loc) {
792   int32_t depth = -int32_t(loc.getPickDepth());
793   current->pick(depth);
794   return true;
795 }
796 
build_Unpick(BytecodeLocation loc)797 bool WarpBuilder::build_Unpick(BytecodeLocation loc) {
798   int32_t depth = -int32_t(loc.getUnpickDepth());
799   current->unpick(depth);
800   return true;
801 }
802 
build_Zero(BytecodeLocation)803 bool WarpBuilder::build_Zero(BytecodeLocation) {
804   pushConstant(Int32Value(0));
805   return true;
806 }
807 
build_One(BytecodeLocation)808 bool WarpBuilder::build_One(BytecodeLocation) {
809   pushConstant(Int32Value(1));
810   return true;
811 }
812 
build_Int8(BytecodeLocation loc)813 bool WarpBuilder::build_Int8(BytecodeLocation loc) {
814   pushConstant(Int32Value(loc.getInt8()));
815   return true;
816 }
817 
build_Uint16(BytecodeLocation loc)818 bool WarpBuilder::build_Uint16(BytecodeLocation loc) {
819   pushConstant(Int32Value(loc.getUint16()));
820   return true;
821 }
822 
build_Uint24(BytecodeLocation loc)823 bool WarpBuilder::build_Uint24(BytecodeLocation loc) {
824   pushConstant(Int32Value(loc.getUint24()));
825   return true;
826 }
827 
build_Int32(BytecodeLocation loc)828 bool WarpBuilder::build_Int32(BytecodeLocation loc) {
829   pushConstant(Int32Value(loc.getInt32()));
830   return true;
831 }
832 
build_Double(BytecodeLocation loc)833 bool WarpBuilder::build_Double(BytecodeLocation loc) {
834   pushConstant(loc.getInlineValue());
835   return true;
836 }
837 
build_ResumeIndex(BytecodeLocation loc)838 bool WarpBuilder::build_ResumeIndex(BytecodeLocation loc) {
839   pushConstant(Int32Value(loc.getResumeIndex()));
840   return true;
841 }
842 
build_BigInt(BytecodeLocation loc)843 bool WarpBuilder::build_BigInt(BytecodeLocation loc) {
844   BigInt* bi = loc.getBigInt(script_);
845   pushConstant(BigIntValue(bi));
846   return true;
847 }
848 
build_String(BytecodeLocation loc)849 bool WarpBuilder::build_String(BytecodeLocation loc) {
850   JSAtom* atom = loc.getAtom(script_);
851   pushConstant(StringValue(atom));
852   return true;
853 }
854 
build_Symbol(BytecodeLocation loc)855 bool WarpBuilder::build_Symbol(BytecodeLocation loc) {
856   uint32_t which = loc.getSymbolIndex();
857   JS::Symbol* sym = mirGen().runtime->wellKnownSymbols().get(which);
858   pushConstant(SymbolValue(sym));
859   return true;
860 }
861 
build_RegExp(BytecodeLocation loc)862 bool WarpBuilder::build_RegExp(BytecodeLocation loc) {
863   RegExpObject* reObj = loc.getRegExp(script_);
864 
865   auto* snapshot = getOpSnapshot<WarpRegExp>(loc);
866 
867   MRegExp* regexp = MRegExp::New(alloc(), reObj, snapshot->hasShared());
868   current->add(regexp);
869   current->push(regexp);
870 
871   return true;
872 }
873 
build_Return(BytecodeLocation)874 bool WarpBuilder::build_Return(BytecodeLocation) {
875   MDefinition* def = current->pop();
876 
877   MReturn* ret = MReturn::New(alloc(), def);
878   current->end(ret);
879 
880   if (!graph().addReturn(current)) {
881     return false;
882   }
883 
884   setTerminatedBlock();
885   return true;
886 }
887 
build_RetRval(BytecodeLocation)888 bool WarpBuilder::build_RetRval(BytecodeLocation) {
889   MDefinition* rval;
890   if (script_->noScriptRval()) {
891     rval = constant(UndefinedValue());
892   } else {
893     rval = current->getSlot(info().returnValueSlot());
894   }
895 
896   MReturn* ret = MReturn::New(alloc(), rval);
897   current->end(ret);
898 
899   if (!graph().addReturn(current)) {
900     return false;
901   }
902 
903   setTerminatedBlock();
904   return true;
905 }
906 
build_SetRval(BytecodeLocation)907 bool WarpBuilder::build_SetRval(BytecodeLocation) {
908   MOZ_ASSERT(!script_->noScriptRval());
909 
910   MDefinition* rval = current->pop();
911   current->setSlot(info().returnValueSlot(), rval);
912   return true;
913 }
914 
build_GetRval(BytecodeLocation)915 bool WarpBuilder::build_GetRval(BytecodeLocation) {
916   MOZ_ASSERT(!script_->noScriptRval());
917   MDefinition* rval = current->getSlot(info().returnValueSlot());
918   current->push(rval);
919   return true;
920 }
921 
build_GetLocal(BytecodeLocation loc)922 bool WarpBuilder::build_GetLocal(BytecodeLocation loc) {
923   current->pushLocal(loc.local());
924   return true;
925 }
926 
build_SetLocal(BytecodeLocation loc)927 bool WarpBuilder::build_SetLocal(BytecodeLocation loc) {
928   current->setLocal(loc.local());
929   return true;
930 }
931 
build_InitLexical(BytecodeLocation loc)932 bool WarpBuilder::build_InitLexical(BytecodeLocation loc) {
933   current->setLocal(loc.local());
934   return true;
935 }
936 
build_GetArg(BytecodeLocation loc)937 bool WarpBuilder::build_GetArg(BytecodeLocation loc) {
938   uint32_t arg = loc.arg();
939   if (info().argsObjAliasesFormals()) {
940     MDefinition* argsObj = current->argumentsObject();
941     auto* getArg = MGetArgumentsObjectArg::New(alloc(), argsObj, arg);
942     current->add(getArg);
943     current->push(getArg);
944   } else {
945     current->pushArg(arg);
946   }
947   return true;
948 }
949 
build_SetArg(BytecodeLocation loc)950 bool WarpBuilder::build_SetArg(BytecodeLocation loc) {
951   MOZ_ASSERT(script_->jitScript()->modifiesArguments());
952 
953   uint32_t arg = loc.arg();
954   MDefinition* val = current->peek(-1);
955 
956   if (!info().argsObjAliasesFormals()) {
957     // Either |arguments| is never referenced within this function, or
958     // it doesn't map to the actual arguments values. Either way, we
959     // don't need to worry about synchronizing the argument values
960     // when writing to them.
961     current->setArg(arg);
962     return true;
963   }
964 
965   // If an arguments object is in use, and it aliases formals, then all SetArgs
966   // must go through the arguments object.
967   MDefinition* argsObj = current->argumentsObject();
968   current->add(MPostWriteBarrier::New(alloc(), argsObj, val));
969   auto* ins = MSetArgumentsObjectArg::New(alloc(), argsObj, val, arg);
970   current->add(ins);
971   return resumeAfter(ins, loc);
972 }
973 
build_ToNumeric(BytecodeLocation loc)974 bool WarpBuilder::build_ToNumeric(BytecodeLocation loc) {
975   return buildUnaryOp(loc);
976 }
977 
buildUnaryOp(BytecodeLocation loc)978 bool WarpBuilder::buildUnaryOp(BytecodeLocation loc) {
979   MDefinition* value = current->pop();
980   return buildIC(loc, CacheKind::UnaryArith, {value});
981 }
982 
build_Inc(BytecodeLocation loc)983 bool WarpBuilder::build_Inc(BytecodeLocation loc) { return buildUnaryOp(loc); }
984 
build_Dec(BytecodeLocation loc)985 bool WarpBuilder::build_Dec(BytecodeLocation loc) { return buildUnaryOp(loc); }
986 
build_Pos(BytecodeLocation loc)987 bool WarpBuilder::build_Pos(BytecodeLocation loc) { return buildUnaryOp(loc); }
988 
build_Neg(BytecodeLocation loc)989 bool WarpBuilder::build_Neg(BytecodeLocation loc) { return buildUnaryOp(loc); }
990 
build_BitNot(BytecodeLocation loc)991 bool WarpBuilder::build_BitNot(BytecodeLocation loc) {
992   return buildUnaryOp(loc);
993 }
994 
buildBinaryOp(BytecodeLocation loc)995 bool WarpBuilder::buildBinaryOp(BytecodeLocation loc) {
996   MDefinition* right = current->pop();
997   MDefinition* left = current->pop();
998   return buildIC(loc, CacheKind::BinaryArith, {left, right});
999 }
1000 
build_Add(BytecodeLocation loc)1001 bool WarpBuilder::build_Add(BytecodeLocation loc) { return buildBinaryOp(loc); }
1002 
build_Sub(BytecodeLocation loc)1003 bool WarpBuilder::build_Sub(BytecodeLocation loc) { return buildBinaryOp(loc); }
1004 
build_Mul(BytecodeLocation loc)1005 bool WarpBuilder::build_Mul(BytecodeLocation loc) { return buildBinaryOp(loc); }
1006 
build_Div(BytecodeLocation loc)1007 bool WarpBuilder::build_Div(BytecodeLocation loc) { return buildBinaryOp(loc); }
1008 
build_Mod(BytecodeLocation loc)1009 bool WarpBuilder::build_Mod(BytecodeLocation loc) { return buildBinaryOp(loc); }
1010 
build_Pow(BytecodeLocation loc)1011 bool WarpBuilder::build_Pow(BytecodeLocation loc) { return buildBinaryOp(loc); }
1012 
build_BitAnd(BytecodeLocation loc)1013 bool WarpBuilder::build_BitAnd(BytecodeLocation loc) {
1014   return buildBinaryOp(loc);
1015 }
1016 
build_BitOr(BytecodeLocation loc)1017 bool WarpBuilder::build_BitOr(BytecodeLocation loc) {
1018   return buildBinaryOp(loc);
1019 }
1020 
build_BitXor(BytecodeLocation loc)1021 bool WarpBuilder::build_BitXor(BytecodeLocation loc) {
1022   return buildBinaryOp(loc);
1023 }
1024 
build_Lsh(BytecodeLocation loc)1025 bool WarpBuilder::build_Lsh(BytecodeLocation loc) { return buildBinaryOp(loc); }
1026 
build_Rsh(BytecodeLocation loc)1027 bool WarpBuilder::build_Rsh(BytecodeLocation loc) { return buildBinaryOp(loc); }
1028 
build_Ursh(BytecodeLocation loc)1029 bool WarpBuilder::build_Ursh(BytecodeLocation loc) {
1030   return buildBinaryOp(loc);
1031 }
1032 
buildCompareOp(BytecodeLocation loc)1033 bool WarpBuilder::buildCompareOp(BytecodeLocation loc) {
1034   MDefinition* right = current->pop();
1035   MDefinition* left = current->pop();
1036   return buildIC(loc, CacheKind::Compare, {left, right});
1037 }
1038 
build_Eq(BytecodeLocation loc)1039 bool WarpBuilder::build_Eq(BytecodeLocation loc) { return buildCompareOp(loc); }
1040 
build_Ne(BytecodeLocation loc)1041 bool WarpBuilder::build_Ne(BytecodeLocation loc) { return buildCompareOp(loc); }
1042 
build_Lt(BytecodeLocation loc)1043 bool WarpBuilder::build_Lt(BytecodeLocation loc) { return buildCompareOp(loc); }
1044 
build_Le(BytecodeLocation loc)1045 bool WarpBuilder::build_Le(BytecodeLocation loc) { return buildCompareOp(loc); }
1046 
build_Gt(BytecodeLocation loc)1047 bool WarpBuilder::build_Gt(BytecodeLocation loc) { return buildCompareOp(loc); }
1048 
build_Ge(BytecodeLocation loc)1049 bool WarpBuilder::build_Ge(BytecodeLocation loc) { return buildCompareOp(loc); }
1050 
build_StrictEq(BytecodeLocation loc)1051 bool WarpBuilder::build_StrictEq(BytecodeLocation loc) {
1052   return buildCompareOp(loc);
1053 }
1054 
build_StrictNe(BytecodeLocation loc)1055 bool WarpBuilder::build_StrictNe(BytecodeLocation loc) {
1056   return buildCompareOp(loc);
1057 }
1058 
1059 // Returns true iff the MTest added for |op| has a true-target corresponding
1060 // with the join point in the bytecode.
TestTrueTargetIsJoinPoint(JSOp op)1061 static bool TestTrueTargetIsJoinPoint(JSOp op) {
1062   switch (op) {
1063     case JSOp::JumpIfTrue:
1064     case JSOp::Or:
1065     case JSOp::Case:
1066       return true;
1067 
1068     case JSOp::JumpIfFalse:
1069     case JSOp::And:
1070     case JSOp::Coalesce:
1071       return false;
1072 
1073     default:
1074       MOZ_CRASH("Unexpected op");
1075   }
1076 }
1077 
build_JumpTarget(BytecodeLocation loc)1078 bool WarpBuilder::build_JumpTarget(BytecodeLocation loc) {
1079   PendingEdgesMap::Ptr p = pendingEdges_.lookup(loc.toRawBytecode());
1080   if (!p) {
1081     // No (reachable) jumps so this is just a no-op.
1082     return true;
1083   }
1084 
1085   PendingEdges edges(std::move(p->value()));
1086   pendingEdges_.remove(p);
1087 
1088   MOZ_ASSERT(!edges.empty());
1089 
1090   MBasicBlock* joinBlock = nullptr;
1091 
1092   // Create join block if there's fall-through from the previous bytecode op.
1093   if (!hasTerminatedBlock()) {
1094     MBasicBlock* pred = current;
1095     if (!startNewBlock(pred, loc)) {
1096       return false;
1097     }
1098     pred->end(MGoto::New(alloc(), current));
1099     joinBlock = current;
1100     setTerminatedBlock();
1101   }
1102 
1103   auto addEdge = [&](MBasicBlock* pred, size_t numToPop) -> bool {
1104     if (joinBlock) {
1105       MOZ_ASSERT(pred->stackDepth() - numToPop == joinBlock->stackDepth());
1106       return joinBlock->addPredecessorPopN(alloc(), pred, numToPop);
1107     }
1108     if (!startNewBlock(pred, loc, numToPop)) {
1109       return false;
1110     }
1111     joinBlock = current;
1112     setTerminatedBlock();
1113     return true;
1114   };
1115 
1116   // When a block is terminated with an MTest instruction we can end up with the
1117   // following triangle structure:
1118   //
1119   //        testBlock
1120   //         /    |
1121   //     block    |
1122   //         \    |
1123   //        joinBlock
1124   //
1125   // Although this is fine for correctness, the FoldTests pass is unable to
1126   // optimize this pattern. This matters for short-circuit operations
1127   // (JSOp::And, JSOp::Coalesce, etc).
1128   //
1129   // To fix these issues, we create an empty block to get a diamond structure:
1130   //
1131   //        testBlock
1132   //         /    |
1133   //     block  emptyBlock
1134   //         \    |
1135   //        joinBlock
1136   //
1137   // TODO(post-Warp): re-evaluate this. It would probably be better to fix
1138   // FoldTests to support the triangle pattern so that we can remove this.
1139   // IonBuilder had other concerns that don't apply to WarpBuilder.
1140   auto createEmptyBlockForTest = [&](MBasicBlock* pred, size_t successor,
1141                                      size_t numToPop) -> MBasicBlock* {
1142     MOZ_ASSERT(joinBlock);
1143 
1144     if (!startNewBlock(pred, loc, numToPop)) {
1145       return nullptr;
1146     }
1147 
1148     MBasicBlock* emptyBlock = current;
1149     MOZ_ASSERT(emptyBlock->stackDepth() == joinBlock->stackDepth());
1150 
1151     MTest* test = pred->lastIns()->toTest();
1152     test->initSuccessor(successor, emptyBlock);
1153 
1154     emptyBlock->end(MGoto::New(alloc(), joinBlock));
1155     setTerminatedBlock();
1156 
1157     return emptyBlock;
1158   };
1159 
1160   for (const PendingEdge& edge : edges) {
1161     MBasicBlock* source = edge.block();
1162     MControlInstruction* lastIns = source->lastIns();
1163     switch (edge.kind()) {
1164       case PendingEdge::Kind::TestTrue: {
1165         // JSOp::Case must pop the value when branching to the true-target.
1166         // If we create an empty block, we have to pop the value there instead
1167         // of as part of the emptyBlock -> joinBlock edge so stack depths match
1168         // the current depth.
1169         const size_t numToPop = (edge.testOp() == JSOp::Case) ? 1 : 0;
1170 
1171         const size_t successor = 0;  // true-branch
1172         if (joinBlock && TestTrueTargetIsJoinPoint(edge.testOp())) {
1173           MBasicBlock* pred =
1174               createEmptyBlockForTest(source, successor, numToPop);
1175           if (!pred || !addEdge(pred, /* numToPop = */ 0)) {
1176             return false;
1177           }
1178         } else {
1179           if (!addEdge(source, numToPop)) {
1180             return false;
1181           }
1182           lastIns->toTest()->initSuccessor(successor, joinBlock);
1183         }
1184         continue;
1185       }
1186 
1187       case PendingEdge::Kind::TestFalse: {
1188         const size_t numToPop = 0;
1189         const size_t successor = 1;  // false-branch
1190         if (joinBlock && !TestTrueTargetIsJoinPoint(edge.testOp())) {
1191           MBasicBlock* pred =
1192               createEmptyBlockForTest(source, successor, numToPop);
1193           if (!pred || !addEdge(pred, /* numToPop = */ 0)) {
1194             return false;
1195           }
1196         } else {
1197           if (!addEdge(source, numToPop)) {
1198             return false;
1199           }
1200           lastIns->toTest()->initSuccessor(successor, joinBlock);
1201         }
1202         continue;
1203       }
1204 
1205       case PendingEdge::Kind::Goto:
1206         if (!addEdge(source, /* numToPop = */ 0)) {
1207           return false;
1208         }
1209         lastIns->toGoto()->initSuccessor(0, joinBlock);
1210         continue;
1211     }
1212     MOZ_CRASH("Invalid kind");
1213   }
1214 
1215   // Start traversing the join block. Make sure it comes after predecessor
1216   // blocks created by createEmptyBlockForTest.
1217   MOZ_ASSERT(hasTerminatedBlock());
1218   MOZ_ASSERT(joinBlock);
1219   graph().moveBlockToEnd(joinBlock);
1220   current = joinBlock;
1221 
1222   return true;
1223 }
1224 
addIteratorLoopPhis(BytecodeLocation loopHead)1225 bool WarpBuilder::addIteratorLoopPhis(BytecodeLocation loopHead) {
1226   // When unwinding the stack for a thrown exception, the exception handler must
1227   // close live iterators. For ForIn and Destructuring loops, the exception
1228   // handler needs access to values on the stack. To prevent them from being
1229   // optimized away (and replaced with the JS_OPTIMIZED_OUT MagicValue), we need
1230   // to mark the phis (and phis they flow into) as having implicit uses.
1231   // See ProcessTryNotes in vm/Interpreter.cpp and CloseLiveIteratorIon in
1232   // jit/JitFrames.cpp
1233 
1234   MOZ_ASSERT(current->stackDepth() >= info().firstStackSlot());
1235 
1236   bool emptyStack = current->stackDepth() == info().firstStackSlot();
1237   if (emptyStack) {
1238     return true;
1239   }
1240 
1241   jsbytecode* loopHeadPC = loopHead.toRawBytecode();
1242 
1243   for (TryNoteIterAllNoGC tni(script_, loopHeadPC); !tni.done(); ++tni) {
1244     const TryNote& tn = **tni;
1245 
1246     // Stop if we reach an outer loop because outer loops were already
1247     // processed when we visited their loop headers.
1248     if (tn.isLoop()) {
1249       BytecodeLocation tnStart = script_->offsetToLocation(tn.start);
1250       if (tnStart != loopHead) {
1251         MOZ_ASSERT(tnStart.is(JSOp::LoopHead));
1252         MOZ_ASSERT(tnStart < loopHead);
1253         return true;
1254       }
1255     }
1256 
1257     switch (tn.kind()) {
1258       case TryNoteKind::Destructuring:
1259       case TryNoteKind::ForIn: {
1260         // For for-in loops we add the iterator object to iterators(). For
1261         // destructuring loops we add the "done" value that's on top of the
1262         // stack and used in the exception handler.
1263         MOZ_ASSERT(tn.stackDepth >= 1);
1264         uint32_t slot = info().stackSlot(tn.stackDepth - 1);
1265         MPhi* phi = current->getSlot(slot)->toPhi();
1266         if (!iterators()->append(phi)) {
1267           return false;
1268         }
1269         break;
1270       }
1271       case TryNoteKind::Loop:
1272       case TryNoteKind::ForOf:
1273         // Regular loops do not have iterators to close. ForOf loops handle
1274         // unwinding using catch blocks.
1275         break;
1276       default:
1277         break;
1278     }
1279   }
1280 
1281   return true;
1282 }
1283 
build_LoopHead(BytecodeLocation loc)1284 bool WarpBuilder::build_LoopHead(BytecodeLocation loc) {
1285   // All loops have the following bytecode structure:
1286   //
1287   //    LoopHead
1288   //    ...
1289   //    JumpIfTrue/Goto to LoopHead
1290 
1291   if (hasTerminatedBlock()) {
1292     // The whole loop is unreachable.
1293     return true;
1294   }
1295 
1296   // Handle OSR from Baseline JIT code.
1297   if (loc.toRawBytecode() == info().osrPc()) {
1298     if (!startNewOsrPreHeaderBlock(loc)) {
1299       return false;
1300     }
1301   }
1302 
1303   incLoopDepth();
1304 
1305   MBasicBlock* pred = current;
1306   if (!startNewLoopHeaderBlock(loc)) {
1307     return false;
1308   }
1309 
1310   pred->end(MGoto::New(alloc(), current));
1311 
1312   if (!addIteratorLoopPhis(loc)) {
1313     return false;
1314   }
1315 
1316   MInterruptCheck* check = MInterruptCheck::New(alloc());
1317   current->add(check);
1318 
1319 #ifdef JS_CACHEIR_SPEW
1320   if (snapshot().needsFinalWarmUpCount()) {
1321     MIncrementWarmUpCounter* ins =
1322         MIncrementWarmUpCounter::New(alloc(), script_);
1323     current->add(ins);
1324   }
1325 #endif
1326 
1327   return true;
1328 }
1329 
buildTestOp(BytecodeLocation loc)1330 bool WarpBuilder::buildTestOp(BytecodeLocation loc) {
1331   MDefinition* originalValue = current->peek(-1);
1332 
1333   if (auto* cacheIRSnapshot = getOpSnapshot<WarpCacheIR>(loc)) {
1334     // If we have CacheIR, we can use it to refine the input. Note that
1335     // the transpiler doesn't generate any control instructions. Instead,
1336     // we fall through and generate them below.
1337     MDefinition* value = current->pop();
1338     if (!TranspileCacheIRToMIR(this, loc, cacheIRSnapshot, {value})) {
1339       return false;
1340     }
1341   }
1342 
1343   if (loc.isBackedge()) {
1344     return buildTestBackedge(loc);
1345   }
1346 
1347   JSOp op = loc.getOp();
1348   BytecodeLocation target1 = loc.next();
1349   BytecodeLocation target2 = loc.getJumpTarget();
1350 
1351   if (TestTrueTargetIsJoinPoint(op)) {
1352     std::swap(target1, target2);
1353   }
1354 
1355   MDefinition* value = current->pop();
1356 
1357   // JSOp::And and JSOp::Or leave the top stack value unchanged.  The
1358   // top stack value may have been converted to bool by a transpiled
1359   // ToBool IC, so we push the original value. Also note that
1360   // JSOp::Case must pop a second value on the true-branch (the input
1361   // to the switch-statement). This conditional pop happens in
1362   // build_JumpTarget.
1363   bool mustKeepCondition = (op == JSOp::And || op == JSOp::Or);
1364   if (mustKeepCondition) {
1365     current->push(originalValue);
1366   }
1367 
1368   // If this op always branches to the same location we treat this as a
1369   // JSOp::Goto.
1370   if (target1 == target2) {
1371     value->setImplicitlyUsedUnchecked();
1372     return buildForwardGoto(target1);
1373   }
1374 
1375   MTest* test = MTest::New(alloc(), value, /* ifTrue = */ nullptr,
1376                            /* ifFalse = */ nullptr);
1377   current->end(test);
1378 
1379   if (!addPendingEdge(PendingEdge::NewTestTrue(current, op), target1)) {
1380     return false;
1381   }
1382   if (!addPendingEdge(PendingEdge::NewTestFalse(current, op), target2)) {
1383     return false;
1384   }
1385 
1386   if (const auto* typesSnapshot = getOpSnapshot<WarpPolymorphicTypes>(loc)) {
1387     test->setObservedTypes(typesSnapshot->list());
1388   }
1389 
1390   setTerminatedBlock();
1391   return true;
1392 }
1393 
buildTestBackedge(BytecodeLocation loc)1394 bool WarpBuilder::buildTestBackedge(BytecodeLocation loc) {
1395   JSOp op = loc.getOp();
1396   MOZ_ASSERT(op == JSOp::JumpIfTrue);
1397   MOZ_ASSERT(loopDepth() > 0);
1398 
1399   MDefinition* value = current->pop();
1400 
1401   BytecodeLocation loopHead = loc.getJumpTarget();
1402   MOZ_ASSERT(loopHead.is(JSOp::LoopHead));
1403 
1404   BytecodeLocation successor = loc.next();
1405 
1406   // We can finish the loop now. Use the loophead pc instead of the current pc
1407   // because the stack depth at the start of that op matches the current stack
1408   // depth (after popping our operand).
1409   MBasicBlock* pred = current;
1410   if (!startNewBlock(current, loopHead)) {
1411     return false;
1412   }
1413 
1414   MTest* test = MTest::New(alloc(), value, /* ifTrue = */ current,
1415                            /* ifFalse = */ nullptr);
1416   pred->end(test);
1417 
1418   if (const auto* typesSnapshot = getOpSnapshot<WarpPolymorphicTypes>(loc)) {
1419     test->setObservedTypes(typesSnapshot->list());
1420   }
1421 
1422   if (!addPendingEdge(PendingEdge::NewTestFalse(pred, op), successor)) {
1423     return false;
1424   }
1425 
1426   return buildBackedge();
1427 }
1428 
build_JumpIfFalse(BytecodeLocation loc)1429 bool WarpBuilder::build_JumpIfFalse(BytecodeLocation loc) {
1430   return buildTestOp(loc);
1431 }
1432 
build_JumpIfTrue(BytecodeLocation loc)1433 bool WarpBuilder::build_JumpIfTrue(BytecodeLocation loc) {
1434   return buildTestOp(loc);
1435 }
1436 
build_And(BytecodeLocation loc)1437 bool WarpBuilder::build_And(BytecodeLocation loc) { return buildTestOp(loc); }
1438 
build_Or(BytecodeLocation loc)1439 bool WarpBuilder::build_Or(BytecodeLocation loc) { return buildTestOp(loc); }
1440 
build_Case(BytecodeLocation loc)1441 bool WarpBuilder::build_Case(BytecodeLocation loc) { return buildTestOp(loc); }
1442 
build_Default(BytecodeLocation loc)1443 bool WarpBuilder::build_Default(BytecodeLocation loc) {
1444   current->pop();
1445   return buildForwardGoto(loc.getJumpTarget());
1446 }
1447 
build_Coalesce(BytecodeLocation loc)1448 bool WarpBuilder::build_Coalesce(BytecodeLocation loc) {
1449   BytecodeLocation target1 = loc.next();
1450   BytecodeLocation target2 = loc.getJumpTarget();
1451   MOZ_ASSERT(target2 > target1);
1452 
1453   MDefinition* value = current->peek(-1);
1454 
1455   MInstruction* isNullOrUndefined = MIsNullOrUndefined::New(alloc(), value);
1456   current->add(isNullOrUndefined);
1457 
1458   current->end(MTest::New(alloc(), isNullOrUndefined, /* ifTrue = */ nullptr,
1459                           /* ifFalse = */ nullptr));
1460 
1461   if (!addPendingEdge(PendingEdge::NewTestTrue(current, JSOp::Coalesce),
1462                       target1)) {
1463     return false;
1464   }
1465   if (!addPendingEdge(PendingEdge::NewTestFalse(current, JSOp::Coalesce),
1466                       target2)) {
1467     return false;
1468   }
1469 
1470   setTerminatedBlock();
1471   return true;
1472 }
1473 
buildBackedge()1474 bool WarpBuilder::buildBackedge() {
1475   decLoopDepth();
1476 
1477   MBasicBlock* header = loopStack_.popCopy().header();
1478   current->end(MGoto::New(alloc(), header));
1479 
1480   if (!header->setBackedge(current)) {
1481     return false;
1482   }
1483 
1484   setTerminatedBlock();
1485   return true;
1486 }
1487 
buildForwardGoto(BytecodeLocation target)1488 bool WarpBuilder::buildForwardGoto(BytecodeLocation target) {
1489   current->end(MGoto::New(alloc(), nullptr));
1490 
1491   if (!addPendingEdge(PendingEdge::NewGoto(current), target)) {
1492     return false;
1493   }
1494 
1495   setTerminatedBlock();
1496   return true;
1497 }
1498 
build_Goto(BytecodeLocation loc)1499 bool WarpBuilder::build_Goto(BytecodeLocation loc) {
1500   if (loc.isBackedge()) {
1501     return buildBackedge();
1502   }
1503 
1504   return buildForwardGoto(loc.getJumpTarget());
1505 }
1506 
build_DebugCheckSelfHosted(BytecodeLocation loc)1507 bool WarpBuilder::build_DebugCheckSelfHosted(BytecodeLocation loc) {
1508 #ifdef DEBUG
1509   MDefinition* val = current->pop();
1510   MDebugCheckSelfHosted* check = MDebugCheckSelfHosted::New(alloc(), val);
1511   current->add(check);
1512   current->push(check);
1513   if (!resumeAfter(check, loc)) {
1514     return false;
1515   }
1516 #endif
1517   return true;
1518 }
1519 
build_DynamicImport(BytecodeLocation loc)1520 bool WarpBuilder::build_DynamicImport(BytecodeLocation loc) {
1521   MDefinition* specifier = current->pop();
1522   MDynamicImport* ins = MDynamicImport::New(alloc(), specifier);
1523   current->add(ins);
1524   current->push(ins);
1525   return resumeAfter(ins, loc);
1526 }
1527 
build_Not(BytecodeLocation loc)1528 bool WarpBuilder::build_Not(BytecodeLocation loc) {
1529   if (auto* cacheIRSnapshot = getOpSnapshot<WarpCacheIR>(loc)) {
1530     // If we have CacheIR, we can use it to refine the input before
1531     // emitting the MNot.
1532     MDefinition* value = current->pop();
1533     if (!TranspileCacheIRToMIR(this, loc, cacheIRSnapshot, {value})) {
1534       return false;
1535     }
1536   }
1537 
1538   MDefinition* value = current->pop();
1539   MNot* ins = MNot::New(alloc(), value);
1540   current->add(ins);
1541   current->push(ins);
1542 
1543   if (const auto* typesSnapshot = getOpSnapshot<WarpPolymorphicTypes>(loc)) {
1544     ins->setObservedTypes(typesSnapshot->list());
1545   }
1546 
1547   return true;
1548 }
1549 
build_ToString(BytecodeLocation loc)1550 bool WarpBuilder::build_ToString(BytecodeLocation loc) {
1551   MDefinition* value = current->pop();
1552 
1553   if (value->type() == MIRType::String) {
1554     value->setImplicitlyUsedUnchecked();
1555     current->push(value);
1556     return true;
1557   }
1558 
1559   MToString* ins =
1560       MToString::New(alloc(), value, MToString::SideEffectHandling::Supported);
1561   current->add(ins);
1562   current->push(ins);
1563   if (ins->isEffectful()) {
1564     return resumeAfter(ins, loc);
1565   }
1566   return true;
1567 }
1568 
usesEnvironmentChain() const1569 bool WarpBuilder::usesEnvironmentChain() const {
1570   return script_->jitScript()->usesEnvironmentChain();
1571 }
1572 
build_GlobalOrEvalDeclInstantiation(BytecodeLocation loc)1573 bool WarpBuilder::build_GlobalOrEvalDeclInstantiation(BytecodeLocation loc) {
1574   MOZ_ASSERT(!script_->isForEval(), "Eval scripts not supported");
1575   auto* redeclCheck = MGlobalDeclInstantiation::New(alloc());
1576   current->add(redeclCheck);
1577   return resumeAfter(redeclCheck, loc);
1578 }
1579 
build_BindVar(BytecodeLocation)1580 bool WarpBuilder::build_BindVar(BytecodeLocation) {
1581   MOZ_ASSERT(usesEnvironmentChain());
1582 
1583   MDefinition* env = current->environmentChain();
1584   MCallBindVar* ins = MCallBindVar::New(alloc(), env);
1585   current->add(ins);
1586   current->push(ins);
1587   return true;
1588 }
1589 
build_MutateProto(BytecodeLocation loc)1590 bool WarpBuilder::build_MutateProto(BytecodeLocation loc) {
1591   MDefinition* value = current->pop();
1592   MDefinition* obj = current->peek(-1);
1593   MMutateProto* mutate = MMutateProto::New(alloc(), obj, value);
1594   current->add(mutate);
1595   return resumeAfter(mutate, loc);
1596 }
1597 
getCallee()1598 MDefinition* WarpBuilder::getCallee() {
1599   if (inlineCallInfo()) {
1600     return inlineCallInfo()->callee();
1601   }
1602 
1603   MInstruction* callee = MCallee::New(alloc());
1604   current->add(callee);
1605   return callee;
1606 }
1607 
build_Callee(BytecodeLocation)1608 bool WarpBuilder::build_Callee(BytecodeLocation) {
1609   MDefinition* callee = getCallee();
1610   current->push(callee);
1611   return true;
1612 }
1613 
build_ToAsyncIter(BytecodeLocation loc)1614 bool WarpBuilder::build_ToAsyncIter(BytecodeLocation loc) {
1615   MDefinition* nextMethod = current->pop();
1616   MDefinition* iterator = current->pop();
1617   MToAsyncIter* ins = MToAsyncIter::New(alloc(), iterator, nextMethod);
1618   current->add(ins);
1619   current->push(ins);
1620   return resumeAfter(ins, loc);
1621 }
1622 
build_ToPropertyKey(BytecodeLocation loc)1623 bool WarpBuilder::build_ToPropertyKey(BytecodeLocation loc) {
1624   MDefinition* value = current->pop();
1625   return buildIC(loc, CacheKind::ToPropertyKey, {value});
1626 }
1627 
build_Typeof(BytecodeLocation loc)1628 bool WarpBuilder::build_Typeof(BytecodeLocation loc) {
1629   MDefinition* input = current->pop();
1630 
1631   if (const auto* typesSnapshot = getOpSnapshot<WarpPolymorphicTypes>(loc)) {
1632     auto* ins = MTypeOf::New(alloc(), input);
1633     ins->setObservedTypes(typesSnapshot->list());
1634     current->add(ins);
1635     current->push(ins);
1636     return true;
1637   }
1638 
1639   return buildIC(loc, CacheKind::TypeOf, {input});
1640 }
1641 
build_TypeofExpr(BytecodeLocation loc)1642 bool WarpBuilder::build_TypeofExpr(BytecodeLocation loc) {
1643   return build_Typeof(loc);
1644 }
1645 
build_Arguments(BytecodeLocation loc)1646 bool WarpBuilder::build_Arguments(BytecodeLocation loc) {
1647   auto* snapshot = getOpSnapshot<WarpArguments>(loc);
1648   MOZ_ASSERT(info().needsArgsObj());
1649   MOZ_ASSERT(snapshot);
1650 
1651   ArgumentsObject* templateObj = snapshot->templateObj();
1652   MDefinition* env = current->environmentChain();
1653 
1654   MInstruction* argsObj;
1655   if (inlineCallInfo()) {
1656     argsObj = MCreateInlinedArgumentsObject::New(alloc(), env, getCallee(),
1657                                                  inlineCallInfo()->argv());
1658   } else {
1659     argsObj = MCreateArgumentsObject::New(alloc(), env, templateObj);
1660   }
1661   current->add(argsObj);
1662   current->setArgumentsObject(argsObj);
1663   current->push(argsObj);
1664 
1665   return true;
1666 }
1667 
build_ObjWithProto(BytecodeLocation loc)1668 bool WarpBuilder::build_ObjWithProto(BytecodeLocation loc) {
1669   MDefinition* proto = current->pop();
1670   MInstruction* ins = MObjectWithProto::New(alloc(), proto);
1671   current->add(ins);
1672   current->push(ins);
1673   return resumeAfter(ins, loc);
1674 }
1675 
walkEnvironmentChain(uint32_t numHops)1676 MDefinition* WarpBuilder::walkEnvironmentChain(uint32_t numHops) {
1677   MDefinition* env = current->environmentChain();
1678 
1679   for (uint32_t i = 0; i < numHops; i++) {
1680     if (!alloc().ensureBallast()) {
1681       return nullptr;
1682     }
1683 
1684     MInstruction* ins = MEnclosingEnvironment::New(alloc(), env);
1685     current->add(ins);
1686     env = ins;
1687   }
1688 
1689   return env;
1690 }
1691 
build_GetAliasedVar(BytecodeLocation loc)1692 bool WarpBuilder::build_GetAliasedVar(BytecodeLocation loc) {
1693   EnvironmentCoordinate ec = loc.getEnvironmentCoordinate();
1694   MDefinition* obj = walkEnvironmentChain(ec.hops());
1695   if (!obj) {
1696     return false;
1697   }
1698 
1699   MInstruction* load;
1700   if (EnvironmentObject::nonExtensibleIsFixedSlot(ec)) {
1701     load = MLoadFixedSlot::New(alloc(), obj, ec.slot());
1702   } else {
1703     MInstruction* slots = MSlots::New(alloc(), obj);
1704     current->add(slots);
1705 
1706     uint32_t slot = EnvironmentObject::nonExtensibleDynamicSlotIndex(ec);
1707     load = MLoadDynamicSlot::New(alloc(), slots, slot);
1708   }
1709 
1710   current->add(load);
1711   current->push(load);
1712   return true;
1713 }
1714 
build_SetAliasedVar(BytecodeLocation loc)1715 bool WarpBuilder::build_SetAliasedVar(BytecodeLocation loc) {
1716   EnvironmentCoordinate ec = loc.getEnvironmentCoordinate();
1717   MDefinition* val = current->peek(-1);
1718   MDefinition* obj = walkEnvironmentChain(ec.hops());
1719   if (!obj) {
1720     return false;
1721   }
1722 
1723   current->add(MPostWriteBarrier::New(alloc(), obj, val));
1724 
1725   MInstruction* store;
1726   if (EnvironmentObject::nonExtensibleIsFixedSlot(ec)) {
1727     store = MStoreFixedSlot::NewBarriered(alloc(), obj, ec.slot(), val);
1728   } else {
1729     MInstruction* slots = MSlots::New(alloc(), obj);
1730     current->add(slots);
1731 
1732     uint32_t slot = EnvironmentObject::nonExtensibleDynamicSlotIndex(ec);
1733     store = MStoreDynamicSlot::NewBarriered(alloc(), slots, slot, val);
1734   }
1735 
1736   current->add(store);
1737   return resumeAfter(store, loc);
1738 }
1739 
build_InitAliasedLexical(BytecodeLocation loc)1740 bool WarpBuilder::build_InitAliasedLexical(BytecodeLocation loc) {
1741   return build_SetAliasedVar(loc);
1742 }
1743 
build_EnvCallee(BytecodeLocation loc)1744 bool WarpBuilder::build_EnvCallee(BytecodeLocation loc) {
1745   uint32_t numHops = loc.getEnvCalleeNumHops();
1746   MDefinition* env = walkEnvironmentChain(numHops);
1747   if (!env) {
1748     return false;
1749   }
1750 
1751   auto* callee = MLoadFixedSlot::New(alloc(), env, CallObject::calleeSlot());
1752   current->add(callee);
1753   current->push(callee);
1754   return true;
1755 }
1756 
build_Iter(BytecodeLocation loc)1757 bool WarpBuilder::build_Iter(BytecodeLocation loc) {
1758   MDefinition* obj = current->pop();
1759   return buildIC(loc, CacheKind::GetIterator, {obj});
1760 }
1761 
build_MoreIter(BytecodeLocation loc)1762 bool WarpBuilder::build_MoreIter(BytecodeLocation loc) {
1763   MDefinition* iter = current->peek(-1);
1764   MInstruction* ins = MIteratorMore::New(alloc(), iter);
1765   current->add(ins);
1766   current->push(ins);
1767   return resumeAfter(ins, loc);
1768 }
1769 
build_EndIter(BytecodeLocation loc)1770 bool WarpBuilder::build_EndIter(BytecodeLocation loc) {
1771   current->pop();  // Iterator value is not used.
1772   MDefinition* iter = current->pop();
1773   MInstruction* ins = MIteratorEnd::New(alloc(), iter);
1774   current->add(ins);
1775   return resumeAfter(ins, loc);
1776 }
1777 
build_IsNoIter(BytecodeLocation)1778 bool WarpBuilder::build_IsNoIter(BytecodeLocation) {
1779   MDefinition* def = current->peek(-1);
1780   MOZ_ASSERT(def->isIteratorMore());
1781   MInstruction* ins = MIsNoIter::New(alloc(), def);
1782   current->add(ins);
1783   current->push(ins);
1784   return true;
1785 }
1786 
transpileCall(BytecodeLocation loc,const WarpCacheIR * cacheIRSnapshot,CallInfo * callInfo)1787 bool WarpBuilder::transpileCall(BytecodeLocation loc,
1788                                 const WarpCacheIR* cacheIRSnapshot,
1789                                 CallInfo* callInfo) {
1790   // Synthesize the constant number of arguments for this call op.
1791   auto* argc = MConstant::New(alloc(), Int32Value(callInfo->argc()));
1792   current->add(argc);
1793 
1794   return TranspileCacheIRToMIR(this, loc, cacheIRSnapshot, {argc}, callInfo);
1795 }
1796 
buildCallOp(BytecodeLocation loc)1797 bool WarpBuilder::buildCallOp(BytecodeLocation loc) {
1798   uint32_t argc = loc.getCallArgc();
1799   JSOp op = loc.getOp();
1800   bool constructing = IsConstructOp(op);
1801   bool ignoresReturnValue = (op == JSOp::CallIgnoresRv || loc.resultIsPopped());
1802 
1803   CallInfo callInfo(alloc(), constructing, ignoresReturnValue);
1804   if (!callInfo.init(current, argc)) {
1805     return false;
1806   }
1807 
1808   if (const auto* inliningSnapshot = getOpSnapshot<WarpInlinedCall>(loc)) {
1809     // Transpile the CacheIR to generate the correct guards before
1810     // inlining.  In this case, CacheOp::CallInlinedFunction updates
1811     // the CallInfo, but does not generate a call.
1812     callInfo.markAsInlined();
1813     if (!transpileCall(loc, inliningSnapshot->cacheIRSnapshot(), &callInfo)) {
1814       return false;
1815     }
1816 
1817     // Generate the body of the inlined function.
1818     return buildInlinedCall(loc, inliningSnapshot, callInfo);
1819   }
1820 
1821   if (auto* cacheIRSnapshot = getOpSnapshot<WarpCacheIR>(loc)) {
1822     return transpileCall(loc, cacheIRSnapshot, &callInfo);
1823   }
1824 
1825   if (getOpSnapshot<WarpBailout>(loc)) {
1826     callInfo.setImplicitlyUsedUnchecked();
1827     return buildBailoutForColdIC(loc, CacheKind::Call);
1828   }
1829 
1830   bool needsThisCheck = false;
1831   if (callInfo.constructing()) {
1832     // Inline the this-object allocation on the caller-side.
1833     MDefinition* callee = callInfo.callee();
1834     MDefinition* newTarget = callInfo.getNewTarget();
1835     MCreateThis* createThis = MCreateThis::New(alloc(), callee, newTarget);
1836     current->add(createThis);
1837     callInfo.thisArg()->setImplicitlyUsedUnchecked();
1838     callInfo.setThis(createThis);
1839     needsThisCheck = true;
1840   }
1841 
1842   MCall* call = makeCall(callInfo, needsThisCheck);
1843   if (!call) {
1844     return false;
1845   }
1846 
1847   current->add(call);
1848   current->push(call);
1849   return resumeAfter(call, loc);
1850 }
1851 
build_Call(BytecodeLocation loc)1852 bool WarpBuilder::build_Call(BytecodeLocation loc) { return buildCallOp(loc); }
1853 
build_CallIgnoresRv(BytecodeLocation loc)1854 bool WarpBuilder::build_CallIgnoresRv(BytecodeLocation loc) {
1855   return buildCallOp(loc);
1856 }
1857 
build_CallIter(BytecodeLocation loc)1858 bool WarpBuilder::build_CallIter(BytecodeLocation loc) {
1859   return buildCallOp(loc);
1860 }
1861 
build_FunCall(BytecodeLocation loc)1862 bool WarpBuilder::build_FunCall(BytecodeLocation loc) {
1863   return buildCallOp(loc);
1864 }
1865 
build_FunApply(BytecodeLocation loc)1866 bool WarpBuilder::build_FunApply(BytecodeLocation loc) {
1867   return buildCallOp(loc);
1868 }
1869 
build_New(BytecodeLocation loc)1870 bool WarpBuilder::build_New(BytecodeLocation loc) { return buildCallOp(loc); }
1871 
build_SuperCall(BytecodeLocation loc)1872 bool WarpBuilder::build_SuperCall(BytecodeLocation loc) {
1873   return buildCallOp(loc);
1874 }
1875 
build_FunctionThis(BytecodeLocation loc)1876 bool WarpBuilder::build_FunctionThis(BytecodeLocation loc) {
1877   MOZ_ASSERT(info().funMaybeLazy());
1878 
1879   if (script_->strict()) {
1880     // No need to wrap primitive |this| in strict mode.
1881     current->pushSlot(info().thisSlot());
1882     return true;
1883   }
1884 
1885   MOZ_ASSERT(!script_->hasNonSyntacticScope(),
1886              "WarpOracle should have aborted compilation");
1887 
1888   MDefinition* def = current->getSlot(info().thisSlot());
1889   JSObject* globalThis = snapshot().globalLexicalEnvThis();
1890 
1891   auto* thisObj = MBoxNonStrictThis::New(alloc(), def, globalThis);
1892   current->add(thisObj);
1893   current->push(thisObj);
1894 
1895   return true;
1896 }
1897 
build_GlobalThis(BytecodeLocation loc)1898 bool WarpBuilder::build_GlobalThis(BytecodeLocation loc) {
1899   MOZ_ASSERT(!script_->hasNonSyntacticScope(),
1900              "WarpOracle should have aborted compilation");
1901   JSObject* obj = snapshot().globalLexicalEnvThis();
1902   pushConstant(ObjectValue(*obj));
1903   return true;
1904 }
1905 
globalLexicalEnvConstant()1906 MConstant* WarpBuilder::globalLexicalEnvConstant() {
1907   JSObject* globalLexical = snapshot().globalLexicalEnv();
1908   return constant(ObjectValue(*globalLexical));
1909 }
1910 
build_GetName(BytecodeLocation loc)1911 bool WarpBuilder::build_GetName(BytecodeLocation loc) {
1912   MDefinition* env = current->environmentChain();
1913   return buildIC(loc, CacheKind::GetName, {env});
1914 }
1915 
build_GetGName(BytecodeLocation loc)1916 bool WarpBuilder::build_GetGName(BytecodeLocation loc) {
1917   if (script_->hasNonSyntacticScope()) {
1918     return build_GetName(loc);
1919   }
1920 
1921   // Try to optimize undefined/NaN/Infinity.
1922   PropertyName* name = loc.getPropertyName(script_);
1923   const JSAtomState& names = mirGen().runtime->names();
1924 
1925   if (name == names.undefined) {
1926     pushConstant(UndefinedValue());
1927     return true;
1928   }
1929   if (name == names.NaN) {
1930     pushConstant(JS::NaNValue());
1931     return true;
1932   }
1933   if (name == names.Infinity) {
1934     pushConstant(JS::InfinityValue());
1935     return true;
1936   }
1937 
1938   MDefinition* env = globalLexicalEnvConstant();
1939   return buildIC(loc, CacheKind::GetName, {env});
1940 }
1941 
build_BindName(BytecodeLocation loc)1942 bool WarpBuilder::build_BindName(BytecodeLocation loc) {
1943   MDefinition* env = current->environmentChain();
1944   return buildIC(loc, CacheKind::BindName, {env});
1945 }
1946 
build_BindGName(BytecodeLocation loc)1947 bool WarpBuilder::build_BindGName(BytecodeLocation loc) {
1948   if (const auto* snapshot = getOpSnapshot<WarpBindGName>(loc)) {
1949     MOZ_ASSERT(!script_->hasNonSyntacticScope());
1950     JSObject* globalEnv = snapshot->globalEnv();
1951     pushConstant(ObjectValue(*globalEnv));
1952     return true;
1953   }
1954 
1955   if (script_->hasNonSyntacticScope()) {
1956     return build_BindName(loc);
1957   }
1958 
1959   MDefinition* env = globalLexicalEnvConstant();
1960   return buildIC(loc, CacheKind::BindName, {env});
1961 }
1962 
build_GetProp(BytecodeLocation loc)1963 bool WarpBuilder::build_GetProp(BytecodeLocation loc) {
1964   MDefinition* val = current->pop();
1965   return buildIC(loc, CacheKind::GetProp, {val});
1966 }
1967 
build_GetElem(BytecodeLocation loc)1968 bool WarpBuilder::build_GetElem(BytecodeLocation loc) {
1969   MDefinition* id = current->pop();
1970   MDefinition* val = current->pop();
1971   return buildIC(loc, CacheKind::GetElem, {val, id});
1972 }
1973 
build_SetProp(BytecodeLocation loc)1974 bool WarpBuilder::build_SetProp(BytecodeLocation loc) {
1975   MDefinition* val = current->pop();
1976   MDefinition* obj = current->pop();
1977   current->push(val);
1978   return buildIC(loc, CacheKind::SetProp, {obj, val});
1979 }
1980 
build_StrictSetProp(BytecodeLocation loc)1981 bool WarpBuilder::build_StrictSetProp(BytecodeLocation loc) {
1982   return build_SetProp(loc);
1983 }
1984 
build_SetName(BytecodeLocation loc)1985 bool WarpBuilder::build_SetName(BytecodeLocation loc) {
1986   return build_SetProp(loc);
1987 }
1988 
build_StrictSetName(BytecodeLocation loc)1989 bool WarpBuilder::build_StrictSetName(BytecodeLocation loc) {
1990   return build_SetProp(loc);
1991 }
1992 
build_SetGName(BytecodeLocation loc)1993 bool WarpBuilder::build_SetGName(BytecodeLocation loc) {
1994   return build_SetProp(loc);
1995 }
1996 
build_StrictSetGName(BytecodeLocation loc)1997 bool WarpBuilder::build_StrictSetGName(BytecodeLocation loc) {
1998   return build_SetProp(loc);
1999 }
2000 
build_InitGLexical(BytecodeLocation loc)2001 bool WarpBuilder::build_InitGLexical(BytecodeLocation loc) {
2002   MOZ_ASSERT(!script_->hasNonSyntacticScope());
2003 
2004   MDefinition* globalLexical = globalLexicalEnvConstant();
2005   MDefinition* val = current->peek(-1);
2006 
2007   return buildIC(loc, CacheKind::SetProp, {globalLexical, val});
2008 }
2009 
build_SetElem(BytecodeLocation loc)2010 bool WarpBuilder::build_SetElem(BytecodeLocation loc) {
2011   MDefinition* val = current->pop();
2012   MDefinition* id = current->pop();
2013   MDefinition* obj = current->pop();
2014   current->push(val);
2015   return buildIC(loc, CacheKind::SetElem, {obj, id, val});
2016 }
2017 
build_StrictSetElem(BytecodeLocation loc)2018 bool WarpBuilder::build_StrictSetElem(BytecodeLocation loc) {
2019   return build_SetElem(loc);
2020 }
2021 
build_DelProp(BytecodeLocation loc)2022 bool WarpBuilder::build_DelProp(BytecodeLocation loc) {
2023   PropertyName* name = loc.getPropertyName(script_);
2024   MDefinition* obj = current->pop();
2025   bool strict = loc.getOp() == JSOp::StrictDelProp;
2026 
2027   MInstruction* ins = MDeleteProperty::New(alloc(), obj, name, strict);
2028   current->add(ins);
2029   current->push(ins);
2030   return resumeAfter(ins, loc);
2031 }
2032 
build_StrictDelProp(BytecodeLocation loc)2033 bool WarpBuilder::build_StrictDelProp(BytecodeLocation loc) {
2034   return build_DelProp(loc);
2035 }
2036 
build_DelElem(BytecodeLocation loc)2037 bool WarpBuilder::build_DelElem(BytecodeLocation loc) {
2038   MDefinition* id = current->pop();
2039   MDefinition* obj = current->pop();
2040   bool strict = loc.getOp() == JSOp::StrictDelElem;
2041 
2042   MInstruction* ins = MDeleteElement::New(alloc(), obj, id, strict);
2043   current->add(ins);
2044   current->push(ins);
2045   return resumeAfter(ins, loc);
2046 }
2047 
build_StrictDelElem(BytecodeLocation loc)2048 bool WarpBuilder::build_StrictDelElem(BytecodeLocation loc) {
2049   return build_DelElem(loc);
2050 }
2051 
build_SetFunName(BytecodeLocation loc)2052 bool WarpBuilder::build_SetFunName(BytecodeLocation loc) {
2053   FunctionPrefixKind prefixKind = loc.getFunctionPrefixKind();
2054   MDefinition* name = current->pop();
2055   MDefinition* fun = current->pop();
2056 
2057   MSetFunName* ins = MSetFunName::New(alloc(), fun, name, uint8_t(prefixKind));
2058   current->add(ins);
2059   current->push(fun);
2060   return resumeAfter(ins, loc);
2061 }
2062 
build_PushLexicalEnv(BytecodeLocation loc)2063 bool WarpBuilder::build_PushLexicalEnv(BytecodeLocation loc) {
2064   MOZ_ASSERT(usesEnvironmentChain());
2065 
2066   LexicalScope* scope = &loc.getScope(script_)->as<LexicalScope>();
2067   MDefinition* env = current->environmentChain();
2068 
2069   auto* ins = MNewLexicalEnvironmentObject::New(alloc(), env, scope);
2070   current->add(ins);
2071   current->setEnvironmentChain(ins);
2072   return true;
2073 }
2074 
build_PushClassBodyEnv(BytecodeLocation loc)2075 bool WarpBuilder::build_PushClassBodyEnv(BytecodeLocation loc) {
2076   MOZ_ASSERT(usesEnvironmentChain());
2077 
2078   ClassBodyScope* scope = &loc.getScope(script_)->as<ClassBodyScope>();
2079   MDefinition* env = current->environmentChain();
2080 
2081   auto* ins = MNewClassBodyEnvironmentObject::New(alloc(), env, scope);
2082   current->add(ins);
2083   current->setEnvironmentChain(ins);
2084   return true;
2085 }
2086 
build_PopLexicalEnv(BytecodeLocation)2087 bool WarpBuilder::build_PopLexicalEnv(BytecodeLocation) {
2088   MDefinition* enclosingEnv = walkEnvironmentChain(1);
2089   if (!enclosingEnv) {
2090     return false;
2091   }
2092   current->setEnvironmentChain(enclosingEnv);
2093   return true;
2094 }
2095 
buildCopyLexicalEnvOp(bool copySlots)2096 void WarpBuilder::buildCopyLexicalEnvOp(bool copySlots) {
2097   MOZ_ASSERT(usesEnvironmentChain());
2098 
2099   MDefinition* env = current->environmentChain();
2100   auto* ins = MCopyLexicalEnvironmentObject::New(alloc(), env, copySlots);
2101   current->add(ins);
2102   current->setEnvironmentChain(ins);
2103 }
2104 
build_FreshenLexicalEnv(BytecodeLocation)2105 bool WarpBuilder::build_FreshenLexicalEnv(BytecodeLocation) {
2106   buildCopyLexicalEnvOp(/* copySlots = */ true);
2107   return true;
2108 }
2109 
build_RecreateLexicalEnv(BytecodeLocation)2110 bool WarpBuilder::build_RecreateLexicalEnv(BytecodeLocation) {
2111   buildCopyLexicalEnvOp(/* copySlots = */ false);
2112   return true;
2113 }
2114 
build_ImplicitThis(BytecodeLocation loc)2115 bool WarpBuilder::build_ImplicitThis(BytecodeLocation loc) {
2116   MOZ_ASSERT(usesEnvironmentChain());
2117 
2118   PropertyName* name = loc.getPropertyName(script_);
2119   MDefinition* env = current->environmentChain();
2120 
2121   auto* ins = MImplicitThis::New(alloc(), env, name);
2122   current->add(ins);
2123   current->push(ins);
2124   return resumeAfter(ins, loc);
2125 }
2126 
build_GImplicitThis(BytecodeLocation loc)2127 bool WarpBuilder::build_GImplicitThis(BytecodeLocation loc) {
2128   if (script_->hasNonSyntacticScope()) {
2129     return build_ImplicitThis(loc);
2130   }
2131   return build_Undefined(loc);
2132 }
2133 
build_CheckClassHeritage(BytecodeLocation loc)2134 bool WarpBuilder::build_CheckClassHeritage(BytecodeLocation loc) {
2135   MDefinition* def = current->pop();
2136   auto* ins = MCheckClassHeritage::New(alloc(), def);
2137   current->add(ins);
2138   current->push(ins);
2139   return resumeAfter(ins, loc);
2140 }
2141 
build_CheckThis(BytecodeLocation)2142 bool WarpBuilder::build_CheckThis(BytecodeLocation) {
2143   MDefinition* def = current->pop();
2144   auto* ins = MCheckThis::New(alloc(), def);
2145   current->add(ins);
2146   current->push(ins);
2147   return true;
2148 }
2149 
build_CheckThisReinit(BytecodeLocation)2150 bool WarpBuilder::build_CheckThisReinit(BytecodeLocation) {
2151   MDefinition* def = current->pop();
2152   auto* ins = MCheckThisReinit::New(alloc(), def);
2153   current->add(ins);
2154   current->push(ins);
2155   return true;
2156 }
2157 
build_Generator(BytecodeLocation loc)2158 bool WarpBuilder::build_Generator(BytecodeLocation loc) {
2159   MDefinition* callee = getCallee();
2160   MDefinition* environmentChain = current->environmentChain();
2161   MDefinition* argsObj = info().needsArgsObj() ? current->argumentsObject()
2162                                                : constant(Int32Value(0));
2163 
2164   MGenerator* generator =
2165       MGenerator::New(alloc(), callee, environmentChain, argsObj);
2166 
2167   current->add(generator);
2168   current->push(generator);
2169   return resumeAfter(generator, loc);
2170 }
2171 
build_AfterYield(BytecodeLocation loc)2172 bool WarpBuilder::build_AfterYield(BytecodeLocation loc) {
2173   // Unreachable blocks don't need to generate a bail.
2174   if (hasTerminatedBlock()) {
2175     return true;
2176   }
2177 
2178   // This comes after a yield, which we generate as a return,
2179   // so we know this should be unreachable code.
2180   //
2181   // We emit an unreachable bail for this, which will assert if we
2182   // ever execute this.
2183   //
2184   // An Unreachable bail, instead of MUnreachable, because MUnreachable
2185   // is a control instruction, and injecting it in the middle of a block
2186   // causes various graph state assertions to fail.
2187   MBail* bail = MBail::New(alloc(), BailoutKind::Unreachable);
2188   current->add(bail);
2189 
2190   return true;
2191 }
2192 
build_FinalYieldRval(BytecodeLocation loc)2193 bool WarpBuilder::build_FinalYieldRval(BytecodeLocation loc) {
2194   MDefinition* gen = current->pop();
2195 
2196   auto setSlotNull = [this, gen](size_t slot) {
2197     auto* ins = MStoreFixedSlot::NewBarriered(alloc(), gen, slot,
2198                                               constant(NullValue()));
2199     current->add(ins);
2200   };
2201 
2202   // Close the generator
2203   setSlotNull(AbstractGeneratorObject::calleeSlot());
2204   setSlotNull(AbstractGeneratorObject::envChainSlot());
2205   setSlotNull(AbstractGeneratorObject::argsObjectSlot());
2206   setSlotNull(AbstractGeneratorObject::stackStorageSlot());
2207   setSlotNull(AbstractGeneratorObject::resumeIndexSlot());
2208 
2209   // Return
2210   return build_RetRval(loc);
2211 }
2212 
build_AsyncResolve(BytecodeLocation loc)2213 bool WarpBuilder::build_AsyncResolve(BytecodeLocation loc) {
2214   MDefinition* generator = current->pop();
2215   MDefinition* valueOrReason = current->pop();
2216   auto resolveKind = loc.getAsyncFunctionResolveKind();
2217 
2218   MAsyncResolve* resolve =
2219       MAsyncResolve::New(alloc(), generator, valueOrReason, resolveKind);
2220   current->add(resolve);
2221   current->push(resolve);
2222   return resumeAfter(resolve, loc);
2223 }
2224 
build_ResumeKind(BytecodeLocation loc)2225 bool WarpBuilder::build_ResumeKind(BytecodeLocation loc) {
2226   GeneratorResumeKind resumeKind = loc.resumeKind();
2227 
2228   current->push(constant(Int32Value(static_cast<int32_t>(resumeKind))));
2229   return true;
2230 }
2231 
build_CheckResumeKind(BytecodeLocation loc)2232 bool WarpBuilder::build_CheckResumeKind(BytecodeLocation loc) {
2233   // Outside of `yield*`, this is normally unreachable code in Warp,
2234   // so we just manipulate the stack appropriately to ensure correct
2235   // MIR generation.
2236   //
2237   // However, `yield*` emits a forced generator return which can be
2238   // warp compiled, so in order to correctly handle these semantics
2239   // we also generate a bailout, so that the forced generator return
2240   // runs in baseline.
2241   MDefinition* resumeKind = current->pop();
2242   MDefinition* gen = current->pop();
2243   MDefinition* rval = current->peek(-1);
2244 
2245   // Mark operands as implicitly used.
2246   resumeKind->setImplicitlyUsedUnchecked();
2247   gen->setImplicitlyUsedUnchecked();
2248   rval->setImplicitlyUsedUnchecked();
2249 
2250   // Bail out if we encounter CheckResumeKind.
2251   MBail* bail = MBail::New(alloc(), BailoutKind::Inevitable);
2252   current->add(bail);
2253   current->setAlwaysBails();
2254 
2255   return true;
2256 }
2257 
build_CanSkipAwait(BytecodeLocation loc)2258 bool WarpBuilder::build_CanSkipAwait(BytecodeLocation loc) {
2259   MDefinition* val = current->pop();
2260 
2261   MCanSkipAwait* canSkip = MCanSkipAwait::New(alloc(), val);
2262   current->add(canSkip);
2263 
2264   current->push(val);
2265   current->push(canSkip);
2266 
2267   return resumeAfter(canSkip, loc);
2268 }
2269 
build_MaybeExtractAwaitValue(BytecodeLocation loc)2270 bool WarpBuilder::build_MaybeExtractAwaitValue(BytecodeLocation loc) {
2271   MDefinition* canSkip = current->pop();
2272   MDefinition* value = current->pop();
2273 
2274   MMaybeExtractAwaitValue* extracted =
2275       MMaybeExtractAwaitValue::New(alloc(), value, canSkip);
2276   current->add(extracted);
2277 
2278   current->push(extracted);
2279   current->push(canSkip);
2280 
2281   return resumeAfter(extracted, loc);
2282 }
2283 
build_InitialYield(BytecodeLocation loc)2284 bool WarpBuilder::build_InitialYield(BytecodeLocation loc) {
2285   MDefinition* gen = current->pop();
2286   return buildSuspend(loc, gen, gen);
2287 }
2288 
build_Await(BytecodeLocation loc)2289 bool WarpBuilder::build_Await(BytecodeLocation loc) {
2290   MDefinition* gen = current->pop();
2291   MDefinition* promiseOrGenerator = current->pop();
2292 
2293   return buildSuspend(loc, gen, promiseOrGenerator);
2294 }
build_Yield(BytecodeLocation loc)2295 bool WarpBuilder::build_Yield(BytecodeLocation loc) { return build_Await(loc); }
2296 
buildSuspend(BytecodeLocation loc,MDefinition * gen,MDefinition * retVal)2297 bool WarpBuilder::buildSuspend(BytecodeLocation loc, MDefinition* gen,
2298                                MDefinition* retVal) {
2299   // If required, unbox the generator object explicitly and infallibly.
2300   //
2301   // This is done to avoid fuzz-bugs where ApplyTypeInformation does the
2302   // unboxing, and generates fallible unboxes which can lead to torn object
2303   // state due to `bailAfter`.
2304   MDefinition* genObj = gen;
2305   if (genObj->type() != MIRType::Object) {
2306     auto* unbox =
2307         MUnbox::New(alloc(), gen, MIRType::Object, MUnbox::Mode::Infallible);
2308     current->add(unbox);
2309 
2310     genObj = unbox;
2311   }
2312 
2313   int32_t slotsToCopy = current->stackDepth() - info().firstLocalSlot();
2314   MOZ_ASSERT(slotsToCopy >= 0);
2315   if (slotsToCopy > 0) {
2316     auto* arraySlot = MLoadFixedSlot::New(
2317         alloc(), genObj, AbstractGeneratorObject::stackStorageSlot());
2318     current->add(arraySlot);
2319 
2320     auto* arrayObj = MUnbox::New(alloc(), arraySlot, MIRType::Object,
2321                                  MUnbox::Mode::Infallible);
2322     current->add(arrayObj);
2323 
2324     auto* stackStorage = MElements::New(alloc(), arrayObj);
2325     current->add(stackStorage);
2326 
2327     for (int32_t i = 0; i < slotsToCopy; i++) {
2328       if (!alloc().ensureBallast()) {
2329         return false;
2330       }
2331       // Use peekUnchecked because we're also writing out the argument slots
2332       int32_t peek = -slotsToCopy + i;
2333       MDefinition* stackElem = current->peekUnchecked(peek);
2334       auto* store = MStoreElement::New(alloc(), stackStorage,
2335                                        constant(Int32Value(i)), stackElem,
2336                                        /* needsHoleCheck = */ false);
2337 
2338       current->add(store);
2339       current->add(MPostWriteBarrier::New(alloc(), arrayObj, stackElem));
2340     }
2341 
2342     auto* len = constant(Int32Value(slotsToCopy - 1));
2343 
2344     auto* setInitLength =
2345         MSetInitializedLength::New(alloc(), stackStorage, len);
2346     current->add(setInitLength);
2347 
2348     auto* setLength = MSetArrayLength::New(alloc(), stackStorage, len);
2349     current->add(setLength);
2350   }
2351 
2352   // Update Generator Object state
2353   uint32_t resumeIndex = loc.getResumeIndex();
2354 
2355   // This store is unbarriered, as it's only ever storing an integer, and as
2356   // such doesn't partake of object tracing.
2357   current->add(MStoreFixedSlot::NewUnbarriered(
2358       alloc(), genObj, AbstractGeneratorObject::resumeIndexSlot(),
2359       constant(Int32Value(resumeIndex))));
2360 
2361   // This store is barriered because it stores an object value.
2362   current->add(MStoreFixedSlot::NewBarriered(
2363       alloc(), genObj, AbstractGeneratorObject::envChainSlot(),
2364       current->environmentChain()));
2365 
2366   current->add(
2367       MPostWriteBarrier::New(alloc(), genObj, current->environmentChain()));
2368 
2369   // GeneratorReturn will return from the method, however to support MIR
2370   // generation isn't treated like the end of a block
2371   MGeneratorReturn* ret = MGeneratorReturn::New(alloc(), retVal);
2372   current->add(ret);
2373 
2374   // To ensure the rest of the MIR generation looks correct, fill the stack with
2375   // the appropriately typed MUnreachable's for the stack pushes from this
2376   // opcode.
2377   auto* unreachableResumeKind =
2378       MUnreachableResult::New(alloc(), MIRType::Int32);
2379   current->add(unreachableResumeKind);
2380   current->push(unreachableResumeKind);
2381 
2382   auto* unreachableGenerator =
2383       MUnreachableResult::New(alloc(), MIRType::Object);
2384   current->add(unreachableGenerator);
2385   current->push(unreachableGenerator);
2386 
2387   auto* unreachableRval = MUnreachableResult::New(alloc(), MIRType::Value);
2388   current->add(unreachableRval);
2389   current->push(unreachableRval);
2390 
2391   return true;
2392 }
2393 
build_AsyncAwait(BytecodeLocation loc)2394 bool WarpBuilder::build_AsyncAwait(BytecodeLocation loc) {
2395   MDefinition* gen = current->pop();
2396   MDefinition* value = current->pop();
2397 
2398   MAsyncAwait* asyncAwait = MAsyncAwait::New(alloc(), value, gen);
2399   current->add(asyncAwait);
2400   current->push(asyncAwait);
2401   return resumeAfter(asyncAwait, loc);
2402 }
2403 
build_CheckReturn(BytecodeLocation)2404 bool WarpBuilder::build_CheckReturn(BytecodeLocation) {
2405   MOZ_ASSERT(!script_->noScriptRval());
2406 
2407   MDefinition* returnValue = current->getSlot(info().returnValueSlot());
2408   MDefinition* thisValue = current->pop();
2409 
2410   auto* ins = MCheckReturn::New(alloc(), returnValue, thisValue);
2411   current->add(ins);
2412   current->setSlot(info().returnValueSlot(), ins);
2413   return true;
2414 }
2415 
buildCheckLexicalOp(BytecodeLocation loc)2416 void WarpBuilder::buildCheckLexicalOp(BytecodeLocation loc) {
2417   JSOp op = loc.getOp();
2418   MOZ_ASSERT(op == JSOp::CheckLexical || op == JSOp::CheckAliasedLexical);
2419 
2420   MDefinition* input = current->pop();
2421   MInstruction* lexicalCheck = MLexicalCheck::New(alloc(), input);
2422   current->add(lexicalCheck);
2423   current->push(lexicalCheck);
2424 
2425   if (snapshot().bailoutInfo().failedLexicalCheck()) {
2426     lexicalCheck->setNotMovable();
2427   }
2428 
2429   if (op == JSOp::CheckLexical) {
2430     // Set the local slot so that a subsequent GetLocal without a CheckLexical
2431     // (the frontend can elide lexical checks) doesn't let a definition with
2432     // MIRType::MagicUninitializedLexical escape to arbitrary MIR instructions.
2433     // Note that in this case the GetLocal would be unreachable because we throw
2434     // an exception here, but we still generate MIR instructions for it.
2435     uint32_t slot = info().localSlot(loc.local());
2436     current->setSlot(slot, lexicalCheck);
2437   }
2438 }
2439 
build_CheckLexical(BytecodeLocation loc)2440 bool WarpBuilder::build_CheckLexical(BytecodeLocation loc) {
2441   buildCheckLexicalOp(loc);
2442   return true;
2443 }
2444 
build_CheckAliasedLexical(BytecodeLocation loc)2445 bool WarpBuilder::build_CheckAliasedLexical(BytecodeLocation loc) {
2446   buildCheckLexicalOp(loc);
2447   return true;
2448 }
2449 
build_InitHomeObject(BytecodeLocation loc)2450 bool WarpBuilder::build_InitHomeObject(BytecodeLocation loc) {
2451   MDefinition* homeObject = current->pop();
2452   MDefinition* function = current->pop();
2453 
2454   current->add(MPostWriteBarrier::New(alloc(), function, homeObject));
2455 
2456   auto* ins = MInitHomeObject::New(alloc(), function, homeObject);
2457   current->add(ins);
2458   current->push(ins);
2459   return true;
2460 }
2461 
build_SuperBase(BytecodeLocation)2462 bool WarpBuilder::build_SuperBase(BytecodeLocation) {
2463   MDefinition* callee = current->pop();
2464 
2465   auto* homeObject = MHomeObject::New(alloc(), callee);
2466   current->add(homeObject);
2467 
2468   auto* superBase = MHomeObjectSuperBase::New(alloc(), homeObject);
2469   current->add(superBase);
2470   current->push(superBase);
2471   return true;
2472 }
2473 
build_SuperFun(BytecodeLocation)2474 bool WarpBuilder::build_SuperFun(BytecodeLocation) {
2475   MDefinition* callee = current->pop();
2476   auto* ins = MSuperFunction::New(alloc(), callee);
2477   current->add(ins);
2478   current->push(ins);
2479   return true;
2480 }
2481 
build_BuiltinObject(BytecodeLocation loc)2482 bool WarpBuilder::build_BuiltinObject(BytecodeLocation loc) {
2483   if (auto* snapshot = getOpSnapshot<WarpBuiltinObject>(loc)) {
2484     JSObject* builtin = snapshot->builtin();
2485     pushConstant(ObjectValue(*builtin));
2486     return true;
2487   }
2488 
2489   auto kind = loc.getBuiltinObjectKind();
2490   auto* ins = MBuiltinObject::New(alloc(), kind);
2491   current->add(ins);
2492   current->push(ins);
2493   return resumeAfter(ins, loc);
2494 }
2495 
build_GetIntrinsic(BytecodeLocation loc)2496 bool WarpBuilder::build_GetIntrinsic(BytecodeLocation loc) {
2497   if (auto* snapshot = getOpSnapshot<WarpGetIntrinsic>(loc)) {
2498     Value intrinsic = snapshot->intrinsic();
2499     pushConstant(intrinsic);
2500     return true;
2501   }
2502 
2503   PropertyName* name = loc.getPropertyName(script_);
2504   MCallGetIntrinsicValue* ins = MCallGetIntrinsicValue::New(alloc(), name);
2505   current->add(ins);
2506   current->push(ins);
2507   return true;
2508 }
2509 
build_ImportMeta(BytecodeLocation loc)2510 bool WarpBuilder::build_ImportMeta(BytecodeLocation loc) {
2511   ModuleObject* moduleObj = scriptSnapshot()->moduleObject();
2512   MOZ_ASSERT(moduleObj);
2513 
2514   MModuleMetadata* ins = MModuleMetadata::New(alloc(), moduleObj);
2515   current->add(ins);
2516   current->push(ins);
2517   return resumeAfter(ins, loc);
2518 }
2519 
build_CallSiteObj(BytecodeLocation loc)2520 bool WarpBuilder::build_CallSiteObj(BytecodeLocation loc) {
2521   // WarpOracle already called ProcessCallSiteObjOperation to prepare the
2522   // object.
2523   JSObject* obj = loc.getObject(script_);
2524   pushConstant(ObjectValue(*obj));
2525   return true;
2526 }
2527 
build_NewArray(BytecodeLocation loc)2528 bool WarpBuilder::build_NewArray(BytecodeLocation loc) {
2529   return buildIC(loc, CacheKind::NewArray, {});
2530 }
2531 
build_NewObject(BytecodeLocation loc)2532 bool WarpBuilder::build_NewObject(BytecodeLocation loc) {
2533   return buildIC(loc, CacheKind::NewObject, {});
2534 }
2535 
build_NewInit(BytecodeLocation loc)2536 bool WarpBuilder::build_NewInit(BytecodeLocation loc) {
2537   return build_NewObject(loc);
2538 }
2539 
build_Object(BytecodeLocation loc)2540 bool WarpBuilder::build_Object(BytecodeLocation loc) {
2541   JSObject* obj = loc.getObject(script_);
2542   MConstant* objConst = constant(ObjectValue(*obj));
2543 
2544   current->push(objConst);
2545   return true;
2546 }
2547 
buildInitPropGetterSetterOp(BytecodeLocation loc)2548 bool WarpBuilder::buildInitPropGetterSetterOp(BytecodeLocation loc) {
2549   PropertyName* name = loc.getPropertyName(script_);
2550   MDefinition* value = current->pop();
2551   MDefinition* obj = current->peek(-1);
2552 
2553   auto* ins = MInitPropGetterSetter::New(alloc(), obj, value, name);
2554   current->add(ins);
2555   return resumeAfter(ins, loc);
2556 }
2557 
build_InitPropGetter(BytecodeLocation loc)2558 bool WarpBuilder::build_InitPropGetter(BytecodeLocation loc) {
2559   return buildInitPropGetterSetterOp(loc);
2560 }
2561 
build_InitPropSetter(BytecodeLocation loc)2562 bool WarpBuilder::build_InitPropSetter(BytecodeLocation loc) {
2563   return buildInitPropGetterSetterOp(loc);
2564 }
2565 
build_InitHiddenPropGetter(BytecodeLocation loc)2566 bool WarpBuilder::build_InitHiddenPropGetter(BytecodeLocation loc) {
2567   return buildInitPropGetterSetterOp(loc);
2568 }
2569 
build_InitHiddenPropSetter(BytecodeLocation loc)2570 bool WarpBuilder::build_InitHiddenPropSetter(BytecodeLocation loc) {
2571   return buildInitPropGetterSetterOp(loc);
2572 }
2573 
buildInitElemGetterSetterOp(BytecodeLocation loc)2574 bool WarpBuilder::buildInitElemGetterSetterOp(BytecodeLocation loc) {
2575   MDefinition* value = current->pop();
2576   MDefinition* id = current->pop();
2577   MDefinition* obj = current->peek(-1);
2578 
2579   auto* ins = MInitElemGetterSetter::New(alloc(), obj, id, value);
2580   current->add(ins);
2581   return resumeAfter(ins, loc);
2582 }
2583 
build_InitElemGetter(BytecodeLocation loc)2584 bool WarpBuilder::build_InitElemGetter(BytecodeLocation loc) {
2585   return buildInitElemGetterSetterOp(loc);
2586 }
2587 
build_InitElemSetter(BytecodeLocation loc)2588 bool WarpBuilder::build_InitElemSetter(BytecodeLocation loc) {
2589   return buildInitElemGetterSetterOp(loc);
2590 }
2591 
build_InitHiddenElemGetter(BytecodeLocation loc)2592 bool WarpBuilder::build_InitHiddenElemGetter(BytecodeLocation loc) {
2593   return buildInitElemGetterSetterOp(loc);
2594 }
2595 
build_InitHiddenElemSetter(BytecodeLocation loc)2596 bool WarpBuilder::build_InitHiddenElemSetter(BytecodeLocation loc) {
2597   return buildInitElemGetterSetterOp(loc);
2598 }
2599 
build_In(BytecodeLocation loc)2600 bool WarpBuilder::build_In(BytecodeLocation loc) {
2601   MDefinition* obj = current->pop();
2602   MDefinition* id = current->pop();
2603   return buildIC(loc, CacheKind::In, {id, obj});
2604 }
2605 
build_HasOwn(BytecodeLocation loc)2606 bool WarpBuilder::build_HasOwn(BytecodeLocation loc) {
2607   MDefinition* obj = current->pop();
2608   MDefinition* id = current->pop();
2609   return buildIC(loc, CacheKind::HasOwn, {id, obj});
2610 }
2611 
build_CheckPrivateField(BytecodeLocation loc)2612 bool WarpBuilder::build_CheckPrivateField(BytecodeLocation loc) {
2613   MDefinition* id = current->peek(-1);
2614   MDefinition* obj = current->peek(-2);
2615   return buildIC(loc, CacheKind::CheckPrivateField, {obj, id});
2616 }
2617 
build_Instanceof(BytecodeLocation loc)2618 bool WarpBuilder::build_Instanceof(BytecodeLocation loc) {
2619   MDefinition* rhs = current->pop();
2620   MDefinition* obj = current->pop();
2621   return buildIC(loc, CacheKind::InstanceOf, {obj, rhs});
2622 }
2623 
build_NewTarget(BytecodeLocation loc)2624 bool WarpBuilder::build_NewTarget(BytecodeLocation loc) {
2625   MOZ_ASSERT(script_->isFunction());
2626   MOZ_ASSERT(info().funMaybeLazy());
2627 
2628   if (scriptSnapshot()->isArrowFunction()) {
2629     MDefinition* callee = getCallee();
2630     MArrowNewTarget* ins = MArrowNewTarget::New(alloc(), callee);
2631     current->add(ins);
2632     current->push(ins);
2633     return true;
2634   }
2635 
2636   if (inlineCallInfo()) {
2637     if (inlineCallInfo()->constructing()) {
2638       current->push(inlineCallInfo()->getNewTarget());
2639     } else {
2640       pushConstant(UndefinedValue());
2641     }
2642     return true;
2643   }
2644 
2645   MNewTarget* ins = MNewTarget::New(alloc());
2646   current->add(ins);
2647   current->push(ins);
2648   return true;
2649 }
2650 
build_CheckIsObj(BytecodeLocation loc)2651 bool WarpBuilder::build_CheckIsObj(BytecodeLocation loc) {
2652   CheckIsObjectKind kind = loc.getCheckIsObjectKind();
2653 
2654   MDefinition* toCheck = current->peek(-1);
2655   if (toCheck->type() == MIRType::Object) {
2656     toCheck->setImplicitlyUsedUnchecked();
2657     return true;
2658   }
2659 
2660   MDefinition* val = current->pop();
2661   MCheckIsObj* ins = MCheckIsObj::New(alloc(), val, uint8_t(kind));
2662   current->add(ins);
2663   current->push(ins);
2664   return true;
2665 }
2666 
build_CheckObjCoercible(BytecodeLocation loc)2667 bool WarpBuilder::build_CheckObjCoercible(BytecodeLocation loc) {
2668   MDefinition* val = current->pop();
2669   MCheckObjCoercible* ins = MCheckObjCoercible::New(alloc(), val);
2670   current->add(ins);
2671   current->push(ins);
2672   return resumeAfter(ins, loc);
2673 }
2674 
buildLoadSlot(MDefinition * obj,uint32_t numFixedSlots,uint32_t slot)2675 MInstruction* WarpBuilder::buildLoadSlot(MDefinition* obj,
2676                                          uint32_t numFixedSlots,
2677                                          uint32_t slot) {
2678   if (slot < numFixedSlots) {
2679     MLoadFixedSlot* load = MLoadFixedSlot::New(alloc(), obj, slot);
2680     current->add(load);
2681     return load;
2682   }
2683 
2684   MSlots* slots = MSlots::New(alloc(), obj);
2685   current->add(slots);
2686 
2687   MLoadDynamicSlot* load =
2688       MLoadDynamicSlot::New(alloc(), slots, slot - numFixedSlots);
2689   current->add(load);
2690   return load;
2691 }
2692 
build_GetImport(BytecodeLocation loc)2693 bool WarpBuilder::build_GetImport(BytecodeLocation loc) {
2694   auto* snapshot = getOpSnapshot<WarpGetImport>(loc);
2695 
2696   ModuleEnvironmentObject* targetEnv = snapshot->targetEnv();
2697 
2698   // Load the target environment slot.
2699   MConstant* obj = constant(ObjectValue(*targetEnv));
2700   auto* load = buildLoadSlot(obj, snapshot->numFixedSlots(), snapshot->slot());
2701 
2702   if (snapshot->needsLexicalCheck()) {
2703     // TODO: IonBuilder has code to mark non-movable. See buildCheckLexicalOp.
2704     MInstruction* lexicalCheck = MLexicalCheck::New(alloc(), load);
2705     current->add(lexicalCheck);
2706     current->push(lexicalCheck);
2707   } else {
2708     current->push(load);
2709   }
2710 
2711   return true;
2712 }
2713 
build_GetPropSuper(BytecodeLocation loc)2714 bool WarpBuilder::build_GetPropSuper(BytecodeLocation loc) {
2715   MDefinition* obj = current->pop();
2716   MDefinition* receiver = current->pop();
2717   return buildIC(loc, CacheKind::GetPropSuper, {obj, receiver});
2718 }
2719 
build_GetElemSuper(BytecodeLocation loc)2720 bool WarpBuilder::build_GetElemSuper(BytecodeLocation loc) {
2721   MDefinition* obj = current->pop();
2722   MDefinition* id = current->pop();
2723   MDefinition* receiver = current->pop();
2724   return buildIC(loc, CacheKind::GetElemSuper, {obj, id, receiver});
2725 }
2726 
build_InitProp(BytecodeLocation loc)2727 bool WarpBuilder::build_InitProp(BytecodeLocation loc) {
2728   MDefinition* val = current->pop();
2729   MDefinition* obj = current->peek(-1);
2730   return buildIC(loc, CacheKind::SetProp, {obj, val});
2731 }
2732 
build_InitLockedProp(BytecodeLocation loc)2733 bool WarpBuilder::build_InitLockedProp(BytecodeLocation loc) {
2734   return build_InitProp(loc);
2735 }
2736 
build_InitHiddenProp(BytecodeLocation loc)2737 bool WarpBuilder::build_InitHiddenProp(BytecodeLocation loc) {
2738   return build_InitProp(loc);
2739 }
2740 
build_InitElem(BytecodeLocation loc)2741 bool WarpBuilder::build_InitElem(BytecodeLocation loc) {
2742   MDefinition* val = current->pop();
2743   MDefinition* id = current->pop();
2744   MDefinition* obj = current->peek(-1);
2745   return buildIC(loc, CacheKind::SetElem, {obj, id, val});
2746 }
2747 
build_InitHiddenElem(BytecodeLocation loc)2748 bool WarpBuilder::build_InitHiddenElem(BytecodeLocation loc) {
2749   return build_InitElem(loc);
2750 }
2751 
build_InitElemArray(BytecodeLocation loc)2752 bool WarpBuilder::build_InitElemArray(BytecodeLocation loc) {
2753   MDefinition* val = current->pop();
2754   MDefinition* obj = current->peek(-1);
2755 
2756   // Note: getInitElemArrayIndex asserts the index fits in int32_t.
2757   uint32_t index = loc.getInitElemArrayIndex();
2758   MConstant* indexConst = constant(Int32Value(index));
2759 
2760   // Note: InitArrayElemOperation asserts the index does not exceed the array's
2761   // dense element capacity.
2762 
2763   auto* elements = MElements::New(alloc(), obj);
2764   current->add(elements);
2765 
2766   if (val->type() == MIRType::MagicHole) {
2767     val->setImplicitlyUsedUnchecked();
2768     auto* store = MStoreHoleValueElement::New(alloc(), elements, indexConst);
2769     current->add(store);
2770   } else {
2771     current->add(MPostWriteBarrier::New(alloc(), obj, val));
2772     auto* store = MStoreElement::New(alloc(), elements, indexConst, val,
2773                                      /* needsHoleCheck = */ false);
2774     current->add(store);
2775   }
2776 
2777   auto* setLength = MSetInitializedLength::New(alloc(), elements, indexConst);
2778   current->add(setLength);
2779 
2780   return resumeAfter(setLength, loc);
2781 }
2782 
build_InitElemInc(BytecodeLocation loc)2783 bool WarpBuilder::build_InitElemInc(BytecodeLocation loc) {
2784   MDefinition* val = current->pop();
2785   MDefinition* index = current->pop();
2786   MDefinition* obj = current->peek(-1);
2787 
2788   // Push index + 1.
2789   MConstant* constOne = constant(Int32Value(1));
2790   MAdd* nextIndex = MAdd::New(alloc(), index, constOne, TruncateKind::Truncate);
2791   current->add(nextIndex);
2792   current->push(nextIndex);
2793 
2794   return buildIC(loc, CacheKind::SetElem, {obj, index, val});
2795 }
2796 
LambdaInfoFromSnapshot(JSFunction * fun,const WarpLambda * snapshot)2797 static LambdaFunctionInfo LambdaInfoFromSnapshot(JSFunction* fun,
2798                                                  const WarpLambda* snapshot) {
2799   return LambdaFunctionInfo(fun, snapshot->baseScript(), snapshot->flags(),
2800                             snapshot->nargs());
2801 }
2802 
build_Lambda(BytecodeLocation loc)2803 bool WarpBuilder::build_Lambda(BytecodeLocation loc) {
2804   MOZ_ASSERT(usesEnvironmentChain());
2805 
2806   auto* snapshot = getOpSnapshot<WarpLambda>(loc);
2807 
2808   MDefinition* env = current->environmentChain();
2809 
2810   JSFunction* fun = loc.getFunction(script_);
2811   MConstant* funConst = constant(ObjectValue(*fun));
2812 
2813   auto* ins = MLambda::New(alloc(), env, funConst,
2814                            LambdaInfoFromSnapshot(fun, snapshot));
2815   current->add(ins);
2816   current->push(ins);
2817   return resumeAfter(ins, loc);
2818 }
2819 
build_LambdaArrow(BytecodeLocation loc)2820 bool WarpBuilder::build_LambdaArrow(BytecodeLocation loc) {
2821   MOZ_ASSERT(usesEnvironmentChain());
2822 
2823   auto* snapshot = getOpSnapshot<WarpLambda>(loc);
2824 
2825   MDefinition* env = current->environmentChain();
2826   MDefinition* newTarget = current->pop();
2827 
2828   JSFunction* fun = loc.getFunction(script_);
2829   MConstant* funConst = constant(ObjectValue(*fun));
2830 
2831   auto* ins = MLambdaArrow::New(alloc(), env, newTarget, funConst,
2832                                 LambdaInfoFromSnapshot(fun, snapshot));
2833   current->add(ins);
2834   current->push(ins);
2835   return resumeAfter(ins, loc);
2836 }
2837 
build_FunWithProto(BytecodeLocation loc)2838 bool WarpBuilder::build_FunWithProto(BytecodeLocation loc) {
2839   MOZ_ASSERT(usesEnvironmentChain());
2840 
2841   MDefinition* proto = current->pop();
2842   MDefinition* env = current->environmentChain();
2843 
2844   JSFunction* fun = loc.getFunction(script_);
2845   MConstant* funConst = constant(ObjectValue(*fun));
2846 
2847   auto* ins = MFunctionWithProto::New(alloc(), env, proto, funConst);
2848   current->add(ins);
2849   current->push(ins);
2850   return resumeAfter(ins, loc);
2851 }
2852 
build_SpreadCall(BytecodeLocation loc)2853 bool WarpBuilder::build_SpreadCall(BytecodeLocation loc) {
2854   bool constructing = false;
2855   CallInfo callInfo(alloc(), constructing, loc.resultIsPopped());
2856   callInfo.initForSpreadCall(current);
2857 
2858   if (auto* cacheIRSnapshot = getOpSnapshot<WarpCacheIR>(loc)) {
2859     return transpileCall(loc, cacheIRSnapshot, &callInfo);
2860   }
2861 
2862   MInstruction* call = makeSpreadCall(callInfo);
2863   if (!call) {
2864     return false;
2865   }
2866   call->setBailoutKind(BailoutKind::TooManyArguments);
2867   current->add(call);
2868   current->push(call);
2869   return resumeAfter(call, loc);
2870 }
2871 
build_SpreadNew(BytecodeLocation loc)2872 bool WarpBuilder::build_SpreadNew(BytecodeLocation loc) {
2873   MDefinition* newTarget = current->pop();
2874   MDefinition* argArr = current->pop();
2875   MDefinition* thisValue = current->pop();
2876   MDefinition* callee = current->pop();
2877 
2878   // Inline the constructor on the caller-side.
2879   MCreateThis* createThis = MCreateThis::New(alloc(), callee, newTarget);
2880   current->add(createThis);
2881   thisValue->setImplicitlyUsedUnchecked();
2882 
2883   // Load dense elements of the argument array. Note that the bytecode ensures
2884   // this is an array.
2885   MElements* elements = MElements::New(alloc(), argArr);
2886   current->add(elements);
2887 
2888   WrappedFunction* wrappedTarget = nullptr;
2889   auto* apply = MConstructArray::New(alloc(), wrappedTarget, callee, elements,
2890                                      createThis, newTarget);
2891   apply->setBailoutKind(BailoutKind::TooManyArguments);
2892   current->add(apply);
2893   current->push(apply);
2894   return resumeAfter(apply, loc);
2895 }
2896 
build_SpreadSuperCall(BytecodeLocation loc)2897 bool WarpBuilder::build_SpreadSuperCall(BytecodeLocation loc) {
2898   return build_SpreadNew(loc);
2899 }
2900 
build_OptimizeSpreadCall(BytecodeLocation loc)2901 bool WarpBuilder::build_OptimizeSpreadCall(BytecodeLocation loc) {
2902   MDefinition* value = current->peek(-1);
2903   return buildIC(loc, CacheKind::OptimizeSpreadCall, {value});
2904 }
2905 
build_Debugger(BytecodeLocation loc)2906 bool WarpBuilder::build_Debugger(BytecodeLocation loc) {
2907   // The |debugger;| statement will bail out to Baseline if the realm is a
2908   // debuggee realm with an onDebuggerStatement hook.
2909   MDebugger* debugger = MDebugger::New(alloc());
2910   current->add(debugger);
2911   return resumeAfter(debugger, loc);
2912 }
2913 
build_TableSwitch(BytecodeLocation loc)2914 bool WarpBuilder::build_TableSwitch(BytecodeLocation loc) {
2915   int32_t low = loc.getTableSwitchLow();
2916   int32_t high = loc.getTableSwitchHigh();
2917   size_t numCases = high - low + 1;
2918 
2919   MDefinition* input = current->pop();
2920   MTableSwitch* tableswitch = MTableSwitch::New(alloc(), input, low, high);
2921   current->end(tableswitch);
2922 
2923   MBasicBlock* switchBlock = current;
2924 
2925   // Create |default| block.
2926   {
2927     BytecodeLocation defaultLoc = loc.getTableSwitchDefaultTarget();
2928     if (!startNewBlock(switchBlock, defaultLoc)) {
2929       return false;
2930     }
2931 
2932     size_t index;
2933     if (!tableswitch->addDefault(current, &index)) {
2934       return false;
2935     }
2936     MOZ_ASSERT(index == 0);
2937 
2938     if (!buildForwardGoto(defaultLoc)) {
2939       return false;
2940     }
2941   }
2942 
2943   // Create blocks for all cases.
2944   for (size_t i = 0; i < numCases; i++) {
2945     BytecodeLocation caseLoc = loc.getTableSwitchCaseTarget(script_, i);
2946     if (!startNewBlock(switchBlock, caseLoc)) {
2947       return false;
2948     }
2949 
2950     size_t index;
2951     if (!tableswitch->addSuccessor(current, &index)) {
2952       return false;
2953     }
2954     if (!tableswitch->addCase(index)) {
2955       return false;
2956     }
2957 
2958     // TODO: IonBuilder has an optimization where it replaces the switch input
2959     // with the case value. This probably matters less for Warp. Re-evaluate.
2960 
2961     if (!buildForwardGoto(caseLoc)) {
2962       return false;
2963     }
2964   }
2965 
2966   MOZ_ASSERT(hasTerminatedBlock());
2967   return true;
2968 }
2969 
build_Rest(BytecodeLocation loc)2970 bool WarpBuilder::build_Rest(BytecodeLocation loc) {
2971   auto* snapshot = getOpSnapshot<WarpRest>(loc);
2972   Shape* shape = snapshot ? snapshot->shape() : nullptr;
2973 
2974   if (inlineCallInfo()) {
2975     // If we are inlining, we know the actual arguments.
2976     unsigned numActuals = inlineCallInfo()->argc();
2977     unsigned numFormals = info().nargs() - 1;
2978     unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
2979 
2980     // TODO: support pre-tenuring.
2981     gc::InitialHeap heap = gc::DefaultHeap;
2982 
2983     // Allocate an array of the correct size.
2984     MInstruction* newArray;
2985     if (shape && gc::CanUseFixedElementsForArray(numRest)) {
2986       auto* shapeConstant = MConstant::NewShape(alloc(), shape);
2987       current->add(shapeConstant);
2988       newArray = MNewArrayObject::New(alloc(), shapeConstant, numRest, heap);
2989     } else {
2990       MConstant* templateConst = constant(NullValue());
2991       newArray = MNewArray::NewVM(alloc(), numRest, templateConst, heap);
2992     }
2993     current->add(newArray);
2994     current->push(newArray);
2995 
2996     if (numRest == 0) {
2997       // No more updating to do.
2998       return true;
2999     }
3000 
3001     MElements* elements = MElements::New(alloc(), newArray);
3002     current->add(elements);
3003 
3004     // Unroll the argument copy loop. We don't need to do any bounds or hole
3005     // checking here.
3006     MConstant* index = nullptr;
3007     for (uint32_t i = numFormals; i < numActuals; i++) {
3008       if (!alloc().ensureBallast()) {
3009         return false;
3010       }
3011 
3012       index = MConstant::New(alloc(), Int32Value(i - numFormals));
3013       current->add(index);
3014 
3015       MDefinition* arg = inlineCallInfo()->argv()[i];
3016       MStoreElement* store = MStoreElement::New(alloc(), elements, index, arg,
3017                                                 /* needsHoleCheck = */ false);
3018       current->add(store);
3019       current->add(MPostWriteBarrier::New(alloc(), newArray, arg));
3020     }
3021 
3022     // Update the initialized length for all the (necessarily non-hole)
3023     // elements added.
3024     MSetInitializedLength* initLength =
3025         MSetInitializedLength::New(alloc(), elements, index);
3026     current->add(initLength);
3027 
3028     return true;
3029   }
3030 
3031   MArgumentsLength* numActuals = MArgumentsLength::New(alloc());
3032   current->add(numActuals);
3033 
3034   // Pass in the number of actual arguments, the number of formals (not
3035   // including the rest parameter slot itself), and the shape.
3036   unsigned numFormals = info().nargs() - 1;
3037   MRest* rest = MRest::New(alloc(), numActuals, numFormals, shape);
3038   current->add(rest);
3039   current->push(rest);
3040   return true;
3041 }
3042 
build_Try(BytecodeLocation loc)3043 bool WarpBuilder::build_Try(BytecodeLocation loc) {
3044   // Note: WarpOracle aborts compilation for try-statements with a 'finally'
3045   // block.
3046 
3047   graph().setHasTryBlock();
3048 
3049   MBasicBlock* pred = current;
3050   if (!startNewBlock(pred, loc.next())) {
3051     return false;
3052   }
3053 
3054   pred->end(MGoto::New(alloc(), current));
3055   return true;
3056 }
3057 
build_Exception(BytecodeLocation)3058 bool WarpBuilder::build_Exception(BytecodeLocation) {
3059   MOZ_CRASH("Unreachable because we skip catch-blocks");
3060 }
3061 
build_Throw(BytecodeLocation loc)3062 bool WarpBuilder::build_Throw(BytecodeLocation loc) {
3063   MDefinition* def = current->pop();
3064 
3065   MThrow* ins = MThrow::New(alloc(), def);
3066   current->add(ins);
3067   if (!resumeAfter(ins, loc)) {
3068     return false;
3069   }
3070 
3071   // Terminate the block.
3072   current->end(MUnreachable::New(alloc()));
3073   setTerminatedBlock();
3074   return true;
3075 }
3076 
build_ThrowSetConst(BytecodeLocation loc)3077 bool WarpBuilder::build_ThrowSetConst(BytecodeLocation loc) {
3078   auto* ins = MThrowRuntimeLexicalError::New(alloc(), JSMSG_BAD_CONST_ASSIGN);
3079   current->add(ins);
3080   if (!resumeAfter(ins, loc)) {
3081     return false;
3082   }
3083 
3084   // Terminate the block.
3085   current->end(MUnreachable::New(alloc()));
3086   setTerminatedBlock();
3087   return true;
3088 }
3089 
build_ThrowMsg(BytecodeLocation loc)3090 bool WarpBuilder::build_ThrowMsg(BytecodeLocation loc) {
3091   auto* ins = MThrowMsg::New(alloc(), loc.throwMsgKind());
3092   current->add(ins);
3093   if (!resumeAfter(ins, loc)) {
3094     return false;
3095   }
3096 
3097   // Terminate the block.
3098   current->end(MUnreachable::New(alloc()));
3099   setTerminatedBlock();
3100   return true;
3101 }
3102 
buildIC(BytecodeLocation loc,CacheKind kind,std::initializer_list<MDefinition * > inputs)3103 bool WarpBuilder::buildIC(BytecodeLocation loc, CacheKind kind,
3104                           std::initializer_list<MDefinition*> inputs) {
3105   MOZ_ASSERT(loc.opHasIC());
3106 
3107   mozilla::DebugOnly<size_t> numInputs = inputs.size();
3108   MOZ_ASSERT(numInputs == NumInputsForCacheKind(kind));
3109 
3110   if (auto* cacheIRSnapshot = getOpSnapshot<WarpCacheIR>(loc)) {
3111     return TranspileCacheIRToMIR(this, loc, cacheIRSnapshot, inputs);
3112   }
3113 
3114   if (getOpSnapshot<WarpBailout>(loc)) {
3115     for (MDefinition* input : inputs) {
3116       input->setImplicitlyUsedUnchecked();
3117     }
3118     return buildBailoutForColdIC(loc, kind);
3119   }
3120 
3121   if (const auto* inliningSnapshot = getOpSnapshot<WarpInlinedCall>(loc)) {
3122     // The CallInfo will be initialized by the transpiler.
3123     bool ignoresRval = BytecodeIsPopped(loc.toRawBytecode());
3124     CallInfo callInfo(alloc(), /*constructing =*/false, ignoresRval);
3125     callInfo.markAsInlined();
3126 
3127     if (!TranspileCacheIRToMIR(this, loc, inliningSnapshot->cacheIRSnapshot(),
3128                                inputs, &callInfo)) {
3129       return false;
3130     }
3131     return buildInlinedCall(loc, inliningSnapshot, callInfo);
3132   }
3133 
3134   // Work around std::initializer_list not defining operator[].
3135   auto getInput = [&](size_t index) -> MDefinition* {
3136     MOZ_ASSERT(index < numInputs);
3137     return inputs.begin()[index];
3138   };
3139 
3140   switch (kind) {
3141     case CacheKind::UnaryArith: {
3142       MOZ_ASSERT(numInputs == 1);
3143       auto* ins = MUnaryCache::New(alloc(), getInput(0));
3144       current->add(ins);
3145       current->push(ins);
3146       return resumeAfter(ins, loc);
3147     }
3148     case CacheKind::ToPropertyKey: {
3149       MOZ_ASSERT(numInputs == 1);
3150       auto* ins = MToPropertyKeyCache::New(alloc(), getInput(0));
3151       current->add(ins);
3152       current->push(ins);
3153       return resumeAfter(ins, loc);
3154     }
3155     case CacheKind::BinaryArith: {
3156       MOZ_ASSERT(numInputs == 2);
3157       auto* ins =
3158           MBinaryCache::New(alloc(), getInput(0), getInput(1), MIRType::Value);
3159       current->add(ins);
3160       current->push(ins);
3161       return resumeAfter(ins, loc);
3162     }
3163     case CacheKind::Compare: {
3164       MOZ_ASSERT(numInputs == 2);
3165       auto* ins = MBinaryCache::New(alloc(), getInput(0), getInput(1),
3166                                     MIRType::Boolean);
3167       current->add(ins);
3168       current->push(ins);
3169       return resumeAfter(ins, loc);
3170     }
3171     case CacheKind::In: {
3172       MOZ_ASSERT(numInputs == 2);
3173       auto* ins = MInCache::New(alloc(), getInput(0), getInput(1));
3174       current->add(ins);
3175       current->push(ins);
3176       return resumeAfter(ins, loc);
3177     }
3178     case CacheKind::HasOwn: {
3179       MOZ_ASSERT(numInputs == 2);
3180       // Note: the MHasOwnCache constructor takes obj/id instead of id/obj.
3181       auto* ins = MHasOwnCache::New(alloc(), getInput(1), getInput(0));
3182       current->add(ins);
3183       current->push(ins);
3184       return resumeAfter(ins, loc);
3185     }
3186     case CacheKind::CheckPrivateField: {
3187       MOZ_ASSERT(numInputs == 2);
3188       auto* ins =
3189           MCheckPrivateFieldCache::New(alloc(), getInput(0), getInput(1));
3190       current->add(ins);
3191       current->push(ins);
3192       return resumeAfter(ins, loc);
3193     }
3194     case CacheKind::InstanceOf: {
3195       MOZ_ASSERT(numInputs == 2);
3196       auto* ins = MInstanceOfCache::New(alloc(), getInput(0), getInput(1));
3197       current->add(ins);
3198       current->push(ins);
3199       return resumeAfter(ins, loc);
3200     }
3201     case CacheKind::BindName: {
3202       MOZ_ASSERT(numInputs == 1);
3203       auto* ins = MBindNameCache::New(alloc(), getInput(0));
3204       current->add(ins);
3205       current->push(ins);
3206       return resumeAfter(ins, loc);
3207     }
3208     case CacheKind::GetIterator: {
3209       MOZ_ASSERT(numInputs == 1);
3210       auto* ins = MGetIteratorCache::New(alloc(), getInput(0));
3211       current->add(ins);
3212       current->push(ins);
3213       return resumeAfter(ins, loc);
3214     }
3215     case CacheKind::GetName: {
3216       MOZ_ASSERT(numInputs == 1);
3217       auto* ins = MGetNameCache::New(alloc(), getInput(0));
3218       current->add(ins);
3219       current->push(ins);
3220       return resumeAfter(ins, loc);
3221     }
3222     case CacheKind::GetProp: {
3223       MOZ_ASSERT(numInputs == 1);
3224       PropertyName* name = loc.getPropertyName(script_);
3225       MConstant* id = constant(StringValue(name));
3226       MDefinition* val = getInput(0);
3227       auto* ins = MGetPropertyCache::New(alloc(), val, id);
3228       current->add(ins);
3229       current->push(ins);
3230       return resumeAfter(ins, loc);
3231     }
3232     case CacheKind::GetElem: {
3233       MOZ_ASSERT(numInputs == 2);
3234       MDefinition* val = getInput(0);
3235       auto* ins = MGetPropertyCache::New(alloc(), val, getInput(1));
3236       current->add(ins);
3237       current->push(ins);
3238       return resumeAfter(ins, loc);
3239     }
3240     case CacheKind::SetProp: {
3241       MOZ_ASSERT(numInputs == 2);
3242       PropertyName* name = loc.getPropertyName(script_);
3243       MConstant* id = constant(StringValue(name));
3244       bool strict = loc.isStrictSetOp();
3245       auto* ins =
3246           MSetPropertyCache::New(alloc(), getInput(0), id, getInput(1), strict);
3247       current->add(ins);
3248       return resumeAfter(ins, loc);
3249     }
3250     case CacheKind::SetElem: {
3251       MOZ_ASSERT(numInputs == 3);
3252       bool strict = loc.isStrictSetOp();
3253       auto* ins = MSetPropertyCache::New(alloc(), getInput(0), getInput(1),
3254                                          getInput(2), strict);
3255       current->add(ins);
3256       return resumeAfter(ins, loc);
3257     }
3258     case CacheKind::GetPropSuper: {
3259       MOZ_ASSERT(numInputs == 2);
3260       PropertyName* name = loc.getPropertyName(script_);
3261       MConstant* id = constant(StringValue(name));
3262       auto* ins =
3263           MGetPropSuperCache::New(alloc(), getInput(0), getInput(1), id);
3264       current->add(ins);
3265       current->push(ins);
3266       return resumeAfter(ins, loc);
3267     }
3268     case CacheKind::GetElemSuper: {
3269       MOZ_ASSERT(numInputs == 3);
3270       // Note: CacheIR expects obj/id/receiver but MGetPropSuperCache takes
3271       // obj/receiver/id so swap the last two inputs.
3272       auto* ins = MGetPropSuperCache::New(alloc(), getInput(0), getInput(2),
3273                                           getInput(1));
3274       current->add(ins);
3275       current->push(ins);
3276       return resumeAfter(ins, loc);
3277     }
3278     case CacheKind::OptimizeSpreadCall: {
3279       MOZ_ASSERT(numInputs == 1);
3280       auto* ins = MOptimizeSpreadCallCache::New(alloc(), getInput(0));
3281       current->add(ins);
3282       current->push(ins);
3283       return resumeAfter(ins, loc);
3284     }
3285     case CacheKind::TypeOf: {
3286       // Note: Warp does not have a TypeOf IC, it just inlines the operation.
3287       MOZ_ASSERT(numInputs == 1);
3288       auto* ins = MTypeOf::New(alloc(), getInput(0));
3289       current->add(ins);
3290       current->push(ins);
3291       return true;
3292     }
3293     case CacheKind::NewObject: {
3294       auto* templateConst = constant(NullValue());
3295       MNewObject* ins = MNewObject::NewVM(
3296           alloc(), templateConst, gc::DefaultHeap, MNewObject::ObjectLiteral);
3297       current->add(ins);
3298       current->push(ins);
3299       return resumeAfter(ins, loc);
3300     }
3301     case CacheKind::NewArray: {
3302       uint32_t length = loc.getNewArrayLength();
3303       MConstant* templateConst = constant(NullValue());
3304       MNewArray* ins =
3305           MNewArray::NewVM(alloc(), length, templateConst, gc::DefaultHeap);
3306       current->add(ins);
3307       current->push(ins);
3308       return true;
3309     }
3310     case CacheKind::GetIntrinsic:
3311     case CacheKind::ToBool:
3312     case CacheKind::Call:
3313       // We're currently not using an IC or transpiling CacheIR for these kinds.
3314       MOZ_CRASH("Unexpected kind");
3315   }
3316 
3317   return true;
3318 }
3319 
buildBailoutForColdIC(BytecodeLocation loc,CacheKind kind)3320 bool WarpBuilder::buildBailoutForColdIC(BytecodeLocation loc, CacheKind kind) {
3321   MOZ_ASSERT(loc.opHasIC());
3322 
3323   MBail* bail = MBail::New(alloc(), BailoutKind::FirstExecution);
3324   current->add(bail);
3325   current->setAlwaysBails();
3326 
3327   MIRType resultType;
3328   switch (kind) {
3329     case CacheKind::UnaryArith:
3330     case CacheKind::BinaryArith:
3331     case CacheKind::GetName:
3332     case CacheKind::GetProp:
3333     case CacheKind::GetElem:
3334     case CacheKind::GetPropSuper:
3335     case CacheKind::GetElemSuper:
3336     case CacheKind::GetIntrinsic:
3337     case CacheKind::Call:
3338     case CacheKind::ToPropertyKey:
3339       resultType = MIRType::Value;
3340       break;
3341     case CacheKind::BindName:
3342     case CacheKind::GetIterator:
3343     case CacheKind::NewArray:
3344     case CacheKind::NewObject:
3345       resultType = MIRType::Object;
3346       break;
3347     case CacheKind::TypeOf:
3348       resultType = MIRType::String;
3349       break;
3350     case CacheKind::ToBool:
3351     case CacheKind::Compare:
3352     case CacheKind::In:
3353     case CacheKind::HasOwn:
3354     case CacheKind::CheckPrivateField:
3355     case CacheKind::InstanceOf:
3356     case CacheKind::OptimizeSpreadCall:
3357       resultType = MIRType::Boolean;
3358       break;
3359     case CacheKind::SetProp:
3360     case CacheKind::SetElem:
3361       return true;  // No result.
3362   }
3363 
3364   auto* ins = MUnreachableResult::New(alloc(), resultType);
3365   current->add(ins);
3366   current->push(ins);
3367 
3368   return true;
3369 }
3370 
3371 class MOZ_RAII AutoAccumulateReturns {
3372   MIRGraph& graph_;
3373   MIRGraphReturns* prev_;
3374 
3375  public:
AutoAccumulateReturns(MIRGraph & graph,MIRGraphReturns & returns)3376   AutoAccumulateReturns(MIRGraph& graph, MIRGraphReturns& returns)
3377       : graph_(graph) {
3378     prev_ = graph_.returnAccumulator();
3379     graph_.setReturnAccumulator(&returns);
3380   }
~AutoAccumulateReturns()3381   ~AutoAccumulateReturns() { graph_.setReturnAccumulator(prev_); }
3382 };
3383 
buildInlinedCall(BytecodeLocation loc,const WarpInlinedCall * inlineSnapshot,CallInfo & callInfo)3384 bool WarpBuilder::buildInlinedCall(BytecodeLocation loc,
3385                                    const WarpInlinedCall* inlineSnapshot,
3386                                    CallInfo& callInfo) {
3387   jsbytecode* pc = loc.toRawBytecode();
3388 
3389   if (callInfo.isSetter()) {
3390     // build_SetProp pushes the rhs argument onto the stack. Remove it
3391     // in preparation for pushCallStack.
3392     current->pop();
3393   }
3394 
3395   callInfo.setImplicitlyUsedUnchecked();
3396 
3397   // Capture formals in the outer resume point.
3398   if (!callInfo.pushCallStack(current)) {
3399     return false;
3400   }
3401   MResumePoint* outerResumePoint =
3402       MResumePoint::New(alloc(), current, pc, MResumePoint::Outer);
3403   if (!outerResumePoint) {
3404     return false;
3405   }
3406   current->setOuterResumePoint(outerResumePoint);
3407 
3408   // Pop formals again, except leave |callee| on stack for duration of call.
3409   callInfo.popCallStack(current);
3410   current->push(callInfo.callee());
3411 
3412   // Build the graph.
3413   CompileInfo* calleeCompileInfo = inlineSnapshot->info();
3414   MIRGraphReturns returns(alloc());
3415   AutoAccumulateReturns aar(graph(), returns);
3416   WarpBuilder inlineBuilder(this, inlineSnapshot->scriptSnapshot(),
3417                             *calleeCompileInfo, &callInfo, outerResumePoint);
3418   if (!inlineBuilder.buildInline()) {
3419     // Note: Inlining only aborts on OOM.  If inlining would fail for
3420     // any other reason, we detect it in advance and don't inline.
3421     return false;
3422   }
3423 
3424   // We mark scripts as uninlineable in BytecodeAnalysis if we cannot
3425   // reach a return statement (without going through a catch/finally).
3426   MOZ_ASSERT(!returns.empty());
3427 
3428   // Create return block
3429   BytecodeLocation postCall = loc.next();
3430   MBasicBlock* prev = current;
3431   if (!startNewEntryBlock(prev->stackDepth(), postCall)) {
3432     return false;
3433   }
3434   // Restore previous value of callerResumePoint.
3435   current->setCallerResumePoint(callerResumePoint());
3436   current->inheritSlots(prev);
3437 
3438   // Pop |callee|.
3439   current->pop();
3440 
3441   // Accumulate return values.
3442   MDefinition* returnValue =
3443       patchInlinedReturns(calleeCompileInfo, callInfo, returns, current);
3444   if (!returnValue) {
3445     return false;
3446   }
3447   current->push(returnValue);
3448 
3449   // Initialize entry slots
3450   if (!current->initEntrySlots(alloc())) {
3451     return false;
3452   }
3453 
3454   return true;
3455 }
3456 
patchInlinedReturns(CompileInfo * calleeCompileInfo,CallInfo & callInfo,MIRGraphReturns & exits,MBasicBlock * returnBlock)3457 MDefinition* WarpBuilder::patchInlinedReturns(CompileInfo* calleeCompileInfo,
3458                                               CallInfo& callInfo,
3459                                               MIRGraphReturns& exits,
3460                                               MBasicBlock* returnBlock) {
3461   if (exits.length() == 1) {
3462     return patchInlinedReturn(calleeCompileInfo, callInfo, exits[0],
3463                               returnBlock);
3464   }
3465 
3466   // Accumulate multiple returns with a phi.
3467   MPhi* phi = MPhi::New(alloc());
3468   if (!phi->reserveLength(exits.length())) {
3469     return nullptr;
3470   }
3471 
3472   for (auto* exit : exits) {
3473     MDefinition* rdef =
3474         patchInlinedReturn(calleeCompileInfo, callInfo, exit, returnBlock);
3475     if (!rdef) {
3476       return nullptr;
3477     }
3478     phi->addInput(rdef);
3479   }
3480   returnBlock->addPhi(phi);
3481   return phi;
3482 }
3483 
patchInlinedReturn(CompileInfo * calleeCompileInfo,CallInfo & callInfo,MBasicBlock * exit,MBasicBlock * returnBlock)3484 MDefinition* WarpBuilder::patchInlinedReturn(CompileInfo* calleeCompileInfo,
3485                                              CallInfo& callInfo,
3486                                              MBasicBlock* exit,
3487                                              MBasicBlock* returnBlock) {
3488   // Replace the MReturn in the exit block with an MGoto branching to
3489   // the return block.
3490   MDefinition* rdef = exit->lastIns()->toReturn()->input();
3491   exit->discardLastIns();
3492 
3493   // Constructors must be patched by the caller to always return an object.
3494   // Derived class constructors contain extra bytecode to ensure an object
3495   // is always returned, so no additional patching is needed.
3496   if (callInfo.constructing() &&
3497       !calleeCompileInfo->isDerivedClassConstructor()) {
3498     auto* filter = MReturnFromCtor::New(alloc(), rdef, callInfo.thisArg());
3499     exit->add(filter);
3500     rdef = filter;
3501   } else if (callInfo.isSetter()) {
3502     // Setters return the rhs argument, not whatever value is returned.
3503     rdef = callInfo.getArg(0);
3504   }
3505 
3506   exit->end(MGoto::New(alloc(), returnBlock));
3507   if (!returnBlock->addPredecessorWithoutPhis(exit)) {
3508     return nullptr;
3509   }
3510 
3511   return rdef;
3512 }
3513