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