1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "jit/BaselineCompiler.h"
8 
9 #include "mozilla/Casting.h"
10 
11 #include "jit/BaselineIC.h"
12 #include "jit/BaselineJIT.h"
13 #include "jit/FixedList.h"
14 #include "jit/IonAnalysis.h"
15 #include "jit/JitcodeMap.h"
16 #include "jit/JitSpewer.h"
17 #include "jit/Linker.h"
18 #ifdef JS_ION_PERF
19 #include "jit/PerfSpewer.h"
20 #endif
21 #include "jit/SharedICHelpers.h"
22 #include "jit/VMFunctions.h"
23 #include "js/UniquePtr.h"
24 #include "vm/AsyncFunction.h"
25 #include "vm/AsyncIteration.h"
26 #include "vm/EnvironmentObject.h"
27 #include "vm/Interpreter.h"
28 #include "vm/JSFunction.h"
29 #include "vm/TraceLogging.h"
30 #include "vtune/VTuneWrapper.h"
31 
32 #include "jit/BaselineFrameInfo-inl.h"
33 #include "jit/MacroAssembler-inl.h"
34 #include "vm/Interpreter-inl.h"
35 #include "vm/JSScript-inl.h"
36 #include "vm/NativeObject-inl.h"
37 #include "vm/TypeInference-inl.h"
38 
39 using namespace js;
40 using namespace js::jit;
41 
42 using mozilla::AssertedCast;
43 
BaselineCompiler(JSContext * cx,TempAllocator & alloc,JSScript * script)44 BaselineCompiler::BaselineCompiler(JSContext* cx, TempAllocator& alloc,
45                                    JSScript* script)
46     : BaselineCompilerSpecific(cx, alloc, script),
47       yieldAndAwaitOffsets_(cx),
48       modifiesArguments_(false) {}
49 
init()50 bool BaselineCompiler::init() {
51   if (!analysis_.init(alloc_, cx->caches().gsnCache)) return false;
52 
53   if (!labels_.init(alloc_, script->length())) return false;
54 
55   for (size_t i = 0; i < script->length(); i++) new (&labels_[i]) Label();
56 
57   if (!frame.init(alloc_)) return false;
58 
59   return true;
60 }
61 
addPCMappingEntry(bool addIndexEntry)62 bool BaselineCompiler::addPCMappingEntry(bool addIndexEntry) {
63   // Don't add multiple entries for a single pc.
64   size_t nentries = pcMappingEntries_.length();
65   if (nentries > 0 &&
66       pcMappingEntries_[nentries - 1].pcOffset == script->pcToOffset(pc))
67     return true;
68 
69   PCMappingEntry entry;
70   entry.pcOffset = script->pcToOffset(pc);
71   entry.nativeOffset = masm.currentOffset();
72   entry.slotInfo = getStackTopSlotInfo();
73   entry.addIndexEntry = addIndexEntry;
74 
75   return pcMappingEntries_.append(entry);
76 }
77 
compile()78 MethodStatus BaselineCompiler::compile() {
79   JitSpew(JitSpew_BaselineScripts, "Baseline compiling script %s:%zu (%p)",
80           script->filename(), script->lineno(), script);
81 
82   JitSpew(JitSpew_Codegen, "# Emitting baseline code for script %s:%zu",
83           script->filename(), script->lineno());
84 
85   TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
86   TraceLoggerEvent scriptEvent(TraceLogger_AnnotateScripts, script);
87   AutoTraceLog logScript(logger, scriptEvent);
88   AutoTraceLog logCompile(logger, TraceLogger_BaselineCompilation);
89 
90   AutoKeepTypeScripts keepTypes(cx);
91   if (!script->ensureHasTypes(cx, keepTypes) ||
92       !script->ensureHasAnalyzedArgsUsage(cx))
93     return Method_Error;
94 
95   // When code coverage is only enabled for optimizations, or when a Debugger
96   // set the collectCoverageInfo flag, we have to create the ScriptCounts if
97   // they do not exist.
98   if (!script->hasScriptCounts() && cx->compartment()->collectCoverage()) {
99     if (!script->initScriptCounts(cx)) return Method_Error;
100   }
101 
102   // Pin analysis info during compilation.
103   AutoEnterAnalysis autoEnterAnalysis(cx);
104 
105   MOZ_ASSERT(!script->hasBaselineScript());
106 
107   if (!emitPrologue()) return Method_Error;
108 
109   MethodStatus status = emitBody();
110   if (status != Method_Compiled) return status;
111 
112   if (!emitEpilogue()) return Method_Error;
113 
114   if (!emitOutOfLinePostBarrierSlot()) return Method_Error;
115 
116   Linker linker(masm);
117   if (masm.oom()) {
118     ReportOutOfMemory(cx);
119     return Method_Error;
120   }
121 
122   AutoFlushICache afc("Baseline");
123   JitCode* code = linker.newCode(cx, CodeKind::Baseline);
124   if (!code) return Method_Error;
125 
126   Rooted<EnvironmentObject*> templateEnv(cx);
127   if (script->functionNonDelazifying()) {
128     RootedFunction fun(cx, script->functionNonDelazifying());
129 
130     if (fun->needsNamedLambdaEnvironment()) {
131       templateEnv =
132           NamedLambdaObject::createTemplateObject(cx, fun, gc::TenuredHeap);
133       if (!templateEnv) return Method_Error;
134     }
135 
136     if (fun->needsCallObject()) {
137       RootedScript scriptRoot(cx, script);
138       templateEnv = CallObject::createTemplateObject(
139           cx, scriptRoot, templateEnv, gc::TenuredHeap);
140       if (!templateEnv) return Method_Error;
141     }
142   }
143 
144   // Encode the pc mapping table. See PCMappingIndexEntry for
145   // more information.
146   Vector<PCMappingIndexEntry> pcMappingIndexEntries(cx);
147   CompactBufferWriter pcEntries;
148   uint32_t previousOffset = 0;
149 
150   for (size_t i = 0; i < pcMappingEntries_.length(); i++) {
151     PCMappingEntry& entry = pcMappingEntries_[i];
152 
153     if (entry.addIndexEntry) {
154       PCMappingIndexEntry indexEntry;
155       indexEntry.pcOffset = entry.pcOffset;
156       indexEntry.nativeOffset = entry.nativeOffset;
157       indexEntry.bufferOffset = pcEntries.length();
158       if (!pcMappingIndexEntries.append(indexEntry)) {
159         ReportOutOfMemory(cx);
160         return Method_Error;
161       }
162       previousOffset = entry.nativeOffset;
163     }
164 
165     // Use the high bit of the SlotInfo byte to indicate the
166     // native code offset (relative to the previous op) > 0 and
167     // comes next in the buffer.
168     MOZ_ASSERT((entry.slotInfo.toByte() & 0x80) == 0);
169 
170     if (entry.nativeOffset == previousOffset) {
171       pcEntries.writeByte(entry.slotInfo.toByte());
172     } else {
173       MOZ_ASSERT(entry.nativeOffset > previousOffset);
174       pcEntries.writeByte(0x80 | entry.slotInfo.toByte());
175       pcEntries.writeUnsigned(entry.nativeOffset - previousOffset);
176     }
177 
178     previousOffset = entry.nativeOffset;
179   }
180 
181   if (pcEntries.oom()) {
182     ReportOutOfMemory(cx);
183     return Method_Error;
184   }
185 
186   // Note: There is an extra entry in the bytecode type map for the search hint,
187   // see below.
188   size_t bytecodeTypeMapEntries = script->nTypeSets() + 1;
189   UniquePtr<BaselineScript> baselineScript(
190       BaselineScript::New(
191           script, prologueOffset_.offset(), epilogueOffset_.offset(),
192           profilerEnterFrameToggleOffset_.offset(),
193           profilerExitFrameToggleOffset_.offset(),
194           postDebugPrologueOffset_.offset(), icEntries_.length(),
195           pcMappingIndexEntries.length(), pcEntries.length(),
196           bytecodeTypeMapEntries, yieldAndAwaitOffsets_.length(),
197           traceLoggerToggleOffsets_.length()),
198       JS::DeletePolicy<BaselineScript>(cx->runtime()));
199   if (!baselineScript) {
200     ReportOutOfMemory(cx);
201     return Method_Error;
202   }
203 
204   baselineScript->setMethod(code);
205   baselineScript->setTemplateEnvironment(templateEnv);
206 
207   JitSpew(JitSpew_BaselineScripts,
208           "Created BaselineScript %p (raw %p) for %s:%zu",
209           (void*)baselineScript.get(), (void*)code->raw(), script->filename(),
210           script->lineno());
211 
212   MOZ_ASSERT(pcMappingIndexEntries.length() > 0);
213   baselineScript->copyPCMappingIndexEntries(&pcMappingIndexEntries[0]);
214 
215   MOZ_ASSERT(pcEntries.length() > 0);
216   baselineScript->copyPCMappingEntries(pcEntries);
217 
218   // Copy IC entries
219   if (icEntries_.length())
220     baselineScript->copyICEntries(script, &icEntries_[0]);
221 
222   // Adopt fallback stubs from the compiler into the baseline script.
223   baselineScript->adoptFallbackStubs(&stubSpace_);
224 
225   // If profiler instrumentation is enabled, toggle instrumentation on.
226   if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(
227           cx->runtime()))
228     baselineScript->toggleProfilerInstrumentation(true);
229 
230   // Patch IC loads using IC entries.
231   for (size_t i = 0; i < icLoadLabels_.length(); i++) {
232     CodeOffset label = icLoadLabels_[i].label;
233     size_t icEntry = icLoadLabels_[i].icEntry;
234     BaselineICEntry* entryAddr = &(baselineScript->icEntry(icEntry));
235     Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, label),
236                                        ImmPtr(entryAddr), ImmPtr((void*)-1));
237   }
238 
239   if (modifiesArguments_) baselineScript->setModifiesArguments();
240   if (analysis_.usesEnvironmentChain())
241     baselineScript->setUsesEnvironmentChain();
242 
243 #ifdef JS_TRACE_LOGGING
244   // Initialize the tracelogger instrumentation.
245   baselineScript->initTraceLogger(script, traceLoggerToggleOffsets_);
246 #endif
247 
248   uint32_t* bytecodeMap = baselineScript->bytecodeTypeMap();
249   FillBytecodeTypeMap(script, bytecodeMap);
250 
251   // The last entry in the last index found, and is used to avoid binary
252   // searches for the sought entry when queries are in linear order.
253   bytecodeMap[script->nTypeSets()] = 0;
254 
255   baselineScript->copyYieldAndAwaitEntries(script, yieldAndAwaitOffsets_);
256 
257   if (compileDebugInstrumentation_)
258     baselineScript->setHasDebugInstrumentation();
259 
260   // Always register a native => bytecode mapping entry, since profiler can be
261   // turned on with baseline jitcode on stack, and baseline jitcode cannot be
262   // invalidated.
263   {
264     JitSpew(JitSpew_Profiling,
265             "Added JitcodeGlobalEntry for baseline script %s:%zu (%p)",
266             script->filename(), script->lineno(), baselineScript.get());
267 
268     // Generate profiling string.
269     char* str = JitcodeGlobalEntry::createScriptString(cx, script);
270     if (!str) return Method_Error;
271 
272     JitcodeGlobalEntry::BaselineEntry entry;
273     entry.init(code, code->raw(), code->rawEnd(), script, str);
274 
275     JitcodeGlobalTable* globalTable =
276         cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
277     if (!globalTable->addEntry(entry)) {
278       entry.destroy();
279       ReportOutOfMemory(cx);
280       return Method_Error;
281     }
282 
283     // Mark the jitcode as having a bytecode map.
284     code->setHasBytecodeMap();
285   }
286 
287   script->setBaselineScript(cx->runtime(), baselineScript.release());
288 
289 #ifdef JS_ION_PERF
290   writePerfSpewerBaselineProfile(script, code);
291 #endif
292 
293 #ifdef MOZ_VTUNE
294   vtune::MarkScript(code, script, "baseline");
295 #endif
296 
297   return Method_Compiled;
298 }
299 
emitInitializeLocals()300 void BaselineCompiler::emitInitializeLocals() {
301   // Initialize all locals to |undefined|. Lexical bindings are temporal
302   // dead zoned in bytecode.
303 
304   size_t n = frame.nlocals();
305   if (n == 0) return;
306 
307   // Use R0 to minimize code size. If the number of locals to push is <
308   // LOOP_UNROLL_FACTOR, then the initialization pushes are emitted directly
309   // and inline.  Otherwise, they're emitted in a partially unrolled loop.
310   static const size_t LOOP_UNROLL_FACTOR = 4;
311   size_t toPushExtra = n % LOOP_UNROLL_FACTOR;
312 
313   masm.moveValue(UndefinedValue(), R0);
314 
315   // Handle any extra pushes left over by the optional unrolled loop below.
316   for (size_t i = 0; i < toPushExtra; i++) masm.pushValue(R0);
317 
318   // Partially unrolled loop of pushes.
319   if (n >= LOOP_UNROLL_FACTOR) {
320     size_t toPush = n - toPushExtra;
321     MOZ_ASSERT(toPush % LOOP_UNROLL_FACTOR == 0);
322     MOZ_ASSERT(toPush >= LOOP_UNROLL_FACTOR);
323     masm.move32(Imm32(toPush), R1.scratchReg());
324     // Emit unrolled loop with 4 pushes per iteration.
325     Label pushLoop;
326     masm.bind(&pushLoop);
327     for (size_t i = 0; i < LOOP_UNROLL_FACTOR; i++) masm.pushValue(R0);
328     masm.branchSub32(Assembler::NonZero, Imm32(LOOP_UNROLL_FACTOR),
329                      R1.scratchReg(), &pushLoop);
330   }
331 }
332 
emitPrologue()333 bool BaselineCompiler::emitPrologue() {
334 #ifdef JS_USE_LINK_REGISTER
335   // Push link register from generateEnterJIT()'s BLR.
336   masm.pushReturnAddress();
337   masm.checkStackAlignment();
338 #endif
339   emitProfilerEnterFrame();
340 
341   masm.push(BaselineFrameReg);
342   masm.moveStackPtrTo(BaselineFrameReg);
343   masm.subFromStackPtr(Imm32(BaselineFrame::Size()));
344 
345   // Initialize BaselineFrame. For eval scripts, the env chain
346   // is passed in R1, so we have to be careful not to clobber it.
347 
348   // Initialize BaselineFrame::flags.
349   masm.store32(Imm32(0), frame.addressOfFlags());
350 
351   // Handle env chain pre-initialization (in case GC gets run
352   // during stack check).  For global and eval scripts, the env
353   // chain is in R1.  For function scripts, the env chain is in
354   // the callee, nullptr is stored for now so that GC doesn't choke
355   // on a bogus EnvironmentChain value in the frame.
356   if (function())
357     masm.storePtr(ImmPtr(nullptr), frame.addressOfEnvironmentChain());
358   else
359     masm.storePtr(R1.scratchReg(), frame.addressOfEnvironmentChain());
360 
361   // Functions with a large number of locals require two stack checks.
362   // The VMCall for a fallible stack check can only occur after the
363   // env chain has been initialized, as that is required for proper
364   // exception handling if the VMCall returns false.  The env chain
365   // initialization can only happen after the UndefinedValues for the
366   // local slots have been pushed.
367   // However by that time, the stack might have grown too much.
368   // In these cases, we emit an extra, early, infallible check
369   // before pushing the locals.  The early check sets a flag on the
370   // frame if the stack check fails (but otherwise doesn't throw an
371   // exception).  If the flag is set, then the jitcode skips past
372   // the pushing of the locals, and directly to env chain initialization
373   // followed by the actual stack check, which will throw the correct
374   // exception.
375   Label earlyStackCheckFailed;
376   if (needsEarlyStackCheck()) {
377     if (!emitStackCheck(/* earlyCheck = */ true)) return false;
378     masm.branchTest32(Assembler::NonZero, frame.addressOfFlags(),
379                       Imm32(BaselineFrame::OVER_RECURSED),
380                       &earlyStackCheckFailed);
381   }
382 
383   emitInitializeLocals();
384 
385   if (needsEarlyStackCheck()) masm.bind(&earlyStackCheckFailed);
386 
387 #ifdef JS_TRACE_LOGGING
388   if (!emitTraceLoggerEnter()) return false;
389 #endif
390 
391   // Record the offset of the prologue, because Ion can bailout before
392   // the env chain is initialized.
393   prologueOffset_ = CodeOffset(masm.currentOffset());
394 
395   // When compiling with Debugger instrumentation, set the debuggeeness of
396   // the frame before any operation that can call into the VM.
397   emitIsDebuggeeCheck();
398 
399   // Initialize the env chain before any operation that may
400   // call into the VM and trigger a GC.
401   if (!initEnvironmentChain()) return false;
402 
403   if (!emitStackCheck()) return false;
404 
405   if (!emitDebugPrologue()) return false;
406 
407   if (!emitWarmUpCounterIncrement()) return false;
408 
409   if (!emitArgumentTypeChecks()) return false;
410 
411   return true;
412 }
413 
emitEpilogue()414 bool BaselineCompiler::emitEpilogue() {
415   // Record the offset of the epilogue, so we can do early return from
416   // Debugger handlers during on-stack recompile.
417   epilogueOffset_ = CodeOffset(masm.currentOffset());
418 
419   masm.bind(&return_);
420 
421 #ifdef JS_TRACE_LOGGING
422   if (!emitTraceLoggerExit()) return false;
423 #endif
424 
425   masm.moveToStackPtr(BaselineFrameReg);
426   masm.pop(BaselineFrameReg);
427 
428   emitProfilerExitFrame();
429 
430   masm.ret();
431   return true;
432 }
433 
434 // On input:
435 //  R2.scratchReg() contains object being written to.
436 //  Called with the baseline stack synced, except for R0 which is preserved.
437 //  All other registers are usable as scratch.
438 // This calls:
439 //    void PostWriteBarrier(JSRuntime* rt, JSObject* obj);
emitOutOfLinePostBarrierSlot()440 bool BaselineCompiler::emitOutOfLinePostBarrierSlot() {
441   masm.bind(&postBarrierSlot_);
442 
443   Register objReg = R2.scratchReg();
444   AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
445   regs.take(R0);
446   regs.take(objReg);
447   regs.take(BaselineFrameReg);
448   Register scratch = regs.takeAny();
449 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
450   // On ARM, save the link register before calling.  It contains the return
451   // address.  The |masm.ret()| later will pop this into |pc| to return.
452   masm.push(lr);
453 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
454   masm.push(ra);
455 #endif
456   masm.pushValue(R0);
457 
458   masm.setupUnalignedABICall(scratch);
459   masm.movePtr(ImmPtr(cx->runtime()), scratch);
460   masm.passABIArg(scratch);
461   masm.passABIArg(objReg);
462   masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier));
463 
464   masm.popValue(R0);
465   masm.ret();
466   return true;
467 }
468 
emitIC(ICStub * stub,ICEntry::Kind kind)469 bool BaselineCompiler::emitIC(ICStub* stub, ICEntry::Kind kind) {
470   BaselineICEntry* entry = allocateICEntry(stub, kind);
471   if (!entry) return false;
472 
473   CodeOffset patchOffset;
474   EmitCallIC(&patchOffset, masm);
475   entry->setReturnOffset(CodeOffset(masm.currentOffset()));
476   if (!addICLoadLabel(patchOffset)) return false;
477 
478   return true;
479 }
480 
481 typedef bool (*CheckOverRecursedWithExtraFn)(JSContext*, BaselineFrame*,
482                                              uint32_t, uint32_t);
483 static const VMFunction CheckOverRecursedWithExtraInfo =
484     FunctionInfo<CheckOverRecursedWithExtraFn>(CheckOverRecursedWithExtra,
485                                                "CheckOverRecursedWithExtra");
486 
emitStackCheck(bool earlyCheck)487 bool BaselineCompiler::emitStackCheck(bool earlyCheck) {
488   Label skipCall;
489   uint32_t slotsSize = script->nslots() * sizeof(Value);
490   uint32_t tolerance = earlyCheck ? slotsSize : 0;
491 
492   masm.moveStackPtrTo(R1.scratchReg());
493 
494   // If this is the early stack check, locals haven't been pushed yet.  Adjust
495   // the stack pointer to account for the locals that would be pushed before
496   // performing the guard around the vmcall to the stack check.
497   if (earlyCheck) masm.subPtr(Imm32(tolerance), R1.scratchReg());
498 
499   // If this is the late stack check for a frame which contains an early stack
500   // check, then the early stack check might have failed and skipped past the
501   // pushing of locals on the stack.
502   //
503   // If this is a possibility, then the OVER_RECURSED flag should be checked,
504   // and the VMCall to CheckOverRecursed done unconditionally if it's set.
505   Label forceCall;
506   if (!earlyCheck && needsEarlyStackCheck()) {
507     masm.branchTest32(Assembler::NonZero, frame.addressOfFlags(),
508                       Imm32(BaselineFrame::OVER_RECURSED), &forceCall);
509   }
510 
511   void* contextAddr = cx->zone()->group()->addressOfOwnerContext();
512   masm.loadPtr(AbsoluteAddress(contextAddr), R0.scratchReg());
513   masm.branchPtr(Assembler::BelowOrEqual,
514                  Address(R0.scratchReg(), offsetof(JSContext, jitStackLimit)),
515                  R1.scratchReg(), &skipCall);
516 
517   if (!earlyCheck && needsEarlyStackCheck()) masm.bind(&forceCall);
518 
519   prepareVMCall();
520   pushArg(Imm32(earlyCheck));
521   pushArg(Imm32(tolerance));
522   masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
523   pushArg(R1.scratchReg());
524 
525   CallVMPhase phase = POST_INITIALIZE;
526   if (earlyCheck)
527     phase = PRE_INITIALIZE;
528   else if (needsEarlyStackCheck())
529     phase = CHECK_OVER_RECURSED;
530 
531   if (!callVMNonOp(CheckOverRecursedWithExtraInfo, phase)) return false;
532 
533   icEntries_.back().setFakeKind(earlyCheck ? ICEntry::Kind_EarlyStackCheck
534                                            : ICEntry::Kind_StackCheck);
535 
536   masm.bind(&skipCall);
537   return true;
538 }
539 
emitIsDebuggeeCheck()540 void BaselineCompiler::emitIsDebuggeeCheck() {
541   if (compileDebugInstrumentation_) {
542     masm.Push(BaselineFrameReg);
543     masm.setupUnalignedABICall(R0.scratchReg());
544     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
545     masm.passABIArg(R0.scratchReg());
546     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::FrameIsDebuggeeCheck));
547     masm.Pop(BaselineFrameReg);
548   }
549 }
550 
551 typedef bool (*DebugPrologueFn)(JSContext*, BaselineFrame*, jsbytecode*, bool*);
552 static const VMFunction DebugPrologueInfo =
553     FunctionInfo<DebugPrologueFn>(jit::DebugPrologue, "DebugPrologue");
554 
emitDebugPrologue()555 bool BaselineCompiler::emitDebugPrologue() {
556   if (compileDebugInstrumentation_) {
557     // Load pointer to BaselineFrame in R0.
558     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
559 
560     prepareVMCall();
561     pushArg(ImmPtr(pc));
562     pushArg(R0.scratchReg());
563     if (!callVM(DebugPrologueInfo)) return false;
564 
565     // Fix up the fake ICEntry appended by callVM for on-stack recompilation.
566     icEntries_.back().setFakeKind(ICEntry::Kind_DebugPrologue);
567 
568     // If the stub returns |true|, we have to return the value stored in the
569     // frame's return value slot.
570     Label done;
571     masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &done);
572     {
573       masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
574       masm.jump(&return_);
575     }
576     masm.bind(&done);
577   }
578 
579   postDebugPrologueOffset_ = CodeOffset(masm.currentOffset());
580 
581   return true;
582 }
583 
584 typedef bool (*CheckGlobalOrEvalDeclarationConflictsFn)(JSContext*,
585                                                         BaselineFrame*);
586 static const VMFunction CheckGlobalOrEvalDeclarationConflictsInfo =
587     FunctionInfo<CheckGlobalOrEvalDeclarationConflictsFn>(
588         jit::CheckGlobalOrEvalDeclarationConflicts,
589         "CheckGlobalOrEvalDeclarationConflicts");
590 
591 typedef bool (*InitFunctionEnvironmentObjectsFn)(JSContext*, BaselineFrame*);
592 static const VMFunction InitFunctionEnvironmentObjectsInfo =
593     FunctionInfo<InitFunctionEnvironmentObjectsFn>(
594         jit::InitFunctionEnvironmentObjects, "InitFunctionEnvironmentObjects");
595 
initEnvironmentChain()596 bool BaselineCompiler::initEnvironmentChain() {
597   CallVMPhase phase = POST_INITIALIZE;
598   if (needsEarlyStackCheck()) phase = CHECK_OVER_RECURSED;
599 
600   RootedFunction fun(cx, function());
601   if (fun) {
602     // Use callee->environment as env chain. Note that we do this also
603     // for needsSomeEnvironmentObject functions, so that the env chain
604     // slot is properly initialized if the call triggers GC.
605     Register callee = R0.scratchReg();
606     Register scope = R1.scratchReg();
607     masm.loadFunctionFromCalleeToken(frame.addressOfCalleeToken(), callee);
608     masm.loadPtr(Address(callee, JSFunction::offsetOfEnvironment()), scope);
609     masm.storePtr(scope, frame.addressOfEnvironmentChain());
610 
611     if (fun->needsFunctionEnvironmentObjects()) {
612       // Call into the VM to create the proper environment objects.
613       prepareVMCall();
614 
615       masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
616       pushArg(R0.scratchReg());
617 
618       if (!callVMNonOp(InitFunctionEnvironmentObjectsInfo, phase)) return false;
619     }
620   } else if (module()) {
621     // Modules use a pre-created scope object.
622     Register scope = R1.scratchReg();
623     masm.movePtr(ImmGCPtr(&module()->initialEnvironment()), scope);
624     masm.storePtr(scope, frame.addressOfEnvironmentChain());
625   } else {
626     // EnvironmentChain pointer in BaselineFrame has already been initialized
627     // in prologue, but we need to check for redeclaration errors.
628 
629     prepareVMCall();
630     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
631     pushArg(R0.scratchReg());
632 
633     if (!callVMNonOp(CheckGlobalOrEvalDeclarationConflictsInfo, phase))
634       return false;
635   }
636 
637   return true;
638 }
639 
640 typedef bool (*InterruptCheckFn)(JSContext*);
641 static const VMFunction InterruptCheckInfo =
642     FunctionInfo<InterruptCheckFn>(InterruptCheck, "InterruptCheck");
643 
emitInterruptCheck()644 bool BaselineCompiler::emitInterruptCheck() {
645   frame.syncStack(0);
646 
647   Label done;
648   void* context = cx->zone()->group()->addressOfOwnerContext();
649   masm.loadPtr(AbsoluteAddress(context), R0.scratchReg());
650   masm.branch32(Assembler::Equal,
651                 Address(R0.scratchReg(), offsetof(JSContext, interrupt_)),
652                 Imm32(0), &done);
653 
654   prepareVMCall();
655   if (!callVM(InterruptCheckInfo)) return false;
656 
657   masm.bind(&done);
658   return true;
659 }
660 
661 typedef bool (*IonCompileScriptForBaselineFn)(JSContext*, BaselineFrame*,
662                                               jsbytecode*);
663 static const VMFunction IonCompileScriptForBaselineInfo =
664     FunctionInfo<IonCompileScriptForBaselineFn>(IonCompileScriptForBaseline,
665                                                 "IonCompileScriptForBaseline");
666 
emitWarmUpCounterIncrement(bool allowOsr)667 bool BaselineCompiler::emitWarmUpCounterIncrement(bool allowOsr) {
668   // Emit no warm-up counter increments or bailouts if Ion is not
669   // enabled, or if the script will never be Ion-compileable
670 
671   if (!ionCompileable_) return true;
672 
673   frame.assertSyncedStack();
674 
675   Register scriptReg = R2.scratchReg();
676   Register countReg = R0.scratchReg();
677   Address warmUpCounterAddr(scriptReg, JSScript::offsetOfWarmUpCounter());
678 
679   masm.movePtr(ImmGCPtr(script), scriptReg);
680   masm.load32(warmUpCounterAddr, countReg);
681   masm.add32(Imm32(1), countReg);
682   masm.store32(countReg, warmUpCounterAddr);
683 
684   // If this is a loop inside a catch or finally block, increment the warmup
685   // counter but don't attempt OSR (Ion only compiles the try block).
686   if (analysis_.info(pc).loopEntryInCatchOrFinally) {
687     MOZ_ASSERT(JSOp(*pc) == JSOP_LOOPENTRY);
688     return true;
689   }
690 
691   // OSR not possible at this loop entry.
692   if (!allowOsr) {
693     MOZ_ASSERT(JSOp(*pc) == JSOP_LOOPENTRY);
694     return true;
695   }
696 
697   Label skipCall;
698 
699   const OptimizationInfo* info =
700       IonOptimizations.get(IonOptimizations.firstLevel());
701   uint32_t warmUpThreshold = info->compilerWarmUpThreshold(script, pc);
702   masm.branch32(Assembler::LessThan, countReg, Imm32(warmUpThreshold),
703                 &skipCall);
704 
705   masm.branchPtr(Assembler::Equal,
706                  Address(scriptReg, JSScript::offsetOfIonScript()),
707                  ImmPtr(ION_COMPILING_SCRIPT), &skipCall);
708 
709   // Try to compile and/or finish a compilation.
710   if (JSOp(*pc) == JSOP_LOOPENTRY) {
711     // During the loop entry we can try to OSR into ion.
712     // The ic has logic for this.
713     ICWarmUpCounter_Fallback::Compiler stubCompiler(cx);
714     if (!emitNonOpIC(stubCompiler.getStub(&stubSpace_))) return false;
715   } else {
716     // To call stubs we need to have an opcode. This code handles the
717     // prologue and there is no dedicatd opcode present. Therefore use an
718     // annotated vm call.
719     prepareVMCall();
720 
721     masm.Push(ImmPtr(pc));
722     masm.PushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
723 
724     if (!callVM(IonCompileScriptForBaselineInfo)) return false;
725 
726     // Annotate the ICEntry as warmup counter.
727     icEntries_.back().setFakeKind(ICEntry::Kind_WarmupCounter);
728   }
729   masm.bind(&skipCall);
730 
731   return true;
732 }
733 
emitArgumentTypeChecks()734 bool BaselineCompiler::emitArgumentTypeChecks() {
735   if (!function()) return true;
736 
737   frame.pushThis();
738   frame.popRegsAndSync(1);
739 
740   ICTypeMonitor_Fallback::Compiler compiler(cx, uint32_t(0));
741   if (!emitNonOpIC(compiler.getStub(&stubSpace_))) return false;
742 
743   for (size_t i = 0; i < function()->nargs(); i++) {
744     frame.pushArg(i);
745     frame.popRegsAndSync(1);
746 
747     ICTypeMonitor_Fallback::Compiler compiler(cx, i + 1);
748     if (!emitNonOpIC(compiler.getStub(&stubSpace_))) return false;
749   }
750 
751   return true;
752 }
753 
emitDebugTrap()754 bool BaselineCompiler::emitDebugTrap() {
755   MOZ_ASSERT(compileDebugInstrumentation_);
756   MOZ_ASSERT(frame.numUnsyncedSlots() == 0);
757 
758   bool enabled = script->stepModeEnabled() || script->hasBreakpointsAt(pc);
759 
760   // Emit patchable call to debug trap handler.
761   JitCode* handler = cx->runtime()->jitRuntime()->debugTrapHandler(cx);
762   if (!handler) return false;
763   mozilla::DebugOnly<CodeOffset> offset = masm.toggledCall(handler, enabled);
764 
765 #ifdef DEBUG
766   // Patchable call offset has to match the pc mapping offset.
767   PCMappingEntry& entry = pcMappingEntries_.back();
768   MOZ_ASSERT((&offset)->offset() == entry.nativeOffset);
769 #endif
770 
771   // Add an IC entry for the return offset -> pc mapping.
772   return appendICEntry(ICEntry::Kind_DebugTrap, masm.currentOffset());
773 }
774 
775 #ifdef JS_TRACE_LOGGING
emitTraceLoggerEnter()776 bool BaselineCompiler::emitTraceLoggerEnter() {
777   AllocatableRegisterSet regs(RegisterSet::Volatile());
778   Register loggerReg = regs.takeAnyGeneral();
779   Register scriptReg = regs.takeAnyGeneral();
780 
781   Label noTraceLogger;
782   if (!traceLoggerToggleOffsets_.append(masm.toggledJump(&noTraceLogger)))
783     return false;
784 
785   masm.Push(loggerReg);
786   masm.Push(scriptReg);
787 
788   masm.loadTraceLogger(loggerReg);
789 
790   // Script start.
791   masm.movePtr(ImmGCPtr(script), scriptReg);
792   masm.loadPtr(Address(scriptReg, JSScript::offsetOfBaselineScript()),
793                scriptReg);
794   Address scriptEvent(scriptReg,
795                       BaselineScript::offsetOfTraceLoggerScriptEvent());
796   masm.computeEffectiveAddress(scriptEvent, scriptReg);
797   masm.tracelogStartEvent(loggerReg, scriptReg);
798 
799   // Engine start.
800   masm.tracelogStartId(loggerReg, TraceLogger_Baseline, /* force = */ true);
801 
802   masm.Pop(scriptReg);
803   masm.Pop(loggerReg);
804 
805   masm.bind(&noTraceLogger);
806 
807   return true;
808 }
809 
emitTraceLoggerExit()810 bool BaselineCompiler::emitTraceLoggerExit() {
811   AllocatableRegisterSet regs(RegisterSet::Volatile());
812   Register loggerReg = regs.takeAnyGeneral();
813 
814   Label noTraceLogger;
815   if (!traceLoggerToggleOffsets_.append(masm.toggledJump(&noTraceLogger)))
816     return false;
817 
818   masm.Push(loggerReg);
819   masm.loadTraceLogger(loggerReg);
820 
821   masm.tracelogStopId(loggerReg, TraceLogger_Baseline, /* force = */ true);
822   masm.tracelogStopId(loggerReg, TraceLogger_Scripts, /* force = */ true);
823 
824   masm.Pop(loggerReg);
825 
826   masm.bind(&noTraceLogger);
827 
828   return true;
829 }
830 
emitTraceLoggerResume(Register baselineScript,AllocatableGeneralRegisterSet & regs)831 bool BaselineCompiler::emitTraceLoggerResume(
832     Register baselineScript, AllocatableGeneralRegisterSet& regs) {
833   Register scriptId = regs.takeAny();
834   Register loggerReg = regs.takeAny();
835 
836   Label noTraceLogger;
837   if (!traceLoggerToggleOffsets_.append(masm.toggledJump(&noTraceLogger)))
838     return false;
839 
840   masm.loadTraceLogger(loggerReg);
841 
842   Address scriptEvent(baselineScript,
843                       BaselineScript::offsetOfTraceLoggerScriptEvent());
844   masm.computeEffectiveAddress(scriptEvent, scriptId);
845   masm.tracelogStartEvent(loggerReg, scriptId);
846   masm.tracelogStartId(loggerReg, TraceLogger_Baseline, /* force = */ true);
847 
848   regs.add(loggerReg);
849   regs.add(scriptId);
850 
851   masm.bind(&noTraceLogger);
852 
853   return true;
854 }
855 #endif
856 
emitProfilerEnterFrame()857 void BaselineCompiler::emitProfilerEnterFrame() {
858   // Store stack position to lastProfilingFrame variable, guarded by a toggled
859   // jump. Starts off initially disabled.
860   Label noInstrument;
861   CodeOffset toggleOffset = masm.toggledJump(&noInstrument);
862   masm.profilerEnterFrame(masm.getStackPointer(), R0.scratchReg());
863   masm.bind(&noInstrument);
864 
865   // Store the start offset in the appropriate location.
866   MOZ_ASSERT(!profilerEnterFrameToggleOffset_.bound());
867   profilerEnterFrameToggleOffset_ = toggleOffset;
868 }
869 
emitProfilerExitFrame()870 void BaselineCompiler::emitProfilerExitFrame() {
871   // Store previous frame to lastProfilingFrame variable, guarded by a toggled
872   // jump. Starts off initially disabled.
873   Label noInstrument;
874   CodeOffset toggleOffset = masm.toggledJump(&noInstrument);
875   masm.profilerExitFrame();
876   masm.bind(&noInstrument);
877 
878   // Store the start offset in the appropriate location.
879   MOZ_ASSERT(!profilerExitFrameToggleOffset_.bound());
880   profilerExitFrameToggleOffset_ = toggleOffset;
881 }
882 
emitBody()883 MethodStatus BaselineCompiler::emitBody() {
884   MOZ_ASSERT(pc == script->code());
885 
886   bool lastOpUnreachable = false;
887   uint32_t emittedOps = 0;
888   mozilla::DebugOnly<jsbytecode*> prevpc = pc;
889 
890   while (true) {
891     JSOp op = JSOp(*pc);
892     JitSpew(JitSpew_BaselineOp, "Compiling op @ %d: %s",
893             int(script->pcToOffset(pc)), CodeName[op]);
894 
895     BytecodeInfo* info = analysis_.maybeInfo(pc);
896 
897     // Skip unreachable ops.
898     if (!info) {
899       // Test if last instructions and stop emitting in that case.
900       pc += GetBytecodeLength(pc);
901       if (pc >= script->codeEnd()) break;
902 
903       lastOpUnreachable = true;
904       prevpc = pc;
905       continue;
906     }
907 
908     if (info->jumpTarget) {
909       // Fully sync the stack if there are incoming jumps.
910       frame.syncStack(0);
911       frame.setStackDepth(info->stackDepth);
912       masm.bind(labelOf(pc));
913     } else if (MOZ_UNLIKELY(compileDebugInstrumentation_)) {
914       // Also fully sync the stack if the debugger is enabled.
915       frame.syncStack(0);
916     } else {
917       // At the beginning of any op, at most the top 2 stack-values are
918       // unsynced.
919       if (frame.stackDepth() > 2) frame.syncStack(2);
920     }
921 
922     frame.assertValidState(*info);
923 
924     // Add a PC -> native mapping entry for the current op. These entries are
925     // used when we need the native code address for a given pc, for instance
926     // for bailouts from Ion, the debugger and exception handling. See
927     // PCMappingIndexEntry for more information.
928     bool addIndexEntry =
929         (pc == script->code() || lastOpUnreachable || emittedOps > 100);
930     if (addIndexEntry) emittedOps = 0;
931     if (MOZ_UNLIKELY(!addPCMappingEntry(addIndexEntry))) {
932       ReportOutOfMemory(cx);
933       return Method_Error;
934     }
935 
936     // Emit traps for breakpoints and step mode.
937     if (MOZ_UNLIKELY(compileDebugInstrumentation_) && !emitDebugTrap())
938       return Method_Error;
939 
940     switch (op) {
941       // ===== NOT Yet Implemented =====
942       case JSOP_FORCEINTERPRETER:
943         // Intentionally not implemented.
944       case JSOP_SETINTRINSIC:
945         // Run-once opcode during self-hosting initialization.
946       case JSOP_UNUSED126:
947       case JSOP_UNUSED206:
948       case JSOP_UNUSED223:
949       case JSOP_LIMIT:
950         // === !! WARNING WARNING WARNING !! ===
951         // Do you really want to sacrifice performance by not implementing
952         // this operation in the BaselineCompiler?
953         JitSpew(JitSpew_BaselineAbort, "Unhandled op: %s", CodeName[op]);
954         return Method_CantCompile;
955 
956 #define EMIT_OP(OP)                                            \
957   case OP:                                                     \
958     if (MOZ_UNLIKELY(!this->emit_##OP())) return Method_Error; \
959     break;
960         OPCODE_LIST(EMIT_OP)
961 #undef EMIT_OP
962     }
963 
964     // If the main instruction is not a jump target, then we emit the
965     //  corresponding code coverage counter.
966     if (pc == script->main() && !BytecodeIsJumpTarget(op)) {
967       if (!emit_JSOP_JUMPTARGET()) return Method_Error;
968     }
969 
970     // Test if last instructions and stop emitting in that case.
971     pc += GetBytecodeLength(pc);
972     if (pc >= script->codeEnd()) break;
973 
974     emittedOps++;
975     lastOpUnreachable = false;
976 #ifdef DEBUG
977     prevpc = pc;
978 #endif
979   }
980 
981   MOZ_ASSERT(JSOp(*prevpc) == JSOP_RETRVAL);
982   return Method_Compiled;
983 }
984 
emit_JSOP_NOP()985 bool BaselineCompiler::emit_JSOP_NOP() { return true; }
986 
emit_JSOP_ITERNEXT()987 bool BaselineCompiler::emit_JSOP_ITERNEXT() { return true; }
988 
emit_JSOP_NOP_DESTRUCTURING()989 bool BaselineCompiler::emit_JSOP_NOP_DESTRUCTURING() { return true; }
990 
emit_JSOP_TRY_DESTRUCTURING_ITERCLOSE()991 bool BaselineCompiler::emit_JSOP_TRY_DESTRUCTURING_ITERCLOSE() { return true; }
992 
emit_JSOP_LABEL()993 bool BaselineCompiler::emit_JSOP_LABEL() { return true; }
994 
emit_JSOP_POP()995 bool BaselineCompiler::emit_JSOP_POP() {
996   frame.pop();
997   return true;
998 }
999 
emit_JSOP_POPN()1000 bool BaselineCompiler::emit_JSOP_POPN() {
1001   frame.popn(GET_UINT16(pc));
1002   return true;
1003 }
1004 
emit_JSOP_DUPAT()1005 bool BaselineCompiler::emit_JSOP_DUPAT() {
1006   frame.syncStack(0);
1007 
1008   // DUPAT takes a value on the stack and re-pushes it on top.  It's like
1009   // GETLOCAL but it addresses from the top of the stack instead of from the
1010   // stack frame.
1011 
1012   int depth = -(GET_UINT24(pc) + 1);
1013   masm.loadValue(frame.addressOfStackValue(frame.peek(depth)), R0);
1014   frame.push(R0);
1015   return true;
1016 }
1017 
emit_JSOP_DUP()1018 bool BaselineCompiler::emit_JSOP_DUP() {
1019   // Keep top stack value in R0, sync the rest so that we can use R1. We use
1020   // separate registers because every register can be used by at most one
1021   // StackValue.
1022   frame.popRegsAndSync(1);
1023   masm.moveValue(R0, R1);
1024 
1025   // inc/dec ops use DUP followed by ONE, ADD. Push R0 last to avoid a move.
1026   frame.push(R1);
1027   frame.push(R0);
1028   return true;
1029 }
1030 
emit_JSOP_DUP2()1031 bool BaselineCompiler::emit_JSOP_DUP2() {
1032   frame.syncStack(0);
1033 
1034   masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
1035   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
1036 
1037   frame.push(R0);
1038   frame.push(R1);
1039   return true;
1040 }
1041 
emit_JSOP_SWAP()1042 bool BaselineCompiler::emit_JSOP_SWAP() {
1043   // Keep top stack values in R0 and R1.
1044   frame.popRegsAndSync(2);
1045 
1046   frame.push(R1);
1047   frame.push(R0);
1048   return true;
1049 }
1050 
emit_JSOP_PICK()1051 bool BaselineCompiler::emit_JSOP_PICK() {
1052   frame.syncStack(0);
1053 
1054   // Pick takes a value on the stack and moves it to the top.
1055   // For instance, pick 2:
1056   //     before: A B C D E
1057   //     after : A B D E C
1058 
1059   // First, move value at -(amount + 1) into R0.
1060   int32_t depth = -(GET_INT8(pc) + 1);
1061   masm.loadValue(frame.addressOfStackValue(frame.peek(depth)), R0);
1062 
1063   // Move the other values down.
1064   depth++;
1065   for (; depth < 0; depth++) {
1066     Address source = frame.addressOfStackValue(frame.peek(depth));
1067     Address dest = frame.addressOfStackValue(frame.peek(depth - 1));
1068     masm.loadValue(source, R1);
1069     masm.storeValue(R1, dest);
1070   }
1071 
1072   // Push R0.
1073   frame.pop();
1074   frame.push(R0);
1075   return true;
1076 }
1077 
emit_JSOP_UNPICK()1078 bool BaselineCompiler::emit_JSOP_UNPICK() {
1079   frame.syncStack(0);
1080 
1081   // Pick takes the top of the stack value and moves it under the nth value.
1082   // For instance, unpick 2:
1083   //     before: A B C D E
1084   //     after : A B E C D
1085 
1086   // First, move value at -1 into R0.
1087   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
1088 
1089   // Move the other values up.
1090   int32_t depth = -(GET_INT8(pc) + 1);
1091   for (int32_t i = -1; i > depth; i--) {
1092     Address source = frame.addressOfStackValue(frame.peek(i - 1));
1093     Address dest = frame.addressOfStackValue(frame.peek(i));
1094     masm.loadValue(source, R1);
1095     masm.storeValue(R1, dest);
1096   }
1097 
1098   // Store R0 under the nth value.
1099   Address dest = frame.addressOfStackValue(frame.peek(depth));
1100   masm.storeValue(R0, dest);
1101   return true;
1102 }
1103 
emit_JSOP_GOTO()1104 bool BaselineCompiler::emit_JSOP_GOTO() {
1105   frame.syncStack(0);
1106 
1107   jsbytecode* target = pc + GET_JUMP_OFFSET(pc);
1108   masm.jump(labelOf(target));
1109   return true;
1110 }
1111 
emitToBoolean()1112 bool BaselineCompiler::emitToBoolean() {
1113   Label skipIC;
1114   masm.branchTestBoolean(Assembler::Equal, R0, &skipIC);
1115 
1116   // Call IC
1117   ICToBool_Fallback::Compiler stubCompiler(cx);
1118   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1119 
1120   masm.bind(&skipIC);
1121   return true;
1122 }
1123 
emitTest(bool branchIfTrue)1124 bool BaselineCompiler::emitTest(bool branchIfTrue) {
1125   bool knownBoolean = frame.peek(-1)->isKnownBoolean();
1126 
1127   // Keep top stack value in R0.
1128   frame.popRegsAndSync(1);
1129 
1130   if (!knownBoolean && !emitToBoolean()) return false;
1131 
1132   // IC will leave a BooleanValue in R0, just need to branch on it.
1133   masm.branchTestBooleanTruthy(branchIfTrue, R0,
1134                                labelOf(pc + GET_JUMP_OFFSET(pc)));
1135   return true;
1136 }
1137 
emit_JSOP_IFEQ()1138 bool BaselineCompiler::emit_JSOP_IFEQ() { return emitTest(false); }
1139 
emit_JSOP_IFNE()1140 bool BaselineCompiler::emit_JSOP_IFNE() { return emitTest(true); }
1141 
emitAndOr(bool branchIfTrue)1142 bool BaselineCompiler::emitAndOr(bool branchIfTrue) {
1143   bool knownBoolean = frame.peek(-1)->isKnownBoolean();
1144 
1145   // AND and OR leave the original value on the stack.
1146   frame.syncStack(0);
1147 
1148   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
1149   if (!knownBoolean && !emitToBoolean()) return false;
1150 
1151   masm.branchTestBooleanTruthy(branchIfTrue, R0,
1152                                labelOf(pc + GET_JUMP_OFFSET(pc)));
1153   return true;
1154 }
1155 
emit_JSOP_AND()1156 bool BaselineCompiler::emit_JSOP_AND() { return emitAndOr(false); }
1157 
emit_JSOP_OR()1158 bool BaselineCompiler::emit_JSOP_OR() { return emitAndOr(true); }
1159 
emit_JSOP_NOT()1160 bool BaselineCompiler::emit_JSOP_NOT() {
1161   bool knownBoolean = frame.peek(-1)->isKnownBoolean();
1162 
1163   // Keep top stack value in R0.
1164   frame.popRegsAndSync(1);
1165 
1166   if (!knownBoolean && !emitToBoolean()) return false;
1167 
1168   masm.notBoolean(R0);
1169 
1170   frame.push(R0, JSVAL_TYPE_BOOLEAN);
1171   return true;
1172 }
1173 
emit_JSOP_POS()1174 bool BaselineCompiler::emit_JSOP_POS() {
1175   // Keep top stack value in R0.
1176   frame.popRegsAndSync(1);
1177 
1178   // Inline path for int32 and double.
1179   Label done;
1180   masm.branchTestNumber(Assembler::Equal, R0, &done);
1181 
1182   // Call IC.
1183   ICToNumber_Fallback::Compiler stubCompiler(cx);
1184   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1185 
1186   masm.bind(&done);
1187   frame.push(R0);
1188   return true;
1189 }
1190 
emit_JSOP_LOOPHEAD()1191 bool BaselineCompiler::emit_JSOP_LOOPHEAD() {
1192   if (!emit_JSOP_JUMPTARGET()) return false;
1193   return emitInterruptCheck();
1194 }
1195 
emit_JSOP_LOOPENTRY()1196 bool BaselineCompiler::emit_JSOP_LOOPENTRY() {
1197   if (!emit_JSOP_JUMPTARGET()) return false;
1198   frame.syncStack(0);
1199   return emitWarmUpCounterIncrement(LoopEntryCanIonOsr(pc));
1200 }
1201 
emit_JSOP_VOID()1202 bool BaselineCompiler::emit_JSOP_VOID() {
1203   frame.pop();
1204   frame.push(UndefinedValue());
1205   return true;
1206 }
1207 
emit_JSOP_UNDEFINED()1208 bool BaselineCompiler::emit_JSOP_UNDEFINED() {
1209   // If this ever changes, change what JSOP_GIMPLICITTHIS does too.
1210   frame.push(UndefinedValue());
1211   return true;
1212 }
1213 
emit_JSOP_HOLE()1214 bool BaselineCompiler::emit_JSOP_HOLE() {
1215   frame.push(MagicValue(JS_ELEMENTS_HOLE));
1216   return true;
1217 }
1218 
emit_JSOP_NULL()1219 bool BaselineCompiler::emit_JSOP_NULL() {
1220   frame.push(NullValue());
1221   return true;
1222 }
1223 
1224 typedef bool (*ThrowCheckIsObjectFn)(JSContext*, CheckIsObjectKind);
1225 static const VMFunction ThrowCheckIsObjectInfo =
1226     FunctionInfo<ThrowCheckIsObjectFn>(ThrowCheckIsObject,
1227                                        "ThrowCheckIsObject");
1228 
emit_JSOP_CHECKISOBJ()1229 bool BaselineCompiler::emit_JSOP_CHECKISOBJ() {
1230   frame.syncStack(0);
1231   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
1232 
1233   Label ok;
1234   masm.branchTestObject(Assembler::Equal, R0, &ok);
1235 
1236   prepareVMCall();
1237 
1238   pushArg(Imm32(GET_UINT8(pc)));
1239   if (!callVM(ThrowCheckIsObjectInfo)) return false;
1240 
1241   masm.bind(&ok);
1242   return true;
1243 }
1244 
1245 typedef bool (*CheckIsCallableFn)(JSContext*, HandleValue, CheckIsCallableKind);
1246 static const VMFunction CheckIsCallableInfo =
1247     FunctionInfo<CheckIsCallableFn>(CheckIsCallable, "CheckIsCallable");
1248 
emit_JSOP_CHECKISCALLABLE()1249 bool BaselineCompiler::emit_JSOP_CHECKISCALLABLE() {
1250   frame.syncStack(0);
1251   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
1252 
1253   prepareVMCall();
1254 
1255   pushArg(Imm32(GET_UINT8(pc)));
1256   pushArg(R0);
1257   if (!callVM(CheckIsCallableInfo)) return false;
1258 
1259   return true;
1260 }
1261 
1262 typedef bool (*ThrowUninitializedThisFn)(JSContext*, BaselineFrame* frame);
1263 static const VMFunction ThrowUninitializedThisInfo =
1264     FunctionInfo<ThrowUninitializedThisFn>(BaselineThrowUninitializedThis,
1265                                            "BaselineThrowUninitializedThis");
1266 
1267 typedef bool (*ThrowInitializedThisFn)(JSContext*);
1268 static const VMFunction ThrowInitializedThisInfo =
1269     FunctionInfo<ThrowInitializedThisFn>(BaselineThrowInitializedThis,
1270                                          "BaselineThrowInitializedThis");
1271 
emit_JSOP_CHECKTHIS()1272 bool BaselineCompiler::emit_JSOP_CHECKTHIS() {
1273   frame.syncStack(0);
1274   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
1275 
1276   return emitCheckThis(R0);
1277 }
1278 
emit_JSOP_CHECKTHISREINIT()1279 bool BaselineCompiler::emit_JSOP_CHECKTHISREINIT() {
1280   frame.syncStack(0);
1281   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
1282 
1283   return emitCheckThis(R0, /* reinit = */ true);
1284 }
1285 
emitCheckThis(ValueOperand val,bool reinit)1286 bool BaselineCompiler::emitCheckThis(ValueOperand val, bool reinit) {
1287   Label thisOK;
1288   if (reinit)
1289     masm.branchTestMagic(Assembler::Equal, val, &thisOK);
1290   else
1291     masm.branchTestMagic(Assembler::NotEqual, val, &thisOK);
1292 
1293   prepareVMCall();
1294 
1295   if (reinit) {
1296     if (!callVM(ThrowInitializedThisInfo)) return false;
1297   } else {
1298     masm.loadBaselineFramePtr(BaselineFrameReg, val.scratchReg());
1299     pushArg(val.scratchReg());
1300 
1301     if (!callVM(ThrowUninitializedThisInfo)) return false;
1302   }
1303 
1304   masm.bind(&thisOK);
1305   return true;
1306 }
1307 
1308 typedef bool (*ThrowBadDerivedReturnFn)(JSContext*, HandleValue);
1309 static const VMFunction ThrowBadDerivedReturnInfo =
1310     FunctionInfo<ThrowBadDerivedReturnFn>(jit::ThrowBadDerivedReturn,
1311                                           "ThrowBadDerivedReturn");
1312 
emit_JSOP_CHECKRETURN()1313 bool BaselineCompiler::emit_JSOP_CHECKRETURN() {
1314   MOZ_ASSERT(script->isDerivedClassConstructor());
1315 
1316   // Load |this| in R0, return value in R1.
1317   frame.popRegsAndSync(1);
1318   emitLoadReturnValue(R1);
1319 
1320   Label done, returnOK;
1321   masm.branchTestObject(Assembler::Equal, R1, &done);
1322   masm.branchTestUndefined(Assembler::Equal, R1, &returnOK);
1323 
1324   prepareVMCall();
1325   pushArg(R1);
1326   if (!callVM(ThrowBadDerivedReturnInfo)) return false;
1327   masm.assumeUnreachable("Should throw on bad derived constructor return");
1328 
1329   masm.bind(&returnOK);
1330 
1331   if (!emitCheckThis(R0)) return false;
1332 
1333   // Store |this| in the return value slot.
1334   masm.storeValue(R0, frame.addressOfReturnValue());
1335   masm.or32(Imm32(BaselineFrame::HAS_RVAL), frame.addressOfFlags());
1336 
1337   masm.bind(&done);
1338   return true;
1339 }
1340 
1341 typedef bool (*GetFunctionThisFn)(JSContext*, BaselineFrame*,
1342                                   MutableHandleValue);
1343 static const VMFunction GetFunctionThisInfo = FunctionInfo<GetFunctionThisFn>(
1344     jit::BaselineGetFunctionThis, "BaselineGetFunctionThis");
1345 
emit_JSOP_FUNCTIONTHIS()1346 bool BaselineCompiler::emit_JSOP_FUNCTIONTHIS() {
1347   MOZ_ASSERT(function());
1348   MOZ_ASSERT(!function()->isArrow());
1349 
1350   frame.pushThis();
1351 
1352   // In strict mode code or self-hosted functions, |this| is left alone.
1353   if (script->strict() || (function() && function()->isSelfHostedBuiltin()))
1354     return true;
1355 
1356   // Load |thisv| in R0. Skip the call if it's already an object.
1357   Label skipCall;
1358   frame.popRegsAndSync(1);
1359   masm.branchTestObject(Assembler::Equal, R0, &skipCall);
1360 
1361   prepareVMCall();
1362   masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
1363 
1364   pushArg(R1.scratchReg());
1365 
1366   if (!callVM(GetFunctionThisInfo)) return false;
1367 
1368   masm.bind(&skipCall);
1369   frame.push(R0);
1370   return true;
1371 }
1372 
1373 typedef void (*GetNonSyntacticGlobalThisFn)(JSContext*, HandleObject,
1374                                             MutableHandleValue);
1375 static const VMFunction GetNonSyntacticGlobalThisInfo =
1376     FunctionInfo<GetNonSyntacticGlobalThisFn>(js::GetNonSyntacticGlobalThis,
1377                                               "GetNonSyntacticGlobalThis");
1378 
emit_JSOP_GLOBALTHIS()1379 bool BaselineCompiler::emit_JSOP_GLOBALTHIS() {
1380   frame.syncStack(0);
1381 
1382   if (!script->hasNonSyntacticScope()) {
1383     LexicalEnvironmentObject* globalLexical =
1384         &script->global().lexicalEnvironment();
1385     masm.moveValue(globalLexical->thisValue(), R0);
1386     frame.push(R0);
1387     return true;
1388   }
1389 
1390   prepareVMCall();
1391 
1392   masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
1393   pushArg(R0.scratchReg());
1394 
1395   if (!callVM(GetNonSyntacticGlobalThisInfo)) return false;
1396 
1397   frame.push(R0);
1398   return true;
1399 }
1400 
emit_JSOP_TRUE()1401 bool BaselineCompiler::emit_JSOP_TRUE() {
1402   frame.push(BooleanValue(true));
1403   return true;
1404 }
1405 
emit_JSOP_FALSE()1406 bool BaselineCompiler::emit_JSOP_FALSE() {
1407   frame.push(BooleanValue(false));
1408   return true;
1409 }
1410 
emit_JSOP_ZERO()1411 bool BaselineCompiler::emit_JSOP_ZERO() {
1412   frame.push(Int32Value(0));
1413   return true;
1414 }
1415 
emit_JSOP_ONE()1416 bool BaselineCompiler::emit_JSOP_ONE() {
1417   frame.push(Int32Value(1));
1418   return true;
1419 }
1420 
emit_JSOP_INT8()1421 bool BaselineCompiler::emit_JSOP_INT8() {
1422   frame.push(Int32Value(GET_INT8(pc)));
1423   return true;
1424 }
1425 
emit_JSOP_INT32()1426 bool BaselineCompiler::emit_JSOP_INT32() {
1427   frame.push(Int32Value(GET_INT32(pc)));
1428   return true;
1429 }
1430 
emit_JSOP_UINT16()1431 bool BaselineCompiler::emit_JSOP_UINT16() {
1432   frame.push(Int32Value(GET_UINT16(pc)));
1433   return true;
1434 }
1435 
emit_JSOP_UINT24()1436 bool BaselineCompiler::emit_JSOP_UINT24() {
1437   frame.push(Int32Value(GET_UINT24(pc)));
1438   return true;
1439 }
1440 
emit_JSOP_DOUBLE()1441 bool BaselineCompiler::emit_JSOP_DOUBLE() {
1442   frame.push(script->getConst(GET_UINT32_INDEX(pc)));
1443   return true;
1444 }
1445 
emit_JSOP_STRING()1446 bool BaselineCompiler::emit_JSOP_STRING() {
1447   frame.push(StringValue(script->getAtom(pc)));
1448   return true;
1449 }
1450 
emit_JSOP_SYMBOL()1451 bool BaselineCompiler::emit_JSOP_SYMBOL() {
1452   unsigned which = GET_UINT8(pc);
1453   JS::Symbol* sym = cx->runtime()->wellKnownSymbols->get(which);
1454   frame.push(SymbolValue(sym));
1455   return true;
1456 }
1457 
1458 typedef JSObject* (*DeepCloneObjectLiteralFn)(JSContext*, HandleObject,
1459                                               NewObjectKind);
1460 static const VMFunction DeepCloneObjectLiteralInfo =
1461     FunctionInfo<DeepCloneObjectLiteralFn>(DeepCloneObjectLiteral,
1462                                            "DeepCloneObjectLiteral");
1463 
emit_JSOP_OBJECT()1464 bool BaselineCompiler::emit_JSOP_OBJECT() {
1465   JSCompartment* comp = cx->compartment();
1466   if (comp->creationOptions().cloneSingletons()) {
1467     RootedObject obj(cx, script->getObject(GET_UINT32_INDEX(pc)));
1468     if (!obj) return false;
1469 
1470     prepareVMCall();
1471 
1472     pushArg(ImmWord(TenuredObject));
1473     pushArg(ImmGCPtr(obj));
1474 
1475     if (!callVM(DeepCloneObjectLiteralInfo)) return false;
1476 
1477     // Box and push return value.
1478     masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
1479     frame.push(R0);
1480     return true;
1481   }
1482 
1483   comp->behaviors().setSingletonsAsValues();
1484   frame.push(ObjectValue(*script->getObject(pc)));
1485   return true;
1486 }
1487 
emit_JSOP_CALLSITEOBJ()1488 bool BaselineCompiler::emit_JSOP_CALLSITEOBJ() {
1489   RootedObject cso(cx, script->getObject(pc));
1490   RootedObject raw(cx, script->getObject(GET_UINT32_INDEX(pc) + 1));
1491   if (!cso || !raw) return false;
1492 
1493   if (!ProcessCallSiteObjOperation(cx, cso, raw)) return false;
1494 
1495   frame.push(ObjectValue(*cso));
1496   return true;
1497 }
1498 
1499 typedef JSObject* (*CloneRegExpObjectFn)(JSContext*, Handle<RegExpObject*>);
1500 static const VMFunction CloneRegExpObjectInfo =
1501     FunctionInfo<CloneRegExpObjectFn>(CloneRegExpObject, "CloneRegExpObject");
1502 
emit_JSOP_REGEXP()1503 bool BaselineCompiler::emit_JSOP_REGEXP() {
1504   RootedObject reObj(cx, script->getRegExp(pc));
1505 
1506   prepareVMCall();
1507   pushArg(ImmGCPtr(reObj));
1508   if (!callVM(CloneRegExpObjectInfo)) return false;
1509 
1510   // Box and push return value.
1511   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
1512   frame.push(R0);
1513   return true;
1514 }
1515 
1516 typedef JSObject* (*LambdaFn)(JSContext*, HandleFunction, HandleObject);
1517 static const VMFunction LambdaInfo =
1518     FunctionInfo<LambdaFn>(js::Lambda, "Lambda");
1519 
emit_JSOP_LAMBDA()1520 bool BaselineCompiler::emit_JSOP_LAMBDA() {
1521   RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc)));
1522 
1523   prepareVMCall();
1524   masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
1525 
1526   pushArg(R0.scratchReg());
1527   pushArg(ImmGCPtr(fun));
1528 
1529   if (!callVM(LambdaInfo)) return false;
1530 
1531   // Box and push return value.
1532   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
1533   frame.push(R0);
1534   return true;
1535 }
1536 
1537 typedef JSObject* (*LambdaArrowFn)(JSContext*, HandleFunction, HandleObject,
1538                                    HandleValue);
1539 static const VMFunction LambdaArrowInfo =
1540     FunctionInfo<LambdaArrowFn>(js::LambdaArrow, "LambdaArrow");
1541 
emit_JSOP_LAMBDA_ARROW()1542 bool BaselineCompiler::emit_JSOP_LAMBDA_ARROW() {
1543   // Keep pushed newTarget in R0.
1544   frame.popRegsAndSync(1);
1545 
1546   RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc)));
1547 
1548   prepareVMCall();
1549   masm.loadPtr(frame.addressOfEnvironmentChain(), R2.scratchReg());
1550 
1551   pushArg(R0);
1552   pushArg(R2.scratchReg());
1553   pushArg(ImmGCPtr(fun));
1554 
1555   if (!callVM(LambdaArrowInfo)) return false;
1556 
1557   // Box and push return value.
1558   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
1559   frame.push(R0);
1560   return true;
1561 }
1562 
1563 typedef bool (*SetFunNameFn)(JSContext*, HandleFunction, HandleValue,
1564                              FunctionPrefixKind);
1565 static const VMFunction SetFunNameInfo =
1566     FunctionInfo<SetFunNameFn>(js::SetFunctionNameIfNoOwnName, "SetFunName");
1567 
emit_JSOP_SETFUNNAME()1568 bool BaselineCompiler::emit_JSOP_SETFUNNAME() {
1569   frame.popRegsAndSync(2);
1570 
1571   frame.push(R0);
1572   frame.syncStack(0);
1573 
1574   FunctionPrefixKind prefixKind = FunctionPrefixKind(GET_UINT8(pc));
1575   masm.unboxObject(R0, R0.scratchReg());
1576 
1577   prepareVMCall();
1578 
1579   pushArg(Imm32(int32_t(prefixKind)));
1580   pushArg(R1);
1581   pushArg(R0.scratchReg());
1582   return callVM(SetFunNameInfo);
1583 }
1584 
storeValue(const StackValue * source,const Address & dest,const ValueOperand & scratch)1585 void BaselineCompiler::storeValue(const StackValue* source, const Address& dest,
1586                                   const ValueOperand& scratch) {
1587   switch (source->kind()) {
1588     case StackValue::Constant:
1589       masm.storeValue(source->constant(), dest);
1590       break;
1591     case StackValue::Register:
1592       masm.storeValue(source->reg(), dest);
1593       break;
1594     case StackValue::LocalSlot:
1595       masm.loadValue(frame.addressOfLocal(source->localSlot()), scratch);
1596       masm.storeValue(scratch, dest);
1597       break;
1598     case StackValue::ArgSlot:
1599       masm.loadValue(frame.addressOfArg(source->argSlot()), scratch);
1600       masm.storeValue(scratch, dest);
1601       break;
1602     case StackValue::ThisSlot:
1603       masm.loadValue(frame.addressOfThis(), scratch);
1604       masm.storeValue(scratch, dest);
1605       break;
1606     case StackValue::EvalNewTargetSlot:
1607       MOZ_ASSERT(script->isForEval());
1608       masm.loadValue(frame.addressOfEvalNewTarget(), scratch);
1609       masm.storeValue(scratch, dest);
1610       break;
1611     case StackValue::Stack:
1612       masm.loadValue(frame.addressOfStackValue(source), scratch);
1613       masm.storeValue(scratch, dest);
1614       break;
1615     default:
1616       MOZ_CRASH("Invalid kind");
1617   }
1618 }
1619 
emit_JSOP_BITOR()1620 bool BaselineCompiler::emit_JSOP_BITOR() { return emitBinaryArith(); }
1621 
emit_JSOP_BITXOR()1622 bool BaselineCompiler::emit_JSOP_BITXOR() { return emitBinaryArith(); }
1623 
emit_JSOP_BITAND()1624 bool BaselineCompiler::emit_JSOP_BITAND() { return emitBinaryArith(); }
1625 
emit_JSOP_LSH()1626 bool BaselineCompiler::emit_JSOP_LSH() { return emitBinaryArith(); }
1627 
emit_JSOP_RSH()1628 bool BaselineCompiler::emit_JSOP_RSH() { return emitBinaryArith(); }
1629 
emit_JSOP_URSH()1630 bool BaselineCompiler::emit_JSOP_URSH() { return emitBinaryArith(); }
1631 
emit_JSOP_ADD()1632 bool BaselineCompiler::emit_JSOP_ADD() { return emitBinaryArith(); }
1633 
emit_JSOP_SUB()1634 bool BaselineCompiler::emit_JSOP_SUB() { return emitBinaryArith(); }
1635 
emit_JSOP_MUL()1636 bool BaselineCompiler::emit_JSOP_MUL() { return emitBinaryArith(); }
1637 
emit_JSOP_DIV()1638 bool BaselineCompiler::emit_JSOP_DIV() { return emitBinaryArith(); }
1639 
emit_JSOP_MOD()1640 bool BaselineCompiler::emit_JSOP_MOD() { return emitBinaryArith(); }
1641 
emit_JSOP_POW()1642 bool BaselineCompiler::emit_JSOP_POW() { return emitBinaryArith(); }
1643 
emitBinaryArith()1644 bool BaselineCompiler::emitBinaryArith() {
1645   // Keep top JSStack value in R0 and R2
1646   frame.popRegsAndSync(2);
1647 
1648   // Call IC
1649   ICBinaryArith_Fallback::Compiler stubCompiler(
1650       cx, ICStubCompiler::Engine::Baseline);
1651   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1652 
1653   // Mark R0 as pushed stack value.
1654   frame.push(R0);
1655   return true;
1656 }
1657 
emitUnaryArith()1658 bool BaselineCompiler::emitUnaryArith() {
1659   // Keep top stack value in R0.
1660   frame.popRegsAndSync(1);
1661 
1662   // Call IC
1663   ICUnaryArith_Fallback::Compiler stubCompiler(
1664       cx, ICStubCompiler::Engine::Baseline);
1665   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1666 
1667   // Mark R0 as pushed stack value.
1668   frame.push(R0);
1669   return true;
1670 }
1671 
emit_JSOP_BITNOT()1672 bool BaselineCompiler::emit_JSOP_BITNOT() { return emitUnaryArith(); }
1673 
emit_JSOP_NEG()1674 bool BaselineCompiler::emit_JSOP_NEG() { return emitUnaryArith(); }
1675 
emit_JSOP_LT()1676 bool BaselineCompiler::emit_JSOP_LT() { return emitCompare(); }
1677 
emit_JSOP_LE()1678 bool BaselineCompiler::emit_JSOP_LE() { return emitCompare(); }
1679 
emit_JSOP_GT()1680 bool BaselineCompiler::emit_JSOP_GT() { return emitCompare(); }
1681 
emit_JSOP_GE()1682 bool BaselineCompiler::emit_JSOP_GE() { return emitCompare(); }
1683 
emit_JSOP_EQ()1684 bool BaselineCompiler::emit_JSOP_EQ() { return emitCompare(); }
1685 
emit_JSOP_NE()1686 bool BaselineCompiler::emit_JSOP_NE() { return emitCompare(); }
1687 
emitCompare()1688 bool BaselineCompiler::emitCompare() {
1689   // CODEGEN
1690 
1691   // Keep top JSStack value in R0 and R1.
1692   frame.popRegsAndSync(2);
1693 
1694   // Call IC.
1695   ICCompare_Fallback::Compiler stubCompiler(cx,
1696                                             ICStubCompiler::Engine::Baseline);
1697   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1698 
1699   // Mark R0 as pushed stack value.
1700   frame.push(R0, JSVAL_TYPE_BOOLEAN);
1701   return true;
1702 }
1703 
emit_JSOP_STRICTEQ()1704 bool BaselineCompiler::emit_JSOP_STRICTEQ() { return emitCompare(); }
1705 
emit_JSOP_STRICTNE()1706 bool BaselineCompiler::emit_JSOP_STRICTNE() { return emitCompare(); }
1707 
emit_JSOP_CONDSWITCH()1708 bool BaselineCompiler::emit_JSOP_CONDSWITCH() { return true; }
1709 
emit_JSOP_CASE()1710 bool BaselineCompiler::emit_JSOP_CASE() {
1711   frame.popRegsAndSync(2);
1712   frame.push(R0);
1713   frame.syncStack(0);
1714 
1715   // Call IC.
1716   ICCompare_Fallback::Compiler stubCompiler(cx,
1717                                             ICStubCompiler::Engine::Baseline);
1718   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1719 
1720   Register payload = masm.extractInt32(R0, R0.scratchReg());
1721   jsbytecode* target = pc + GET_JUMP_OFFSET(pc);
1722 
1723   Label done;
1724   masm.branch32(Assembler::Equal, payload, Imm32(0), &done);
1725   {
1726     // Pop the switch value if the case matches.
1727     masm.addToStackPtr(Imm32(sizeof(Value)));
1728     masm.jump(labelOf(target));
1729   }
1730   masm.bind(&done);
1731   return true;
1732 }
1733 
emit_JSOP_DEFAULT()1734 bool BaselineCompiler::emit_JSOP_DEFAULT() {
1735   frame.pop();
1736   return emit_JSOP_GOTO();
1737 }
1738 
emit_JSOP_LINENO()1739 bool BaselineCompiler::emit_JSOP_LINENO() { return true; }
1740 
emit_JSOP_NEWARRAY()1741 bool BaselineCompiler::emit_JSOP_NEWARRAY() {
1742   frame.syncStack(0);
1743 
1744   uint32_t length = GET_UINT32(pc);
1745   MOZ_ASSERT(length <= INT32_MAX,
1746              "the bytecode emitter must fail to compile code that would "
1747              "produce JSOP_NEWARRAY with a length exceeding int32_t range");
1748 
1749   // Pass length in R0.
1750   masm.move32(Imm32(AssertedCast<int32_t>(length)), R0.scratchReg());
1751 
1752   ObjectGroup* group =
1753       ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
1754   if (!group) return false;
1755 
1756   ICNewArray_Fallback::Compiler stubCompiler(cx, group,
1757                                              ICStubCompiler::Engine::Baseline);
1758   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1759 
1760   frame.push(R0);
1761   return true;
1762 }
1763 
1764 typedef ArrayObject* (*NewArrayCopyOnWriteFn)(JSContext*, HandleArrayObject,
1765                                               gc::InitialHeap);
1766 const VMFunction jit::NewArrayCopyOnWriteInfo =
1767     FunctionInfo<NewArrayCopyOnWriteFn>(js::NewDenseCopyOnWriteArray,
1768                                         "NewDenseCopyOnWriteArray");
1769 
emit_JSOP_NEWARRAY_COPYONWRITE()1770 bool BaselineCompiler::emit_JSOP_NEWARRAY_COPYONWRITE() {
1771   RootedScript scriptRoot(cx, script);
1772   JSObject* obj = ObjectGroup::getOrFixupCopyOnWriteObject(cx, scriptRoot, pc);
1773   if (!obj) return false;
1774 
1775   prepareVMCall();
1776 
1777   pushArg(Imm32(gc::DefaultHeap));
1778   pushArg(ImmGCPtr(obj));
1779 
1780   if (!callVM(NewArrayCopyOnWriteInfo)) return false;
1781 
1782   // Box and push return value.
1783   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
1784   frame.push(R0);
1785   return true;
1786 }
1787 
emit_JSOP_INITELEM_ARRAY()1788 bool BaselineCompiler::emit_JSOP_INITELEM_ARRAY() {
1789   // Keep the object and rhs on the stack.
1790   frame.syncStack(0);
1791 
1792   // Load object in R0, index in R1.
1793   masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
1794   uint32_t index = GET_UINT32(pc);
1795   MOZ_ASSERT(index <= INT32_MAX,
1796              "the bytecode emitter must fail to compile code that would "
1797              "produce JSOP_INITELEM_ARRAY with a length exceeding "
1798              "int32_t range");
1799   masm.moveValue(Int32Value(AssertedCast<int32_t>(index)), R1);
1800 
1801   // Call IC.
1802   ICSetElem_Fallback::Compiler stubCompiler(cx);
1803   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1804 
1805   // Pop the rhs, so that the object is on the top of the stack.
1806   frame.pop();
1807   return true;
1808 }
1809 
emit_JSOP_NEWOBJECT()1810 bool BaselineCompiler::emit_JSOP_NEWOBJECT() {
1811   frame.syncStack(0);
1812 
1813   ICNewObject_Fallback::Compiler stubCompiler(cx,
1814                                               ICStubCompiler::Engine::Baseline);
1815   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1816 
1817   frame.push(R0);
1818   return true;
1819 }
1820 
emit_JSOP_NEWINIT()1821 bool BaselineCompiler::emit_JSOP_NEWINIT() {
1822   frame.syncStack(0);
1823   JSProtoKey key = JSProtoKey(GET_UINT8(pc));
1824 
1825   if (key == JSProto_Array) {
1826     // Pass length in R0.
1827     masm.move32(Imm32(0), R0.scratchReg());
1828 
1829     ObjectGroup* group =
1830         ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
1831     if (!group) return false;
1832 
1833     ICNewArray_Fallback::Compiler stubCompiler(
1834         cx, group, ICStubCompiler::Engine::Baseline);
1835     if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1836   } else {
1837     MOZ_ASSERT(key == JSProto_Object);
1838 
1839     ICNewObject_Fallback::Compiler stubCompiler(
1840         cx, ICStubCompiler::Engine::Baseline);
1841     if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1842   }
1843 
1844   frame.push(R0);
1845   return true;
1846 }
1847 
emit_JSOP_INITELEM()1848 bool BaselineCompiler::emit_JSOP_INITELEM() {
1849   // Store RHS in the scratch slot.
1850   storeValue(frame.peek(-1), frame.addressOfScratchValue(), R2);
1851   frame.pop();
1852 
1853   // Keep object and index in R0 and R1.
1854   frame.popRegsAndSync(2);
1855 
1856   // Push the object to store the result of the IC.
1857   frame.push(R0);
1858   frame.syncStack(0);
1859 
1860   // Keep RHS on the stack.
1861   frame.pushScratchValue();
1862 
1863   // Call IC.
1864   ICSetElem_Fallback::Compiler stubCompiler(cx);
1865   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1866 
1867   // Pop the rhs, so that the object is on the top of the stack.
1868   frame.pop();
1869   return true;
1870 }
1871 
emit_JSOP_INITHIDDENELEM()1872 bool BaselineCompiler::emit_JSOP_INITHIDDENELEM() {
1873   return emit_JSOP_INITELEM();
1874 }
1875 
1876 typedef bool (*MutateProtoFn)(JSContext* cx, HandlePlainObject obj,
1877                               HandleValue newProto);
1878 static const VMFunction MutateProtoInfo =
1879     FunctionInfo<MutateProtoFn>(MutatePrototype, "MutatePrototype");
1880 
emit_JSOP_MUTATEPROTO()1881 bool BaselineCompiler::emit_JSOP_MUTATEPROTO() {
1882   // Keep values on the stack for the decompiler.
1883   frame.syncStack(0);
1884 
1885   masm.extractObject(frame.addressOfStackValue(frame.peek(-2)),
1886                      R0.scratchReg());
1887   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
1888 
1889   prepareVMCall();
1890 
1891   pushArg(R1);
1892   pushArg(R0.scratchReg());
1893 
1894   if (!callVM(MutateProtoInfo)) return false;
1895 
1896   frame.pop();
1897   return true;
1898 }
1899 
emit_JSOP_INITPROP()1900 bool BaselineCompiler::emit_JSOP_INITPROP() {
1901   // Load lhs in R0, rhs in R1.
1902   frame.syncStack(0);
1903   masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
1904   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
1905 
1906   // Call IC.
1907   ICSetProp_Fallback::Compiler compiler(cx);
1908   if (!emitOpIC(compiler.getStub(&stubSpace_))) return false;
1909 
1910   // Leave the object on the stack.
1911   frame.pop();
1912   return true;
1913 }
1914 
emit_JSOP_INITLOCKEDPROP()1915 bool BaselineCompiler::emit_JSOP_INITLOCKEDPROP() {
1916   return emit_JSOP_INITPROP();
1917 }
1918 
emit_JSOP_INITHIDDENPROP()1919 bool BaselineCompiler::emit_JSOP_INITHIDDENPROP() {
1920   return emit_JSOP_INITPROP();
1921 }
1922 
emit_JSOP_GETELEM()1923 bool BaselineCompiler::emit_JSOP_GETELEM() {
1924   // Keep top two stack values in R0 and R1.
1925   frame.popRegsAndSync(2);
1926 
1927   // Call IC.
1928   ICGetElem_Fallback::Compiler stubCompiler(cx);
1929   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1930 
1931   // Mark R0 as pushed stack value.
1932   frame.push(R0);
1933   return true;
1934 }
1935 
emit_JSOP_GETELEM_SUPER()1936 bool BaselineCompiler::emit_JSOP_GETELEM_SUPER() {
1937   // Store obj in the scratch slot.
1938   storeValue(frame.peek(-1), frame.addressOfScratchValue(), R2);
1939   frame.pop();
1940 
1941   // Keep index and receiver in R0 and R1.
1942   frame.popRegsAndSync(2);
1943 
1944   // Keep obj on the stack.
1945   frame.pushScratchValue();
1946 
1947   ICGetElem_Fallback::Compiler stubCompiler(cx, /* hasReceiver = */ true);
1948   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1949 
1950   frame.pop();  // This value is also popped in InitFromBailout.
1951   frame.push(R0);
1952   return true;
1953 }
1954 
emit_JSOP_CALLELEM()1955 bool BaselineCompiler::emit_JSOP_CALLELEM() { return emit_JSOP_GETELEM(); }
1956 
emit_JSOP_SETELEM()1957 bool BaselineCompiler::emit_JSOP_SETELEM() {
1958   // Store RHS in the scratch slot.
1959   storeValue(frame.peek(-1), frame.addressOfScratchValue(), R2);
1960   frame.pop();
1961 
1962   // Keep object and index in R0 and R1.
1963   frame.popRegsAndSync(2);
1964 
1965   // Keep RHS on the stack.
1966   frame.pushScratchValue();
1967 
1968   // Call IC.
1969   ICSetElem_Fallback::Compiler stubCompiler(cx);
1970   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
1971 
1972   return true;
1973 }
1974 
emit_JSOP_STRICTSETELEM()1975 bool BaselineCompiler::emit_JSOP_STRICTSETELEM() { return emit_JSOP_SETELEM(); }
1976 
emit_JSOP_SETELEM_SUPER()1977 bool BaselineCompiler::emit_JSOP_SETELEM_SUPER() {
1978   bool strict = IsCheckStrictOp(JSOp(*pc));
1979 
1980   // Incoming stack is |propval, receiver, obj, rval|. We need to shuffle
1981   // stack to leave rval when operation is complete.
1982 
1983   // Pop rval into R0, then load propval into R1 and replace with rval.
1984   frame.popRegsAndSync(1);
1985   masm.loadValue(frame.addressOfStackValue(frame.peek(-3)), R1);
1986   masm.storeValue(R0, frame.addressOfStackValue(frame.peek(-3)));
1987 
1988   prepareVMCall();
1989 
1990   pushArg(Imm32(strict));
1991   masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R2);
1992   pushArg(R2);  // receiver
1993   pushArg(R0);  // rval
1994   pushArg(R1);  // propval
1995   masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
1996   pushArg(R0.scratchReg());  // obj
1997 
1998   if (!callVM(SetObjectElementInfo)) return false;
1999 
2000   frame.popn(2);
2001   return true;
2002 }
2003 
emit_JSOP_STRICTSETELEM_SUPER()2004 bool BaselineCompiler::emit_JSOP_STRICTSETELEM_SUPER() {
2005   return emit_JSOP_SETELEM_SUPER();
2006 }
2007 
2008 typedef bool (*DeleteElementFn)(JSContext*, HandleValue, HandleValue, bool*);
2009 static const VMFunction DeleteElementStrictInfo = FunctionInfo<DeleteElementFn>(
2010     DeleteElementJit<true>, "DeleteElementStrict");
2011 static const VMFunction DeleteElementNonStrictInfo =
2012     FunctionInfo<DeleteElementFn>(DeleteElementJit<false>,
2013                                   "DeleteElementNonStrict");
2014 
emit_JSOP_DELELEM()2015 bool BaselineCompiler::emit_JSOP_DELELEM() {
2016   // Keep values on the stack for the decompiler.
2017   frame.syncStack(0);
2018   masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
2019   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
2020 
2021   prepareVMCall();
2022 
2023   pushArg(R1);
2024   pushArg(R0);
2025 
2026   bool strict = JSOp(*pc) == JSOP_STRICTDELELEM;
2027   if (!callVM(strict ? DeleteElementStrictInfo : DeleteElementNonStrictInfo))
2028     return false;
2029 
2030   masm.boxNonDouble(JSVAL_TYPE_BOOLEAN, ReturnReg, R1);
2031   frame.popn(2);
2032   frame.push(R1);
2033   return true;
2034 }
2035 
emit_JSOP_STRICTDELELEM()2036 bool BaselineCompiler::emit_JSOP_STRICTDELELEM() { return emit_JSOP_DELELEM(); }
2037 
emit_JSOP_IN()2038 bool BaselineCompiler::emit_JSOP_IN() {
2039   frame.popRegsAndSync(2);
2040 
2041   ICIn_Fallback::Compiler stubCompiler(cx);
2042   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
2043 
2044   frame.push(R0);
2045   return true;
2046 }
2047 
emit_JSOP_HASOWN()2048 bool BaselineCompiler::emit_JSOP_HASOWN() {
2049   frame.popRegsAndSync(2);
2050 
2051   ICHasOwn_Fallback::Compiler stubCompiler(cx);
2052   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
2053 
2054   frame.push(R0);
2055   return true;
2056 }
2057 
emit_JSOP_GETGNAME()2058 bool BaselineCompiler::emit_JSOP_GETGNAME() {
2059   if (script->hasNonSyntacticScope()) return emit_JSOP_GETNAME();
2060 
2061   RootedPropertyName name(cx, script->getName(pc));
2062 
2063   // These names are non-configurable on the global and cannot be shadowed.
2064   if (name == cx->names().undefined) {
2065     frame.push(UndefinedValue());
2066     return true;
2067   }
2068   if (name == cx->names().NaN) {
2069     frame.push(cx->runtime()->NaNValue);
2070     return true;
2071   }
2072   if (name == cx->names().Infinity) {
2073     frame.push(cx->runtime()->positiveInfinityValue);
2074     return true;
2075   }
2076 
2077   frame.syncStack(0);
2078 
2079   masm.movePtr(ImmGCPtr(&script->global().lexicalEnvironment()),
2080                R0.scratchReg());
2081 
2082   // Call IC.
2083   ICGetName_Fallback::Compiler stubCompiler(cx);
2084   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
2085 
2086   // Mark R0 as pushed stack value.
2087   frame.push(R0);
2088   return true;
2089 }
2090 
emit_JSOP_BINDGNAME()2091 bool BaselineCompiler::emit_JSOP_BINDGNAME() {
2092   if (!script->hasNonSyntacticScope()) {
2093     // We can bind name to the global lexical scope if the binding already
2094     // exists, is initialized, and is writable (i.e., an initialized
2095     // 'let') at compile time.
2096     RootedPropertyName name(cx, script->getName(pc));
2097     Rooted<LexicalEnvironmentObject*> env(
2098         cx, &script->global().lexicalEnvironment());
2099     if (Shape* shape = env->lookup(cx, name)) {
2100       if (shape->writable() &&
2101           !env->getSlot(shape->slot()).isMagic(JS_UNINITIALIZED_LEXICAL)) {
2102         frame.push(ObjectValue(*env));
2103         return true;
2104       }
2105     } else if (Shape* shape = script->global().lookup(cx, name)) {
2106       // If the property does not currently exist on the global lexical
2107       // scope, we can bind name to the global object if the property
2108       // exists on the global and is non-configurable, as then it cannot
2109       // be shadowed.
2110       if (!shape->configurable()) {
2111         frame.push(ObjectValue(script->global()));
2112         return true;
2113       }
2114     }
2115 
2116     // Otherwise we have to use the environment chain.
2117   }
2118 
2119   return emit_JSOP_BINDNAME();
2120 }
2121 
2122 typedef JSObject* (*BindVarFn)(JSContext*, HandleObject);
2123 static const VMFunction BindVarInfo =
2124     FunctionInfo<BindVarFn>(jit::BindVar, "BindVar");
2125 
emit_JSOP_BINDVAR()2126 bool BaselineCompiler::emit_JSOP_BINDVAR() {
2127   frame.syncStack(0);
2128   masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
2129 
2130   prepareVMCall();
2131   pushArg(R0.scratchReg());
2132 
2133   if (!callVM(BindVarInfo)) return false;
2134 
2135   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
2136   frame.push(R0);
2137   return true;
2138 }
2139 
emit_JSOP_SETPROP()2140 bool BaselineCompiler::emit_JSOP_SETPROP() {
2141   // Keep lhs in R0, rhs in R1.
2142   frame.popRegsAndSync(2);
2143 
2144   // Keep RHS on the stack.
2145   frame.push(R1);
2146   frame.syncStack(0);
2147 
2148   // Call IC.
2149   ICSetProp_Fallback::Compiler compiler(cx);
2150   if (!emitOpIC(compiler.getStub(&stubSpace_))) return false;
2151 
2152   return true;
2153 }
2154 
emit_JSOP_STRICTSETPROP()2155 bool BaselineCompiler::emit_JSOP_STRICTSETPROP() { return emit_JSOP_SETPROP(); }
2156 
emit_JSOP_SETNAME()2157 bool BaselineCompiler::emit_JSOP_SETNAME() { return emit_JSOP_SETPROP(); }
2158 
emit_JSOP_STRICTSETNAME()2159 bool BaselineCompiler::emit_JSOP_STRICTSETNAME() { return emit_JSOP_SETPROP(); }
2160 
emit_JSOP_SETGNAME()2161 bool BaselineCompiler::emit_JSOP_SETGNAME() { return emit_JSOP_SETPROP(); }
2162 
emit_JSOP_STRICTSETGNAME()2163 bool BaselineCompiler::emit_JSOP_STRICTSETGNAME() {
2164   return emit_JSOP_SETPROP();
2165 }
2166 
2167 typedef bool (*SetPropertySuperFn)(JSContext*, HandleObject, HandleValue,
2168                                    HandlePropertyName, HandleValue, bool);
2169 static const VMFunction SetPropertySuperInfo =
2170     FunctionInfo<SetPropertySuperFn>(js::SetPropertySuper, "SetPropertySuper");
2171 
emit_JSOP_SETPROP_SUPER()2172 bool BaselineCompiler::emit_JSOP_SETPROP_SUPER() {
2173   bool strict = IsCheckStrictOp(JSOp(*pc));
2174 
2175   // Incoming stack is |receiver, obj, rval|. We need to shuffle stack to
2176   // leave rval when operation is complete.
2177 
2178   // Pop rval into R0, then load receiver into R1 and replace with rval.
2179   frame.popRegsAndSync(1);
2180   masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R1);
2181   masm.storeValue(R0, frame.addressOfStackValue(frame.peek(-2)));
2182 
2183   prepareVMCall();
2184 
2185   pushArg(Imm32(strict));
2186   pushArg(R0);  // rval
2187   pushArg(ImmGCPtr(script->getName(pc)));
2188   pushArg(R1);  // receiver
2189   masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
2190   pushArg(R0.scratchReg());  // obj
2191 
2192   if (!callVM(SetPropertySuperInfo)) return false;
2193 
2194   frame.pop();
2195   return true;
2196 }
2197 
emit_JSOP_STRICTSETPROP_SUPER()2198 bool BaselineCompiler::emit_JSOP_STRICTSETPROP_SUPER() {
2199   return emit_JSOP_SETPROP_SUPER();
2200 }
2201 
emit_JSOP_GETPROP()2202 bool BaselineCompiler::emit_JSOP_GETPROP() {
2203   // Keep object in R0.
2204   frame.popRegsAndSync(1);
2205 
2206   // Call IC.
2207   ICGetProp_Fallback::Compiler compiler(cx, ICStubCompiler::Engine::Baseline);
2208   if (!emitOpIC(compiler.getStub(&stubSpace_))) return false;
2209 
2210   // Mark R0 as pushed stack value.
2211   frame.push(R0);
2212   return true;
2213 }
2214 
emit_JSOP_CALLPROP()2215 bool BaselineCompiler::emit_JSOP_CALLPROP() { return emit_JSOP_GETPROP(); }
2216 
emit_JSOP_LENGTH()2217 bool BaselineCompiler::emit_JSOP_LENGTH() { return emit_JSOP_GETPROP(); }
2218 
emit_JSOP_GETBOUNDNAME()2219 bool BaselineCompiler::emit_JSOP_GETBOUNDNAME() { return emit_JSOP_GETPROP(); }
2220 
emit_JSOP_GETPROP_SUPER()2221 bool BaselineCompiler::emit_JSOP_GETPROP_SUPER() {
2222   // Receiver -> R1, Object -> R0
2223   frame.popRegsAndSync(1);
2224   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
2225   frame.pop();
2226 
2227   ICGetProp_Fallback::Compiler compiler(cx, ICStubCompiler::Engine::Baseline,
2228                                         /* hasReceiver = */ true);
2229   if (!emitOpIC(compiler.getStub(&stubSpace_))) return false;
2230 
2231   frame.push(R0);
2232   return true;
2233 }
2234 
2235 typedef bool (*DeletePropertyFn)(JSContext*, HandleValue, HandlePropertyName,
2236                                  bool*);
2237 static const VMFunction DeletePropertyStrictInfo =
2238     FunctionInfo<DeletePropertyFn>(DeletePropertyJit<true>,
2239                                    "DeletePropertyStrict");
2240 static const VMFunction DeletePropertyNonStrictInfo =
2241     FunctionInfo<DeletePropertyFn>(DeletePropertyJit<false>,
2242                                    "DeletePropertyNonStrict");
2243 
emit_JSOP_DELPROP()2244 bool BaselineCompiler::emit_JSOP_DELPROP() {
2245   // Keep value on the stack for the decompiler.
2246   frame.syncStack(0);
2247   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
2248 
2249   prepareVMCall();
2250 
2251   pushArg(ImmGCPtr(script->getName(pc)));
2252   pushArg(R0);
2253 
2254   bool strict = JSOp(*pc) == JSOP_STRICTDELPROP;
2255   if (!callVM(strict ? DeletePropertyStrictInfo : DeletePropertyNonStrictInfo))
2256     return false;
2257 
2258   masm.boxNonDouble(JSVAL_TYPE_BOOLEAN, ReturnReg, R1);
2259   frame.pop();
2260   frame.push(R1);
2261   return true;
2262 }
2263 
emit_JSOP_STRICTDELPROP()2264 bool BaselineCompiler::emit_JSOP_STRICTDELPROP() { return emit_JSOP_DELPROP(); }
2265 
getEnvironmentCoordinateObject(Register reg)2266 void BaselineCompiler::getEnvironmentCoordinateObject(Register reg) {
2267   EnvironmentCoordinate ec(pc);
2268 
2269   masm.loadPtr(frame.addressOfEnvironmentChain(), reg);
2270   for (unsigned i = ec.hops(); i; i--)
2271     masm.extractObject(
2272         Address(reg, EnvironmentObject::offsetOfEnclosingEnvironment()), reg);
2273 }
2274 
getEnvironmentCoordinateAddressFromObject(Register objReg,Register reg)2275 Address BaselineCompiler::getEnvironmentCoordinateAddressFromObject(
2276     Register objReg, Register reg) {
2277   EnvironmentCoordinate ec(pc);
2278   Shape* shape = EnvironmentCoordinateToEnvironmentShape(script, pc);
2279 
2280   Address addr;
2281   if (shape->numFixedSlots() <= ec.slot()) {
2282     masm.loadPtr(Address(objReg, NativeObject::offsetOfSlots()), reg);
2283     return Address(reg, (ec.slot() - shape->numFixedSlots()) * sizeof(Value));
2284   }
2285 
2286   return Address(objReg, NativeObject::getFixedSlotOffset(ec.slot()));
2287 }
2288 
getEnvironmentCoordinateAddress(Register reg)2289 Address BaselineCompiler::getEnvironmentCoordinateAddress(Register reg) {
2290   getEnvironmentCoordinateObject(reg);
2291   return getEnvironmentCoordinateAddressFromObject(reg, reg);
2292 }
2293 
emit_JSOP_GETALIASEDVAR()2294 bool BaselineCompiler::emit_JSOP_GETALIASEDVAR() {
2295   frame.syncStack(0);
2296 
2297   Address address = getEnvironmentCoordinateAddress(R0.scratchReg());
2298   masm.loadValue(address, R0);
2299 
2300   if (ionCompileable_) {
2301     // No need to monitor types if we know Ion can't compile this script.
2302     ICTypeMonitor_Fallback::Compiler compiler(cx, nullptr);
2303     if (!emitOpIC(compiler.getStub(&stubSpace_))) return false;
2304   }
2305 
2306   frame.push(R0);
2307   return true;
2308 }
2309 
emit_JSOP_SETALIASEDVAR()2310 bool BaselineCompiler::emit_JSOP_SETALIASEDVAR() {
2311   JSScript* outerScript = EnvironmentCoordinateFunctionScript(script, pc);
2312   if (outerScript && outerScript->treatAsRunOnce()) {
2313     // Type updates for this operation might need to be tracked, so treat
2314     // this as a SETPROP.
2315 
2316     // Load rhs into R1.
2317     frame.syncStack(0);
2318     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
2319 
2320     // Load and box lhs into R0.
2321     getEnvironmentCoordinateObject(R2.scratchReg());
2322     masm.tagValue(JSVAL_TYPE_OBJECT, R2.scratchReg(), R0);
2323 
2324     // Call SETPROP IC.
2325     ICSetProp_Fallback::Compiler compiler(cx);
2326     if (!emitOpIC(compiler.getStub(&stubSpace_))) return false;
2327 
2328     return true;
2329   }
2330 
2331   // Keep rvalue in R0.
2332   frame.popRegsAndSync(1);
2333   Register objReg = R2.scratchReg();
2334 
2335   getEnvironmentCoordinateObject(objReg);
2336   Address address =
2337       getEnvironmentCoordinateAddressFromObject(objReg, R1.scratchReg());
2338   masm.guardedCallPreBarrier(address, MIRType::Value);
2339   masm.storeValue(R0, address);
2340   frame.push(R0);
2341 
2342   // Only R0 is live at this point.
2343   // Scope coordinate object is already in R2.scratchReg().
2344   Register temp = R1.scratchReg();
2345 
2346   Label skipBarrier;
2347   masm.branchPtrInNurseryChunk(Assembler::Equal, objReg, temp, &skipBarrier);
2348   masm.branchValueIsNurseryCell(Assembler::NotEqual, R0, temp, &skipBarrier);
2349 
2350   masm.call(&postBarrierSlot_);  // Won't clobber R0
2351 
2352   masm.bind(&skipBarrier);
2353   return true;
2354 }
2355 
emit_JSOP_GETNAME()2356 bool BaselineCompiler::emit_JSOP_GETNAME() {
2357   frame.syncStack(0);
2358 
2359   masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
2360 
2361   // Call IC.
2362   ICGetName_Fallback::Compiler stubCompiler(cx);
2363   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
2364 
2365   // Mark R0 as pushed stack value.
2366   frame.push(R0);
2367   return true;
2368 }
2369 
emit_JSOP_BINDNAME()2370 bool BaselineCompiler::emit_JSOP_BINDNAME() {
2371   frame.syncStack(0);
2372 
2373   if (*pc == JSOP_BINDGNAME && !script->hasNonSyntacticScope())
2374     masm.movePtr(ImmGCPtr(&script->global().lexicalEnvironment()),
2375                  R0.scratchReg());
2376   else
2377     masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
2378 
2379   // Call IC.
2380   ICBindName_Fallback::Compiler stubCompiler(cx);
2381   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
2382 
2383   // Mark R0 as pushed stack value.
2384   frame.push(R0);
2385   return true;
2386 }
2387 
2388 typedef bool (*DeleteNameFn)(JSContext*, HandlePropertyName, HandleObject,
2389                              MutableHandleValue);
2390 static const VMFunction DeleteNameInfo =
2391     FunctionInfo<DeleteNameFn>(DeleteNameOperation, "DeleteNameOperation");
2392 
emit_JSOP_DELNAME()2393 bool BaselineCompiler::emit_JSOP_DELNAME() {
2394   frame.syncStack(0);
2395   masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
2396 
2397   prepareVMCall();
2398 
2399   pushArg(R0.scratchReg());
2400   pushArg(ImmGCPtr(script->getName(pc)));
2401 
2402   if (!callVM(DeleteNameInfo)) return false;
2403 
2404   frame.push(R0);
2405   return true;
2406 }
2407 
emit_JSOP_GETIMPORT()2408 bool BaselineCompiler::emit_JSOP_GETIMPORT() {
2409   ModuleEnvironmentObject* env = GetModuleEnvironmentForScript(script);
2410   MOZ_ASSERT(env);
2411 
2412   ModuleEnvironmentObject* targetEnv;
2413   Shape* shape;
2414   MOZ_ALWAYS_TRUE(
2415       env->lookupImport(NameToId(script->getName(pc)), &targetEnv, &shape));
2416 
2417   EnsureTrackPropertyTypes(cx, targetEnv, shape->propid());
2418 
2419   frame.syncStack(0);
2420 
2421   uint32_t slot = shape->slot();
2422   Register scratch = R0.scratchReg();
2423   masm.movePtr(ImmGCPtr(targetEnv), scratch);
2424   if (slot < targetEnv->numFixedSlots()) {
2425     masm.loadValue(Address(scratch, NativeObject::getFixedSlotOffset(slot)),
2426                    R0);
2427   } else {
2428     masm.loadPtr(Address(scratch, NativeObject::offsetOfSlots()), scratch);
2429     masm.loadValue(
2430         Address(scratch, (slot - targetEnv->numFixedSlots()) * sizeof(Value)),
2431         R0);
2432   }
2433 
2434   // Imports are initialized by this point except in rare circumstances, so
2435   // don't emit a check unless we have to.
2436   if (targetEnv->getSlot(shape->slot()).isMagic(JS_UNINITIALIZED_LEXICAL))
2437     if (!emitUninitializedLexicalCheck(R0)) return false;
2438 
2439   if (ionCompileable_) {
2440     // No need to monitor types if we know Ion can't compile this script.
2441     ICTypeMonitor_Fallback::Compiler compiler(cx, nullptr);
2442     if (!emitOpIC(compiler.getStub(&stubSpace_))) return false;
2443   }
2444 
2445   frame.push(R0);
2446   return true;
2447 }
2448 
emit_JSOP_GETINTRINSIC()2449 bool BaselineCompiler::emit_JSOP_GETINTRINSIC() {
2450   frame.syncStack(0);
2451 
2452   ICGetIntrinsic_Fallback::Compiler stubCompiler(cx);
2453   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
2454 
2455   frame.push(R0);
2456   return true;
2457 }
2458 
2459 typedef bool (*DefVarFn)(JSContext*, HandlePropertyName, unsigned,
2460                          HandleObject);
2461 static const VMFunction DefVarInfo = FunctionInfo<DefVarFn>(DefVar, "DefVar");
2462 
emit_JSOP_DEFVAR()2463 bool BaselineCompiler::emit_JSOP_DEFVAR() {
2464   frame.syncStack(0);
2465 
2466   unsigned attrs = JSPROP_ENUMERATE;
2467   if (!script->isForEval()) attrs |= JSPROP_PERMANENT;
2468   MOZ_ASSERT(attrs <= UINT32_MAX);
2469 
2470   masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
2471 
2472   prepareVMCall();
2473 
2474   pushArg(R0.scratchReg());
2475   pushArg(Imm32(attrs));
2476   pushArg(ImmGCPtr(script->getName(pc)));
2477 
2478   return callVM(DefVarInfo);
2479 }
2480 
2481 typedef bool (*DefLexicalFn)(JSContext*, HandlePropertyName, unsigned,
2482                              HandleObject);
2483 static const VMFunction DefLexicalInfo =
2484     FunctionInfo<DefLexicalFn>(DefLexical, "DefLexical");
2485 
emit_JSOP_DEFCONST()2486 bool BaselineCompiler::emit_JSOP_DEFCONST() { return emit_JSOP_DEFLET(); }
2487 
emit_JSOP_DEFLET()2488 bool BaselineCompiler::emit_JSOP_DEFLET() {
2489   frame.syncStack(0);
2490 
2491   unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT;
2492   if (*pc == JSOP_DEFCONST) attrs |= JSPROP_READONLY;
2493   MOZ_ASSERT(attrs <= UINT32_MAX);
2494 
2495   masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
2496 
2497   prepareVMCall();
2498 
2499   pushArg(R0.scratchReg());
2500   pushArg(Imm32(attrs));
2501   pushArg(ImmGCPtr(script->getName(pc)));
2502 
2503   return callVM(DefLexicalInfo);
2504 }
2505 
2506 typedef bool (*DefFunOperationFn)(JSContext*, HandleScript, HandleObject,
2507                                   HandleFunction);
2508 static const VMFunction DefFunOperationInfo =
2509     FunctionInfo<DefFunOperationFn>(DefFunOperation, "DefFunOperation");
2510 
emit_JSOP_DEFFUN()2511 bool BaselineCompiler::emit_JSOP_DEFFUN() {
2512   frame.popRegsAndSync(1);
2513   masm.unboxObject(R0, R0.scratchReg());
2514   masm.loadPtr(frame.addressOfEnvironmentChain(), R1.scratchReg());
2515 
2516   prepareVMCall();
2517 
2518   pushArg(R0.scratchReg());
2519   pushArg(R1.scratchReg());
2520   pushArg(ImmGCPtr(script));
2521 
2522   return callVM(DefFunOperationInfo);
2523 }
2524 
2525 typedef bool (*InitPropGetterSetterFn)(JSContext*, jsbytecode*, HandleObject,
2526                                        HandlePropertyName, HandleObject);
2527 static const VMFunction InitPropGetterSetterInfo =
2528     FunctionInfo<InitPropGetterSetterFn>(InitGetterSetterOperation,
2529                                          "InitPropGetterSetterOperation");
2530 
emitInitPropGetterSetter()2531 bool BaselineCompiler::emitInitPropGetterSetter() {
2532   MOZ_ASSERT(JSOp(*pc) == JSOP_INITPROP_GETTER ||
2533              JSOp(*pc) == JSOP_INITHIDDENPROP_GETTER ||
2534              JSOp(*pc) == JSOP_INITPROP_SETTER ||
2535              JSOp(*pc) == JSOP_INITHIDDENPROP_SETTER);
2536 
2537   // Keep values on the stack for the decompiler.
2538   frame.syncStack(0);
2539 
2540   prepareVMCall();
2541 
2542   masm.extractObject(frame.addressOfStackValue(frame.peek(-1)),
2543                      R0.scratchReg());
2544   masm.extractObject(frame.addressOfStackValue(frame.peek(-2)),
2545                      R1.scratchReg());
2546 
2547   pushArg(R0.scratchReg());
2548   pushArg(ImmGCPtr(script->getName(pc)));
2549   pushArg(R1.scratchReg());
2550   pushArg(ImmPtr(pc));
2551 
2552   if (!callVM(InitPropGetterSetterInfo)) return false;
2553 
2554   frame.pop();
2555   return true;
2556 }
2557 
emit_JSOP_INITPROP_GETTER()2558 bool BaselineCompiler::emit_JSOP_INITPROP_GETTER() {
2559   return emitInitPropGetterSetter();
2560 }
2561 
emit_JSOP_INITHIDDENPROP_GETTER()2562 bool BaselineCompiler::emit_JSOP_INITHIDDENPROP_GETTER() {
2563   return emitInitPropGetterSetter();
2564 }
2565 
emit_JSOP_INITPROP_SETTER()2566 bool BaselineCompiler::emit_JSOP_INITPROP_SETTER() {
2567   return emitInitPropGetterSetter();
2568 }
2569 
emit_JSOP_INITHIDDENPROP_SETTER()2570 bool BaselineCompiler::emit_JSOP_INITHIDDENPROP_SETTER() {
2571   return emitInitPropGetterSetter();
2572 }
2573 
2574 typedef bool (*InitElemGetterSetterFn)(JSContext*, jsbytecode*, HandleObject,
2575                                        HandleValue, HandleObject);
2576 static const VMFunction InitElemGetterSetterInfo =
2577     FunctionInfo<InitElemGetterSetterFn>(InitGetterSetterOperation,
2578                                          "InitElemGetterSetterOperation");
2579 
emitInitElemGetterSetter()2580 bool BaselineCompiler::emitInitElemGetterSetter() {
2581   MOZ_ASSERT(JSOp(*pc) == JSOP_INITELEM_GETTER ||
2582              JSOp(*pc) == JSOP_INITHIDDENELEM_GETTER ||
2583              JSOp(*pc) == JSOP_INITELEM_SETTER ||
2584              JSOp(*pc) == JSOP_INITHIDDENELEM_SETTER);
2585 
2586   // Load index and value in R0 and R1, but keep values on the stack for the
2587   // decompiler.
2588   frame.syncStack(0);
2589   masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
2590   masm.extractObject(frame.addressOfStackValue(frame.peek(-1)),
2591                      R1.scratchReg());
2592 
2593   prepareVMCall();
2594 
2595   pushArg(R1.scratchReg());
2596   pushArg(R0);
2597   masm.extractObject(frame.addressOfStackValue(frame.peek(-3)),
2598                      R0.scratchReg());
2599   pushArg(R0.scratchReg());
2600   pushArg(ImmPtr(pc));
2601 
2602   if (!callVM(InitElemGetterSetterInfo)) return false;
2603 
2604   frame.popn(2);
2605   return true;
2606 }
2607 
emit_JSOP_INITELEM_GETTER()2608 bool BaselineCompiler::emit_JSOP_INITELEM_GETTER() {
2609   return emitInitElemGetterSetter();
2610 }
2611 
emit_JSOP_INITHIDDENELEM_GETTER()2612 bool BaselineCompiler::emit_JSOP_INITHIDDENELEM_GETTER() {
2613   return emitInitElemGetterSetter();
2614 }
2615 
emit_JSOP_INITELEM_SETTER()2616 bool BaselineCompiler::emit_JSOP_INITELEM_SETTER() {
2617   return emitInitElemGetterSetter();
2618 }
2619 
emit_JSOP_INITHIDDENELEM_SETTER()2620 bool BaselineCompiler::emit_JSOP_INITHIDDENELEM_SETTER() {
2621   return emitInitElemGetterSetter();
2622 }
2623 
emit_JSOP_INITELEM_INC()2624 bool BaselineCompiler::emit_JSOP_INITELEM_INC() {
2625   // Keep the object and rhs on the stack.
2626   frame.syncStack(0);
2627 
2628   // Load object in R0, index in R1.
2629   masm.loadValue(frame.addressOfStackValue(frame.peek(-3)), R0);
2630   masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R1);
2631 
2632   // Call IC.
2633   ICSetElem_Fallback::Compiler stubCompiler(cx);
2634   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
2635 
2636   // Pop the rhs
2637   frame.pop();
2638 
2639   // Increment index
2640   Address indexAddr = frame.addressOfStackValue(frame.peek(-1));
2641 #ifdef DEBUG
2642   Label isInt32;
2643   masm.branchTestInt32(Assembler::Equal, indexAddr, &isInt32);
2644   masm.assumeUnreachable("INITELEM_INC index must be Int32");
2645   masm.bind(&isInt32);
2646 #endif
2647   masm.incrementInt32Value(indexAddr);
2648   return true;
2649 }
2650 
emit_JSOP_GETLOCAL()2651 bool BaselineCompiler::emit_JSOP_GETLOCAL() {
2652   frame.pushLocal(GET_LOCALNO(pc));
2653   return true;
2654 }
2655 
emit_JSOP_SETLOCAL()2656 bool BaselineCompiler::emit_JSOP_SETLOCAL() {
2657   // Ensure no other StackValue refers to the old value, for instance i + (i =
2658   // 3). This also allows us to use R0 as scratch below.
2659   frame.syncStack(1);
2660 
2661   uint32_t local = GET_LOCALNO(pc);
2662   storeValue(frame.peek(-1), frame.addressOfLocal(local), R0);
2663   return true;
2664 }
2665 
emitFormalArgAccess(uint32_t arg,bool get)2666 bool BaselineCompiler::emitFormalArgAccess(uint32_t arg, bool get) {
2667   // Fast path: the script does not use |arguments| or formals don't
2668   // alias the arguments object.
2669   if (!script->argumentsAliasesFormals()) {
2670     if (get) {
2671       frame.pushArg(arg);
2672     } else {
2673       // See the comment in emit_JSOP_SETLOCAL.
2674       frame.syncStack(1);
2675       storeValue(frame.peek(-1), frame.addressOfArg(arg), R0);
2676     }
2677 
2678     return true;
2679   }
2680 
2681   // Sync so that we can use R0.
2682   frame.syncStack(0);
2683 
2684   // If the script is known to have an arguments object, we can just use it.
2685   // Else, we *may* have an arguments object (because we can't invalidate
2686   // when needsArgsObj becomes |true|), so we have to test HAS_ARGS_OBJ.
2687   Label done;
2688   if (!script->needsArgsObj()) {
2689     Label hasArgsObj;
2690     masm.branchTest32(Assembler::NonZero, frame.addressOfFlags(),
2691                       Imm32(BaselineFrame::HAS_ARGS_OBJ), &hasArgsObj);
2692     if (get)
2693       masm.loadValue(frame.addressOfArg(arg), R0);
2694     else
2695       storeValue(frame.peek(-1), frame.addressOfArg(arg), R0);
2696     masm.jump(&done);
2697     masm.bind(&hasArgsObj);
2698   }
2699 
2700   // Load the arguments object data vector.
2701   Register reg = R2.scratchReg();
2702   masm.loadPtr(
2703       Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfArgsObj()), reg);
2704   masm.loadPrivate(Address(reg, ArgumentsObject::getDataSlotOffset()), reg);
2705 
2706   // Load/store the argument.
2707   Address argAddr(reg, ArgumentsData::offsetOfArgs() + arg * sizeof(Value));
2708   if (get) {
2709     masm.loadValue(argAddr, R0);
2710     frame.push(R0);
2711   } else {
2712     masm.guardedCallPreBarrier(argAddr, MIRType::Value);
2713     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
2714     masm.storeValue(R0, argAddr);
2715 
2716     MOZ_ASSERT(frame.numUnsyncedSlots() == 0);
2717 
2718     Register temp = R1.scratchReg();
2719 
2720     // Reload the arguments object
2721     Register reg = R2.scratchReg();
2722     masm.loadPtr(
2723         Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfArgsObj()),
2724         reg);
2725 
2726     Label skipBarrier;
2727 
2728     masm.branchPtrInNurseryChunk(Assembler::Equal, reg, temp, &skipBarrier);
2729     masm.branchValueIsNurseryCell(Assembler::NotEqual, R0, temp, &skipBarrier);
2730 
2731     masm.call(&postBarrierSlot_);
2732 
2733     masm.bind(&skipBarrier);
2734   }
2735 
2736   masm.bind(&done);
2737   return true;
2738 }
2739 
emit_JSOP_GETARG()2740 bool BaselineCompiler::emit_JSOP_GETARG() {
2741   uint32_t arg = GET_ARGNO(pc);
2742   return emitFormalArgAccess(arg, /* get = */ true);
2743 }
2744 
emit_JSOP_SETARG()2745 bool BaselineCompiler::emit_JSOP_SETARG() {
2746   // Ionmonkey can't inline functions with SETARG with magic arguments.
2747   if (!script->argsObjAliasesFormals() && script->argumentsAliasesFormals())
2748     script->setUninlineable();
2749 
2750   modifiesArguments_ = true;
2751 
2752   uint32_t arg = GET_ARGNO(pc);
2753   return emitFormalArgAccess(arg, /* get = */ false);
2754 }
2755 
emit_JSOP_NEWTARGET()2756 bool BaselineCompiler::emit_JSOP_NEWTARGET() {
2757   if (script->isForEval()) {
2758     frame.pushEvalNewTarget();
2759     return true;
2760   }
2761 
2762   MOZ_ASSERT(function());
2763   frame.syncStack(0);
2764 
2765   if (function()->isArrow()) {
2766     // Arrow functions store their |new.target| value in an
2767     // extended slot.
2768     Register scratch = R0.scratchReg();
2769     masm.loadFunctionFromCalleeToken(frame.addressOfCalleeToken(), scratch);
2770     masm.loadValue(
2771         Address(scratch, FunctionExtended::offsetOfArrowNewTargetSlot()), R0);
2772     frame.push(R0);
2773     return true;
2774   }
2775 
2776   // if (isConstructing()) push(argv[Max(numActualArgs, numFormalArgs)])
2777   Label notConstructing, done;
2778   masm.branchTestPtr(Assembler::Zero, frame.addressOfCalleeToken(),
2779                      Imm32(CalleeToken_FunctionConstructing), &notConstructing);
2780 
2781   Register argvLen = R0.scratchReg();
2782 
2783   Address actualArgs(BaselineFrameReg, BaselineFrame::offsetOfNumActualArgs());
2784   masm.loadPtr(actualArgs, argvLen);
2785 
2786   Label useNFormals;
2787 
2788   masm.branchPtr(Assembler::Below, argvLen, Imm32(function()->nargs()),
2789                  &useNFormals);
2790 
2791   {
2792     BaseValueIndex newTarget(BaselineFrameReg, argvLen,
2793                              BaselineFrame::offsetOfArg(0));
2794     masm.loadValue(newTarget, R0);
2795     masm.jump(&done);
2796   }
2797 
2798   masm.bind(&useNFormals);
2799 
2800   {
2801     Address newTarget(
2802         BaselineFrameReg,
2803         BaselineFrame::offsetOfArg(0) + (function()->nargs() * sizeof(Value)));
2804     masm.loadValue(newTarget, R0);
2805     masm.jump(&done);
2806   }
2807 
2808   // else push(undefined)
2809   masm.bind(&notConstructing);
2810   masm.moveValue(UndefinedValue(), R0);
2811 
2812   masm.bind(&done);
2813   frame.push(R0);
2814 
2815   return true;
2816 }
2817 
2818 typedef bool (*ThrowRuntimeLexicalErrorFn)(JSContext* cx, unsigned);
2819 static const VMFunction ThrowRuntimeLexicalErrorInfo =
2820     FunctionInfo<ThrowRuntimeLexicalErrorFn>(jit::ThrowRuntimeLexicalError,
2821                                              "ThrowRuntimeLexicalError");
2822 
emitThrowConstAssignment()2823 bool BaselineCompiler::emitThrowConstAssignment() {
2824   prepareVMCall();
2825   pushArg(Imm32(JSMSG_BAD_CONST_ASSIGN));
2826   return callVM(ThrowRuntimeLexicalErrorInfo);
2827 }
2828 
emit_JSOP_THROWSETCONST()2829 bool BaselineCompiler::emit_JSOP_THROWSETCONST() {
2830   return emitThrowConstAssignment();
2831 }
2832 
emit_JSOP_THROWSETALIASEDCONST()2833 bool BaselineCompiler::emit_JSOP_THROWSETALIASEDCONST() {
2834   return emitThrowConstAssignment();
2835 }
2836 
emit_JSOP_THROWSETCALLEE()2837 bool BaselineCompiler::emit_JSOP_THROWSETCALLEE() {
2838   return emitThrowConstAssignment();
2839 }
2840 
emitUninitializedLexicalCheck(const ValueOperand & val)2841 bool BaselineCompiler::emitUninitializedLexicalCheck(const ValueOperand& val) {
2842   Label done;
2843   masm.branchTestMagicValue(Assembler::NotEqual, val, JS_UNINITIALIZED_LEXICAL,
2844                             &done);
2845 
2846   prepareVMCall();
2847   pushArg(Imm32(JSMSG_UNINITIALIZED_LEXICAL));
2848   if (!callVM(ThrowRuntimeLexicalErrorInfo)) return false;
2849 
2850   masm.bind(&done);
2851   return true;
2852 }
2853 
emit_JSOP_CHECKLEXICAL()2854 bool BaselineCompiler::emit_JSOP_CHECKLEXICAL() {
2855   frame.syncStack(0);
2856   masm.loadValue(frame.addressOfLocal(GET_LOCALNO(pc)), R0);
2857   return emitUninitializedLexicalCheck(R0);
2858 }
2859 
emit_JSOP_INITLEXICAL()2860 bool BaselineCompiler::emit_JSOP_INITLEXICAL() { return emit_JSOP_SETLOCAL(); }
2861 
emit_JSOP_INITGLEXICAL()2862 bool BaselineCompiler::emit_JSOP_INITGLEXICAL() {
2863   frame.popRegsAndSync(1);
2864   frame.push(ObjectValue(script->global().lexicalEnvironment()));
2865   frame.push(R0);
2866   return emit_JSOP_SETPROP();
2867 }
2868 
emit_JSOP_CHECKALIASEDLEXICAL()2869 bool BaselineCompiler::emit_JSOP_CHECKALIASEDLEXICAL() {
2870   frame.syncStack(0);
2871   masm.loadValue(getEnvironmentCoordinateAddress(R0.scratchReg()), R0);
2872   return emitUninitializedLexicalCheck(R0);
2873 }
2874 
emit_JSOP_INITALIASEDLEXICAL()2875 bool BaselineCompiler::emit_JSOP_INITALIASEDLEXICAL() {
2876   return emit_JSOP_SETALIASEDVAR();
2877 }
2878 
emit_JSOP_UNINITIALIZED()2879 bool BaselineCompiler::emit_JSOP_UNINITIALIZED() {
2880   frame.push(MagicValue(JS_UNINITIALIZED_LEXICAL));
2881   return true;
2882 }
2883 
emitCall()2884 bool BaselineCompiler::emitCall() {
2885   MOZ_ASSERT(IsCallPC(pc));
2886 
2887   bool construct = JSOp(*pc) == JSOP_NEW || JSOp(*pc) == JSOP_SUPERCALL;
2888   uint32_t argc = GET_ARGC(pc);
2889 
2890   frame.syncStack(0);
2891   masm.move32(Imm32(argc), R0.scratchReg());
2892 
2893   // Call IC
2894   ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ construct,
2895                                          /* isSpread = */ false);
2896   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
2897 
2898   // Update FrameInfo.
2899   frame.popn(2 + argc + construct);
2900   frame.push(R0);
2901   return true;
2902 }
2903 
emitSpreadCall()2904 bool BaselineCompiler::emitSpreadCall() {
2905   MOZ_ASSERT(IsCallPC(pc));
2906 
2907   frame.syncStack(0);
2908   masm.move32(Imm32(1), R0.scratchReg());
2909 
2910   // Call IC
2911   bool construct =
2912       JSOp(*pc) == JSOP_SPREADNEW || JSOp(*pc) == JSOP_SPREADSUPERCALL;
2913   ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ construct,
2914                                          /* isSpread = */ true);
2915   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
2916 
2917   // Update FrameInfo.
2918   frame.popn(3 + construct);
2919   frame.push(R0);
2920   return true;
2921 }
2922 
emit_JSOP_CALL()2923 bool BaselineCompiler::emit_JSOP_CALL() { return emitCall(); }
2924 
emit_JSOP_CALL_IGNORES_RV()2925 bool BaselineCompiler::emit_JSOP_CALL_IGNORES_RV() { return emitCall(); }
2926 
emit_JSOP_CALLITER()2927 bool BaselineCompiler::emit_JSOP_CALLITER() { return emitCall(); }
2928 
emit_JSOP_NEW()2929 bool BaselineCompiler::emit_JSOP_NEW() { return emitCall(); }
2930 
emit_JSOP_SUPERCALL()2931 bool BaselineCompiler::emit_JSOP_SUPERCALL() { return emitCall(); }
2932 
emit_JSOP_FUNCALL()2933 bool BaselineCompiler::emit_JSOP_FUNCALL() { return emitCall(); }
2934 
emit_JSOP_FUNAPPLY()2935 bool BaselineCompiler::emit_JSOP_FUNAPPLY() { return emitCall(); }
2936 
emit_JSOP_EVAL()2937 bool BaselineCompiler::emit_JSOP_EVAL() { return emitCall(); }
2938 
emit_JSOP_STRICTEVAL()2939 bool BaselineCompiler::emit_JSOP_STRICTEVAL() { return emitCall(); }
2940 
emit_JSOP_SPREADCALL()2941 bool BaselineCompiler::emit_JSOP_SPREADCALL() { return emitSpreadCall(); }
2942 
emit_JSOP_SPREADNEW()2943 bool BaselineCompiler::emit_JSOP_SPREADNEW() { return emitSpreadCall(); }
2944 
emit_JSOP_SPREADSUPERCALL()2945 bool BaselineCompiler::emit_JSOP_SPREADSUPERCALL() { return emitSpreadCall(); }
2946 
emit_JSOP_SPREADEVAL()2947 bool BaselineCompiler::emit_JSOP_SPREADEVAL() { return emitSpreadCall(); }
2948 
emit_JSOP_STRICTSPREADEVAL()2949 bool BaselineCompiler::emit_JSOP_STRICTSPREADEVAL() { return emitSpreadCall(); }
2950 
2951 typedef bool (*OptimizeSpreadCallFn)(JSContext*, HandleValue, bool*);
2952 static const VMFunction OptimizeSpreadCallInfo =
2953     FunctionInfo<OptimizeSpreadCallFn>(OptimizeSpreadCall,
2954                                        "OptimizeSpreadCall");
2955 
emit_JSOP_OPTIMIZE_SPREADCALL()2956 bool BaselineCompiler::emit_JSOP_OPTIMIZE_SPREADCALL() {
2957   frame.syncStack(0);
2958   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
2959 
2960   prepareVMCall();
2961   pushArg(R0);
2962 
2963   if (!callVM(OptimizeSpreadCallInfo)) return false;
2964 
2965   masm.boxNonDouble(JSVAL_TYPE_BOOLEAN, ReturnReg, R0);
2966   frame.push(R0);
2967   return true;
2968 }
2969 
2970 typedef bool (*ImplicitThisFn)(JSContext*, HandleObject, HandlePropertyName,
2971                                MutableHandleValue);
2972 const VMFunction jit::ImplicitThisInfo = FunctionInfo<ImplicitThisFn>(
2973     ImplicitThisOperation, "ImplicitThisOperation");
2974 
emit_JSOP_IMPLICITTHIS()2975 bool BaselineCompiler::emit_JSOP_IMPLICITTHIS() {
2976   frame.syncStack(0);
2977   masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
2978 
2979   prepareVMCall();
2980 
2981   pushArg(ImmGCPtr(script->getName(pc)));
2982   pushArg(R0.scratchReg());
2983 
2984   if (!callVM(ImplicitThisInfo)) return false;
2985 
2986   frame.push(R0);
2987   return true;
2988 }
2989 
emit_JSOP_GIMPLICITTHIS()2990 bool BaselineCompiler::emit_JSOP_GIMPLICITTHIS() {
2991   if (!script->hasNonSyntacticScope()) {
2992     frame.push(UndefinedValue());
2993     return true;
2994   }
2995 
2996   return emit_JSOP_IMPLICITTHIS();
2997 }
2998 
emit_JSOP_INSTANCEOF()2999 bool BaselineCompiler::emit_JSOP_INSTANCEOF() {
3000   frame.popRegsAndSync(2);
3001 
3002   ICInstanceOf_Fallback::Compiler stubCompiler(cx);
3003   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
3004 
3005   frame.push(R0);
3006   return true;
3007 }
3008 
emit_JSOP_TYPEOF()3009 bool BaselineCompiler::emit_JSOP_TYPEOF() {
3010   frame.popRegsAndSync(1);
3011 
3012   ICTypeOf_Fallback::Compiler stubCompiler(cx);
3013   if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false;
3014 
3015   frame.push(R0);
3016   return true;
3017 }
3018 
emit_JSOP_TYPEOFEXPR()3019 bool BaselineCompiler::emit_JSOP_TYPEOFEXPR() { return emit_JSOP_TYPEOF(); }
3020 
3021 typedef bool (*ThrowMsgFn)(JSContext*, const unsigned);
3022 static const VMFunction ThrowMsgInfo =
3023     FunctionInfo<ThrowMsgFn>(js::ThrowMsgOperation, "ThrowMsgOperation");
3024 
emit_JSOP_THROWMSG()3025 bool BaselineCompiler::emit_JSOP_THROWMSG() {
3026   prepareVMCall();
3027   pushArg(Imm32(GET_UINT16(pc)));
3028   return callVM(ThrowMsgInfo);
3029 }
3030 
3031 typedef bool (*ThrowFn)(JSContext*, HandleValue);
3032 static const VMFunction ThrowInfo = FunctionInfo<ThrowFn>(js::Throw, "Throw");
3033 
emit_JSOP_THROW()3034 bool BaselineCompiler::emit_JSOP_THROW() {
3035   // Keep value to throw in R0.
3036   frame.popRegsAndSync(1);
3037 
3038   prepareVMCall();
3039   pushArg(R0);
3040 
3041   return callVM(ThrowInfo);
3042 }
3043 
3044 typedef bool (*ThrowingFn)(JSContext*, HandleValue);
3045 static const VMFunction ThrowingInfo =
3046     FunctionInfo<ThrowingFn>(js::ThrowingOperation, "ThrowingOperation");
3047 
emit_JSOP_THROWING()3048 bool BaselineCompiler::emit_JSOP_THROWING() {
3049   // Keep value to throw in R0.
3050   frame.popRegsAndSync(1);
3051 
3052   prepareVMCall();
3053   pushArg(R0);
3054 
3055   return callVM(ThrowingInfo);
3056 }
3057 
emit_JSOP_TRY()3058 bool BaselineCompiler::emit_JSOP_TRY() {
3059   if (!emit_JSOP_JUMPTARGET()) return false;
3060 
3061   // Ionmonkey can't inline function with JSOP_TRY.
3062   script->setUninlineable();
3063   return true;
3064 }
3065 
emit_JSOP_FINALLY()3066 bool BaselineCompiler::emit_JSOP_FINALLY() {
3067   // JSOP_FINALLY has a def count of 2, but these values are already on the
3068   // stack (they're pushed by JSOP_GOSUB). Update the compiler's stack state.
3069   frame.setStackDepth(frame.stackDepth() + 2);
3070 
3071   // To match the interpreter, emit an interrupt check at the start of the
3072   // finally block.
3073   return emitInterruptCheck();
3074 }
3075 
emit_JSOP_GOSUB()3076 bool BaselineCompiler::emit_JSOP_GOSUB() {
3077   // Push |false| so that RETSUB knows the value on top of the
3078   // stack is not an exception but the offset to the op following
3079   // this GOSUB.
3080   frame.push(BooleanValue(false));
3081 
3082   int32_t nextOffset = script->pcToOffset(GetNextPc(pc));
3083   frame.push(Int32Value(nextOffset));
3084 
3085   // Jump to the finally block.
3086   frame.syncStack(0);
3087   jsbytecode* target = pc + GET_JUMP_OFFSET(pc);
3088   masm.jump(labelOf(target));
3089   return true;
3090 }
3091 
emit_JSOP_RETSUB()3092 bool BaselineCompiler::emit_JSOP_RETSUB() {
3093   frame.popRegsAndSync(2);
3094 
3095   ICRetSub_Fallback::Compiler stubCompiler(cx);
3096   return emitOpIC(stubCompiler.getStub(&stubSpace_));
3097 }
3098 
3099 typedef bool (*PushLexicalEnvFn)(JSContext*, BaselineFrame*,
3100                                  Handle<LexicalScope*>);
3101 static const VMFunction PushLexicalEnvInfo =
3102     FunctionInfo<PushLexicalEnvFn>(jit::PushLexicalEnv, "PushLexicalEnv");
3103 
emit_JSOP_PUSHLEXICALENV()3104 bool BaselineCompiler::emit_JSOP_PUSHLEXICALENV() {
3105   LexicalScope& scope = script->getScope(pc)->as<LexicalScope>();
3106 
3107   // Call a stub to push the block on the block chain.
3108   prepareVMCall();
3109   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
3110 
3111   pushArg(ImmGCPtr(&scope));
3112   pushArg(R0.scratchReg());
3113 
3114   return callVM(PushLexicalEnvInfo);
3115 }
3116 
3117 typedef bool (*PopLexicalEnvFn)(JSContext*, BaselineFrame*);
3118 static const VMFunction PopLexicalEnvInfo =
3119     FunctionInfo<PopLexicalEnvFn>(jit::PopLexicalEnv, "PopLexicalEnv");
3120 
3121 typedef bool (*DebugLeaveThenPopLexicalEnvFn)(JSContext*, BaselineFrame*,
3122                                               jsbytecode*);
3123 static const VMFunction DebugLeaveThenPopLexicalEnvInfo =
3124     FunctionInfo<DebugLeaveThenPopLexicalEnvFn>(
3125         jit::DebugLeaveThenPopLexicalEnv, "DebugLeaveThenPopLexicalEnv");
3126 
emit_JSOP_POPLEXICALENV()3127 bool BaselineCompiler::emit_JSOP_POPLEXICALENV() {
3128   prepareVMCall();
3129 
3130   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
3131 
3132   if (compileDebugInstrumentation_) {
3133     pushArg(ImmPtr(pc));
3134     pushArg(R0.scratchReg());
3135     return callVM(DebugLeaveThenPopLexicalEnvInfo);
3136   }
3137 
3138   pushArg(R0.scratchReg());
3139   return callVM(PopLexicalEnvInfo);
3140 }
3141 
3142 typedef bool (*FreshenLexicalEnvFn)(JSContext*, BaselineFrame*);
3143 static const VMFunction FreshenLexicalEnvInfo =
3144     FunctionInfo<FreshenLexicalEnvFn>(jit::FreshenLexicalEnv,
3145                                       "FreshenLexicalEnv");
3146 
3147 typedef bool (*DebugLeaveThenFreshenLexicalEnvFn)(JSContext*, BaselineFrame*,
3148                                                   jsbytecode*);
3149 static const VMFunction DebugLeaveThenFreshenLexicalEnvInfo =
3150     FunctionInfo<DebugLeaveThenFreshenLexicalEnvFn>(
3151         jit::DebugLeaveThenFreshenLexicalEnv,
3152         "DebugLeaveThenFreshenLexicalEnv");
3153 
emit_JSOP_FRESHENLEXICALENV()3154 bool BaselineCompiler::emit_JSOP_FRESHENLEXICALENV() {
3155   prepareVMCall();
3156 
3157   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
3158 
3159   if (compileDebugInstrumentation_) {
3160     pushArg(ImmPtr(pc));
3161     pushArg(R0.scratchReg());
3162     return callVM(DebugLeaveThenFreshenLexicalEnvInfo);
3163   }
3164 
3165   pushArg(R0.scratchReg());
3166   return callVM(FreshenLexicalEnvInfo);
3167 }
3168 
3169 typedef bool (*RecreateLexicalEnvFn)(JSContext*, BaselineFrame*);
3170 static const VMFunction RecreateLexicalEnvInfo =
3171     FunctionInfo<RecreateLexicalEnvFn>(jit::RecreateLexicalEnv,
3172                                        "RecreateLexicalEnv");
3173 
3174 typedef bool (*DebugLeaveThenRecreateLexicalEnvFn)(JSContext*, BaselineFrame*,
3175                                                    jsbytecode*);
3176 static const VMFunction DebugLeaveThenRecreateLexicalEnvInfo =
3177     FunctionInfo<DebugLeaveThenRecreateLexicalEnvFn>(
3178         jit::DebugLeaveThenRecreateLexicalEnv,
3179         "DebugLeaveThenRecreateLexicalEnv");
3180 
emit_JSOP_RECREATELEXICALENV()3181 bool BaselineCompiler::emit_JSOP_RECREATELEXICALENV() {
3182   prepareVMCall();
3183 
3184   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
3185 
3186   if (compileDebugInstrumentation_) {
3187     pushArg(ImmPtr(pc));
3188     pushArg(R0.scratchReg());
3189     return callVM(DebugLeaveThenRecreateLexicalEnvInfo);
3190   }
3191 
3192   pushArg(R0.scratchReg());
3193   return callVM(RecreateLexicalEnvInfo);
3194 }
3195 
3196 typedef bool (*DebugLeaveLexicalEnvFn)(JSContext*, BaselineFrame*, jsbytecode*);
3197 static const VMFunction DebugLeaveLexicalEnvInfo =
3198     FunctionInfo<DebugLeaveLexicalEnvFn>(jit::DebugLeaveLexicalEnv,
3199                                          "DebugLeaveLexicalEnv");
3200 
emit_JSOP_DEBUGLEAVELEXICALENV()3201 bool BaselineCompiler::emit_JSOP_DEBUGLEAVELEXICALENV() {
3202   if (!compileDebugInstrumentation_) return true;
3203 
3204   prepareVMCall();
3205   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
3206   pushArg(ImmPtr(pc));
3207   pushArg(R0.scratchReg());
3208 
3209   return callVM(DebugLeaveLexicalEnvInfo);
3210 }
3211 
3212 typedef bool (*PushVarEnvFn)(JSContext*, BaselineFrame*, HandleScope);
3213 static const VMFunction PushVarEnvInfo =
3214     FunctionInfo<PushVarEnvFn>(jit::PushVarEnv, "PushVarEnv");
3215 
emit_JSOP_PUSHVARENV()3216 bool BaselineCompiler::emit_JSOP_PUSHVARENV() {
3217   prepareVMCall();
3218   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
3219   pushArg(ImmGCPtr(script->getScope(pc)));
3220   pushArg(R0.scratchReg());
3221 
3222   return callVM(PushVarEnvInfo);
3223 }
3224 
3225 typedef bool (*PopVarEnvFn)(JSContext*, BaselineFrame*);
3226 static const VMFunction PopVarEnvInfo =
3227     FunctionInfo<PopVarEnvFn>(jit::PopVarEnv, "PopVarEnv");
3228 
emit_JSOP_POPVARENV()3229 bool BaselineCompiler::emit_JSOP_POPVARENV() {
3230   prepareVMCall();
3231   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
3232   pushArg(R0.scratchReg());
3233 
3234   return callVM(PopVarEnvInfo);
3235 }
3236 
3237 typedef bool (*EnterWithFn)(JSContext*, BaselineFrame*, HandleValue,
3238                             Handle<WithScope*>);
3239 static const VMFunction EnterWithInfo =
3240     FunctionInfo<EnterWithFn>(jit::EnterWith, "EnterWith");
3241 
emit_JSOP_ENTERWITH()3242 bool BaselineCompiler::emit_JSOP_ENTERWITH() {
3243   WithScope& withScope = script->getScope(pc)->as<WithScope>();
3244 
3245   // Pop "with" object to R0.
3246   frame.popRegsAndSync(1);
3247 
3248   // Call a stub to push the object onto the environment chain.
3249   prepareVMCall();
3250   masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
3251 
3252   pushArg(ImmGCPtr(&withScope));
3253   pushArg(R0);
3254   pushArg(R1.scratchReg());
3255 
3256   return callVM(EnterWithInfo);
3257 }
3258 
3259 typedef bool (*LeaveWithFn)(JSContext*, BaselineFrame*);
3260 static const VMFunction LeaveWithInfo =
3261     FunctionInfo<LeaveWithFn>(jit::LeaveWith, "LeaveWith");
3262 
emit_JSOP_LEAVEWITH()3263 bool BaselineCompiler::emit_JSOP_LEAVEWITH() {
3264   // Call a stub to pop the with object from the environment chain.
3265   prepareVMCall();
3266 
3267   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
3268   pushArg(R0.scratchReg());
3269 
3270   return callVM(LeaveWithInfo);
3271 }
3272 
3273 typedef bool (*GetAndClearExceptionFn)(JSContext*, MutableHandleValue);
3274 static const VMFunction GetAndClearExceptionInfo =
3275     FunctionInfo<GetAndClearExceptionFn>(GetAndClearException,
3276                                          "GetAndClearException");
3277 
emit_JSOP_EXCEPTION()3278 bool BaselineCompiler::emit_JSOP_EXCEPTION() {
3279   prepareVMCall();
3280 
3281   if (!callVM(GetAndClearExceptionInfo)) return false;
3282 
3283   frame.push(R0);
3284   return true;
3285 }
3286 
3287 typedef bool (*OnDebuggerStatementFn)(JSContext*, BaselineFrame*,
3288                                       jsbytecode* pc, bool*);
3289 static const VMFunction OnDebuggerStatementInfo =
3290     FunctionInfo<OnDebuggerStatementFn>(jit::OnDebuggerStatement,
3291                                         "OnDebuggerStatement");
3292 
emit_JSOP_DEBUGGER()3293 bool BaselineCompiler::emit_JSOP_DEBUGGER() {
3294   prepareVMCall();
3295   pushArg(ImmPtr(pc));
3296 
3297   frame.assertSyncedStack();
3298   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
3299   pushArg(R0.scratchReg());
3300 
3301   if (!callVM(OnDebuggerStatementInfo)) return false;
3302 
3303   // If the stub returns |true|, return the frame's return value.
3304   Label done;
3305   masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &done);
3306   {
3307     masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
3308     masm.jump(&return_);
3309   }
3310   masm.bind(&done);
3311   return true;
3312 }
3313 
3314 typedef bool (*DebugEpilogueFn)(JSContext*, BaselineFrame*, jsbytecode*);
3315 static const VMFunction DebugEpilogueInfo = FunctionInfo<DebugEpilogueFn>(
3316     jit::DebugEpilogueOnBaselineReturn, "DebugEpilogueOnBaselineReturn");
3317 
emitReturn()3318 bool BaselineCompiler::emitReturn() {
3319   if (compileDebugInstrumentation_) {
3320     // Move return value into the frame's rval slot.
3321     masm.storeValue(JSReturnOperand, frame.addressOfReturnValue());
3322     masm.or32(Imm32(BaselineFrame::HAS_RVAL), frame.addressOfFlags());
3323 
3324     // Load BaselineFrame pointer in R0.
3325     frame.syncStack(0);
3326     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
3327 
3328     prepareVMCall();
3329     pushArg(ImmPtr(pc));
3330     pushArg(R0.scratchReg());
3331     if (!callVM(DebugEpilogueInfo)) return false;
3332 
3333     // Fix up the fake ICEntry appended by callVM for on-stack recompilation.
3334     icEntries_.back().setFakeKind(ICEntry::Kind_DebugEpilogue);
3335 
3336     masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
3337   }
3338 
3339   // Only emit the jump if this JSOP_RETRVAL is not the last instruction.
3340   // Not needed for last instruction, because last instruction flows
3341   // into return label.
3342   if (pc + GetBytecodeLength(pc) < script->codeEnd()) masm.jump(&return_);
3343 
3344   return true;
3345 }
3346 
emit_JSOP_RETURN()3347 bool BaselineCompiler::emit_JSOP_RETURN() {
3348   MOZ_ASSERT(frame.stackDepth() == 1);
3349 
3350   frame.popValue(JSReturnOperand);
3351   return emitReturn();
3352 }
3353 
emitLoadReturnValue(ValueOperand val)3354 void BaselineCompiler::emitLoadReturnValue(ValueOperand val) {
3355   Label done, noRval;
3356   masm.branchTest32(Assembler::Zero, frame.addressOfFlags(),
3357                     Imm32(BaselineFrame::HAS_RVAL), &noRval);
3358   masm.loadValue(frame.addressOfReturnValue(), val);
3359   masm.jump(&done);
3360 
3361   masm.bind(&noRval);
3362   masm.moveValue(UndefinedValue(), val);
3363 
3364   masm.bind(&done);
3365 }
3366 
emit_JSOP_RETRVAL()3367 bool BaselineCompiler::emit_JSOP_RETRVAL() {
3368   MOZ_ASSERT(frame.stackDepth() == 0);
3369 
3370   masm.moveValue(UndefinedValue(), JSReturnOperand);
3371 
3372   if (!script->noScriptRval()) {
3373     // Return the value in the return value slot, if any.
3374     Label done;
3375     Address flags = frame.addressOfFlags();
3376     masm.branchTest32(Assembler::Zero, flags, Imm32(BaselineFrame::HAS_RVAL),
3377                       &done);
3378     masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
3379     masm.bind(&done);
3380   }
3381 
3382   return emitReturn();
3383 }
3384 
3385 typedef bool (*ToIdFn)(JSContext*, HandleValue, MutableHandleValue);
3386 static const VMFunction ToIdInfo =
3387     FunctionInfo<ToIdFn>(js::ToIdOperation, "ToIdOperation");
3388 
emit_JSOP_TOID()3389 bool BaselineCompiler::emit_JSOP_TOID() {
3390   // Load index in R0, but keep values on the stack for the decompiler.
3391   frame.syncStack(0);
3392   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
3393 
3394   // No-op if the index is trivally convertable to an id.
3395   Label done;
3396   masm.branchTestInt32(Assembler::Equal, R0, &done);
3397   masm.branchTestString(Assembler::Equal, R0, &done);
3398   masm.branchTestSymbol(Assembler::Equal, R0, &done);
3399 
3400   prepareVMCall();
3401 
3402   pushArg(R0);
3403 
3404   if (!callVM(ToIdInfo)) return false;
3405 
3406   masm.bind(&done);
3407   frame.pop();  // Pop index.
3408   frame.push(R0);
3409   return true;
3410 }
3411 
3412 typedef JSObject* (*ToAsyncFn)(JSContext*, HandleFunction);
3413 static const VMFunction ToAsyncInfo =
3414     FunctionInfo<ToAsyncFn>(js::WrapAsyncFunction, "ToAsync");
3415 
emit_JSOP_TOASYNC()3416 bool BaselineCompiler::emit_JSOP_TOASYNC() {
3417   frame.syncStack(0);
3418   masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
3419 
3420   prepareVMCall();
3421   pushArg(R0.scratchReg());
3422 
3423   if (!callVM(ToAsyncInfo)) return false;
3424 
3425   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
3426   frame.pop();
3427   frame.push(R0);
3428   return true;
3429 }
3430 
3431 typedef JSObject* (*ToAsyncGenFn)(JSContext*, HandleFunction);
3432 static const VMFunction ToAsyncGenInfo =
3433     FunctionInfo<ToAsyncGenFn>(js::WrapAsyncGenerator, "ToAsyncGen");
3434 
emit_JSOP_TOASYNCGEN()3435 bool BaselineCompiler::emit_JSOP_TOASYNCGEN() {
3436   frame.syncStack(0);
3437   masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
3438 
3439   prepareVMCall();
3440   pushArg(R0.scratchReg());
3441 
3442   if (!callVM(ToAsyncGenInfo)) return false;
3443 
3444   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
3445   frame.pop();
3446   frame.push(R0);
3447   return true;
3448 }
3449 
3450 typedef JSObject* (*ToAsyncIterFn)(JSContext*, HandleObject, HandleValue);
3451 static const VMFunction ToAsyncIterInfo =
3452     FunctionInfo<ToAsyncIterFn>(js::CreateAsyncFromSyncIterator, "ToAsyncIter");
3453 
emit_JSOP_TOASYNCITER()3454 bool BaselineCompiler::emit_JSOP_TOASYNCITER() {
3455   frame.syncStack(0);
3456   masm.unboxObject(frame.addressOfStackValue(frame.peek(-2)), R0.scratchReg());
3457   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
3458 
3459   prepareVMCall();
3460   pushArg(R1);
3461   pushArg(R0.scratchReg());
3462 
3463   if (!callVM(ToAsyncIterInfo)) return false;
3464 
3465   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
3466   frame.popn(2);
3467   frame.push(R0);
3468   return true;
3469 }
3470 
3471 typedef bool (*ThrowObjectCoercibleFn)(JSContext*, HandleValue);
3472 static const VMFunction ThrowObjectCoercibleInfo =
3473     FunctionInfo<ThrowObjectCoercibleFn>(ThrowObjectCoercible,
3474                                          "ThrowObjectCoercible");
3475 
emit_JSOP_CHECKOBJCOERCIBLE()3476 bool BaselineCompiler::emit_JSOP_CHECKOBJCOERCIBLE() {
3477   frame.syncStack(0);
3478   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
3479 
3480   Label fail, done;
3481 
3482   masm.branchTestUndefined(Assembler::Equal, R0, &fail);
3483   masm.branchTestNull(Assembler::NotEqual, R0, &done);
3484 
3485   masm.bind(&fail);
3486   prepareVMCall();
3487 
3488   pushArg(R0);
3489 
3490   if (!callVM(ThrowObjectCoercibleInfo)) return false;
3491 
3492   masm.bind(&done);
3493   return true;
3494 }
3495 
3496 typedef JSString* (*ToStringFn)(JSContext*, HandleValue);
3497 static const VMFunction ToStringInfo =
3498     FunctionInfo<ToStringFn>(ToStringSlow, "ToStringSlow");
3499 
emit_JSOP_TOSTRING()3500 bool BaselineCompiler::emit_JSOP_TOSTRING() {
3501   // Keep top stack value in R0.
3502   frame.popRegsAndSync(1);
3503 
3504   // Inline path for string.
3505   Label done;
3506   masm.branchTestString(Assembler::Equal, R0, &done);
3507 
3508   prepareVMCall();
3509 
3510   pushArg(R0);
3511 
3512   // Call ToStringSlow which doesn't handle string inputs.
3513   if (!callVM(ToStringInfo)) return false;
3514 
3515   masm.tagValue(JSVAL_TYPE_STRING, ReturnReg, R0);
3516 
3517   masm.bind(&done);
3518   frame.push(R0);
3519   return true;
3520 }
3521 
emit_JSOP_TABLESWITCH()3522 bool BaselineCompiler::emit_JSOP_TABLESWITCH() {
3523   frame.popRegsAndSync(1);
3524 
3525   // Call IC.
3526   ICTableSwitch::Compiler compiler(cx, pc);
3527   return emitOpIC(compiler.getStub(&stubSpace_));
3528 }
3529 
emit_JSOP_ITER()3530 bool BaselineCompiler::emit_JSOP_ITER() {
3531   frame.popRegsAndSync(1);
3532 
3533   ICGetIterator_Fallback::Compiler compiler(cx);
3534   if (!emitOpIC(compiler.getStub(&stubSpace_))) return false;
3535 
3536   frame.push(R0);
3537   return true;
3538 }
3539 
emit_JSOP_MOREITER()3540 bool BaselineCompiler::emit_JSOP_MOREITER() {
3541   frame.syncStack(0);
3542   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
3543 
3544   ICIteratorMore_Fallback::Compiler compiler(cx);
3545   if (!emitOpIC(compiler.getStub(&stubSpace_))) return false;
3546 
3547   frame.push(R0);
3548   return true;
3549 }
3550 
emitIsMagicValue()3551 bool BaselineCompiler::emitIsMagicValue() {
3552   frame.syncStack(0);
3553 
3554   Label isMagic, done;
3555   masm.branchTestMagic(Assembler::Equal,
3556                        frame.addressOfStackValue(frame.peek(-1)), &isMagic);
3557   masm.moveValue(BooleanValue(false), R0);
3558   masm.jump(&done);
3559 
3560   masm.bind(&isMagic);
3561   masm.moveValue(BooleanValue(true), R0);
3562 
3563   masm.bind(&done);
3564   frame.push(R0, JSVAL_TYPE_BOOLEAN);
3565   return true;
3566 }
3567 
emit_JSOP_ISNOITER()3568 bool BaselineCompiler::emit_JSOP_ISNOITER() { return emitIsMagicValue(); }
3569 
emit_JSOP_ENDITER()3570 bool BaselineCompiler::emit_JSOP_ENDITER() {
3571   if (!emit_JSOP_JUMPTARGET()) return false;
3572   frame.popRegsAndSync(1);
3573 
3574   ICIteratorClose_Fallback::Compiler compiler(cx);
3575   return emitOpIC(compiler.getStub(&stubSpace_));
3576 }
3577 
emit_JSOP_ISGENCLOSING()3578 bool BaselineCompiler::emit_JSOP_ISGENCLOSING() { return emitIsMagicValue(); }
3579 
emit_JSOP_GETRVAL()3580 bool BaselineCompiler::emit_JSOP_GETRVAL() {
3581   frame.syncStack(0);
3582 
3583   emitLoadReturnValue(R0);
3584 
3585   frame.push(R0);
3586   return true;
3587 }
3588 
emit_JSOP_SETRVAL()3589 bool BaselineCompiler::emit_JSOP_SETRVAL() {
3590   // Store to the frame's return value slot.
3591   storeValue(frame.peek(-1), frame.addressOfReturnValue(), R2);
3592   masm.or32(Imm32(BaselineFrame::HAS_RVAL), frame.addressOfFlags());
3593   frame.pop();
3594   return true;
3595 }
3596 
emit_JSOP_CALLEE()3597 bool BaselineCompiler::emit_JSOP_CALLEE() {
3598   MOZ_ASSERT(function());
3599   frame.syncStack(0);
3600   masm.loadFunctionFromCalleeToken(frame.addressOfCalleeToken(),
3601                                    R0.scratchReg());
3602   masm.tagValue(JSVAL_TYPE_OBJECT, R0.scratchReg(), R0);
3603   frame.push(R0);
3604   return true;
3605 }
3606 
getThisEnvironmentCallee(Register reg)3607 void BaselineCompiler::getThisEnvironmentCallee(Register reg) {
3608   // Directly load callee from frame if we have a HomeObject
3609   if (function() && function()->allowSuperProperty()) {
3610     masm.loadFunctionFromCalleeToken(frame.addressOfCalleeToken(), reg);
3611     return;
3612   }
3613 
3614   // Locate environment chain
3615   masm.loadPtr(frame.addressOfEnvironmentChain(), reg);
3616 
3617   // Walk environment chain until first non-arrow CallObject
3618   for (ScopeIter si(script->innermostScope(pc)); si; si++) {
3619     // Find first non-arrow FunctionScope
3620     if (si.hasSyntacticEnvironment() && si.scope()->is<FunctionScope>()) {
3621       JSFunction* fn = si.scope()->as<FunctionScope>().canonicalFunction();
3622 
3623       if (!fn->isArrow()) break;
3624     }
3625 
3626     // Traverse environment chain
3627     if (si.scope()->hasEnvironment()) {
3628       Address nextAddr(reg, EnvironmentObject::offsetOfEnclosingEnvironment());
3629       masm.unboxObject(nextAddr, reg);
3630     }
3631   }
3632 
3633   // Load callee
3634   masm.unboxObject(Address(reg, CallObject::offsetOfCallee()), reg);
3635 }
3636 
3637 typedef JSObject* (*HomeObjectSuperBaseFn)(JSContext*, HandleObject);
3638 static const VMFunction HomeObjectSuperBaseInfo =
3639     FunctionInfo<HomeObjectSuperBaseFn>(HomeObjectSuperBase,
3640                                         "HomeObjectSuperBase");
3641 
emit_JSOP_SUPERBASE()3642 bool BaselineCompiler::emit_JSOP_SUPERBASE() {
3643   frame.syncStack(0);
3644 
3645   Register scratch = R0.scratchReg();
3646   Register proto = R1.scratchReg();
3647 
3648   // Lookup callee object of environment containing [[ThisValue]]
3649   getThisEnvironmentCallee(scratch);
3650 
3651   // Load [[HomeObject]]
3652   Address homeObjAddr(scratch,
3653                       FunctionExtended::offsetOfMethodHomeObjectSlot());
3654 #ifdef DEBUG
3655   Label isObject;
3656   masm.branchTestObject(Assembler::Equal, homeObjAddr, &isObject);
3657   masm.assumeUnreachable("[[HomeObject]] must be Object");
3658   masm.bind(&isObject);
3659 #endif
3660   masm.unboxObject(homeObjAddr, scratch);
3661 
3662   // Load prototype from [[HomeObject]]
3663   masm.loadObjProto(scratch, proto);
3664 
3665   Label hasProto;
3666   MOZ_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
3667   masm.branchPtr(Assembler::Above, proto, ImmWord(1), &hasProto);
3668 
3669   // Use VMCall for missing or lazy proto
3670   prepareVMCall();
3671   pushArg(scratch);  // [[HomeObject]]
3672   if (!callVM(HomeObjectSuperBaseInfo)) return false;
3673   masm.movePtr(ReturnReg, proto);
3674 
3675   // Box prototype and return
3676   masm.bind(&hasProto);
3677   masm.tagValue(JSVAL_TYPE_OBJECT, proto, R1);
3678   frame.push(R1);
3679   return true;
3680 }
3681 
3682 typedef JSObject* (*SuperFunOperationFn)(JSContext*, HandleObject);
3683 static const VMFunction SuperFunOperationInfo =
3684     FunctionInfo<SuperFunOperationFn>(SuperFunOperation, "SuperFunOperation");
3685 
emit_JSOP_SUPERFUN()3686 bool BaselineCompiler::emit_JSOP_SUPERFUN() {
3687   frame.syncStack(0);
3688 
3689   Register callee = R0.scratchReg();
3690   Register proto = R1.scratchReg();
3691   Register scratch = R2.scratchReg();
3692 
3693   // Lookup callee object of environment containing [[ThisValue]]
3694   getThisEnvironmentCallee(callee);
3695 
3696   // Load prototype of callee
3697   masm.loadObjProto(callee, proto);
3698 
3699   // Use VMCall for missing or lazy proto
3700   Label needVMCall;
3701   MOZ_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
3702   masm.branchPtr(Assembler::BelowOrEqual, proto, ImmWord(1), &needVMCall);
3703 
3704   // Use VMCall for non-JSFunction objects (eg. Proxy)
3705   masm.branchTestObjClass(Assembler::NotEqual, proto, &JSFunction::class_,
3706                           scratch, proto, &needVMCall);
3707 
3708   // Use VMCall if not constructor
3709   masm.load16ZeroExtend(Address(proto, JSFunction::offsetOfFlags()), scratch);
3710   masm.branchTest32(Assembler::Zero, scratch, Imm32(JSFunction::CONSTRUCTOR),
3711                     &needVMCall);
3712 
3713   // Valid constructor
3714   Label hasSuperFun;
3715   masm.jump(&hasSuperFun);
3716 
3717   // Slow path VM Call
3718   masm.bind(&needVMCall);
3719   prepareVMCall();
3720   pushArg(callee);
3721   if (!callVM(SuperFunOperationInfo)) return false;
3722   masm.movePtr(ReturnReg, proto);
3723 
3724   // Box prototype and return
3725   masm.bind(&hasSuperFun);
3726   masm.tagValue(JSVAL_TYPE_OBJECT, proto, R1);
3727   frame.push(R1);
3728   return true;
3729 }
3730 
3731 typedef bool (*NewArgumentsObjectFn)(JSContext*, BaselineFrame*,
3732                                      MutableHandleValue);
3733 static const VMFunction NewArgumentsObjectInfo =
3734     FunctionInfo<NewArgumentsObjectFn>(jit::NewArgumentsObject,
3735                                        "NewArgumentsObject");
3736 
emit_JSOP_ARGUMENTS()3737 bool BaselineCompiler::emit_JSOP_ARGUMENTS() {
3738   frame.syncStack(0);
3739 
3740   Label done;
3741   if (!script->argumentsHasVarBinding() || !script->needsArgsObj()) {
3742     // We assume the script does not need an arguments object. However, this
3743     // assumption can be invalidated later, see argumentsOptimizationFailed
3744     // in JSScript. Because we can't invalidate baseline JIT code, we set a
3745     // flag on BaselineScript when that happens and guard on it here.
3746     masm.moveValue(MagicValue(JS_OPTIMIZED_ARGUMENTS), R0);
3747 
3748     // Load script->baseline.
3749     Register scratch = R1.scratchReg();
3750     masm.movePtr(ImmGCPtr(script), scratch);
3751     masm.loadPtr(Address(scratch, JSScript::offsetOfBaselineScript()), scratch);
3752 
3753     // If we don't need an arguments object, skip the VM call.
3754     masm.branchTest32(Assembler::Zero,
3755                       Address(scratch, BaselineScript::offsetOfFlags()),
3756                       Imm32(BaselineScript::NEEDS_ARGS_OBJ), &done);
3757   }
3758 
3759   prepareVMCall();
3760 
3761   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
3762   pushArg(R0.scratchReg());
3763 
3764   if (!callVM(NewArgumentsObjectInfo)) return false;
3765 
3766   masm.bind(&done);
3767   frame.push(R0);
3768   return true;
3769 }
3770 
3771 typedef bool (*RunOnceScriptPrologueFn)(JSContext*, HandleScript);
3772 static const VMFunction RunOnceScriptPrologueInfo =
3773     FunctionInfo<RunOnceScriptPrologueFn>(js::RunOnceScriptPrologue,
3774                                           "RunOnceScriptPrologue");
3775 
emit_JSOP_RUNONCE()3776 bool BaselineCompiler::emit_JSOP_RUNONCE() {
3777   frame.syncStack(0);
3778 
3779   prepareVMCall();
3780 
3781   masm.movePtr(ImmGCPtr(script), R0.scratchReg());
3782   pushArg(R0.scratchReg());
3783 
3784   return callVM(RunOnceScriptPrologueInfo);
3785 }
3786 
emit_JSOP_REST()3787 bool BaselineCompiler::emit_JSOP_REST() {
3788   frame.syncStack(0);
3789 
3790   ArrayObject* templateObject = ObjectGroup::newArrayObject(
3791       cx, nullptr, 0, TenuredObject, ObjectGroup::NewArrayKind::UnknownIndex);
3792   if (!templateObject) return false;
3793 
3794   // Call IC.
3795   ICRest_Fallback::Compiler compiler(cx, templateObject);
3796   if (!emitOpIC(compiler.getStub(&stubSpace_))) return false;
3797 
3798   // Mark R0 as pushed stack value.
3799   frame.push(R0);
3800   return true;
3801 }
3802 
3803 typedef JSObject* (*CreateGeneratorFn)(JSContext*, BaselineFrame*);
3804 static const VMFunction CreateGeneratorInfo =
3805     FunctionInfo<CreateGeneratorFn>(jit::CreateGenerator, "CreateGenerator");
3806 
emit_JSOP_GENERATOR()3807 bool BaselineCompiler::emit_JSOP_GENERATOR() {
3808   MOZ_ASSERT(frame.stackDepth() == 0);
3809 
3810   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
3811 
3812   prepareVMCall();
3813   pushArg(R0.scratchReg());
3814   if (!callVM(CreateGeneratorInfo)) return false;
3815 
3816   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
3817   frame.push(R0);
3818   return true;
3819 }
3820 
addYieldAndAwaitOffset()3821 bool BaselineCompiler::addYieldAndAwaitOffset() {
3822   MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD ||
3823              *pc == JSOP_AWAIT);
3824 
3825   uint32_t yieldAndAwaitIndex = GET_UINT24(pc);
3826 
3827   while (yieldAndAwaitIndex >= yieldAndAwaitOffsets_.length()) {
3828     if (!yieldAndAwaitOffsets_.append(0)) return false;
3829   }
3830 
3831   static_assert(
3832       JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH &&
3833           JSOP_INITIALYIELD_LENGTH == JSOP_AWAIT_LENGTH,
3834       "code below assumes INITIALYIELD and YIELD and AWAIT have same length");
3835   yieldAndAwaitOffsets_[yieldAndAwaitIndex] =
3836       script->pcToOffset(pc + JSOP_YIELD_LENGTH);
3837   return true;
3838 }
3839 
emit_JSOP_INITIALYIELD()3840 bool BaselineCompiler::emit_JSOP_INITIALYIELD() {
3841   if (!addYieldAndAwaitOffset()) return false;
3842 
3843   frame.syncStack(0);
3844   MOZ_ASSERT(frame.stackDepth() == 1);
3845 
3846   Register genObj = R2.scratchReg();
3847   masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), genObj);
3848 
3849   MOZ_ASSERT(GET_UINT24(pc) == 0);
3850   masm.storeValue(
3851       Int32Value(0),
3852       Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
3853 
3854   Register envObj = R0.scratchReg();
3855   Address envChainSlot(genObj, GeneratorObject::offsetOfEnvironmentChainSlot());
3856   masm.loadPtr(frame.addressOfEnvironmentChain(), envObj);
3857   masm.guardedCallPreBarrier(envChainSlot, MIRType::Value);
3858   masm.storeValue(JSVAL_TYPE_OBJECT, envObj, envChainSlot);
3859 
3860   Register temp = R1.scratchReg();
3861   Label skipBarrier;
3862   masm.branchPtrInNurseryChunk(Assembler::Equal, genObj, temp, &skipBarrier);
3863   masm.branchPtrInNurseryChunk(Assembler::NotEqual, envObj, temp, &skipBarrier);
3864   masm.push(genObj);
3865   MOZ_ASSERT(genObj == R2.scratchReg());
3866   masm.call(&postBarrierSlot_);
3867   masm.pop(genObj);
3868   masm.bind(&skipBarrier);
3869 
3870   masm.tagValue(JSVAL_TYPE_OBJECT, genObj, JSReturnOperand);
3871   return emitReturn();
3872 }
3873 
3874 typedef bool (*NormalSuspendFn)(JSContext*, HandleObject, BaselineFrame*,
3875                                 jsbytecode*, uint32_t);
3876 static const VMFunction NormalSuspendInfo =
3877     FunctionInfo<NormalSuspendFn>(jit::NormalSuspend, "NormalSuspend");
3878 
emit_JSOP_YIELD()3879 bool BaselineCompiler::emit_JSOP_YIELD() {
3880   if (!addYieldAndAwaitOffset()) return false;
3881 
3882   // Store generator in R0.
3883   frame.popRegsAndSync(1);
3884 
3885   Register genObj = R2.scratchReg();
3886   masm.unboxObject(R0, genObj);
3887 
3888   MOZ_ASSERT(frame.stackDepth() >= 1);
3889 
3890   if (frame.stackDepth() == 1) {
3891     // If the expression stack is empty, we can inline the YIELD.
3892 
3893     masm.storeValue(
3894         Int32Value(GET_UINT24(pc)),
3895         Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
3896 
3897     Register envObj = R0.scratchReg();
3898     Address envChainSlot(genObj,
3899                          GeneratorObject::offsetOfEnvironmentChainSlot());
3900     masm.loadPtr(frame.addressOfEnvironmentChain(), envObj);
3901     masm.guardedCallPreBarrier(envChainSlot, MIRType::Value);
3902     masm.storeValue(JSVAL_TYPE_OBJECT, envObj, envChainSlot);
3903 
3904     Register temp = R1.scratchReg();
3905     Label skipBarrier;
3906     masm.branchPtrInNurseryChunk(Assembler::Equal, genObj, temp, &skipBarrier);
3907     masm.branchPtrInNurseryChunk(Assembler::NotEqual, envObj, temp,
3908                                  &skipBarrier);
3909     MOZ_ASSERT(genObj == R2.scratchReg());
3910     masm.call(&postBarrierSlot_);
3911     masm.bind(&skipBarrier);
3912   } else {
3913     masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
3914 
3915     prepareVMCall();
3916     pushArg(Imm32(frame.stackDepth()));
3917     pushArg(ImmPtr(pc));
3918     pushArg(R1.scratchReg());
3919     pushArg(genObj);
3920 
3921     if (!callVM(NormalSuspendInfo)) return false;
3922   }
3923 
3924   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), JSReturnOperand);
3925   return emitReturn();
3926 }
3927 
emit_JSOP_AWAIT()3928 bool BaselineCompiler::emit_JSOP_AWAIT() { return emit_JSOP_YIELD(); }
3929 
3930 typedef bool (*DebugAfterYieldFn)(JSContext*, BaselineFrame*);
3931 static const VMFunction DebugAfterYieldInfo =
3932     FunctionInfo<DebugAfterYieldFn>(jit::DebugAfterYield, "DebugAfterYield");
3933 
emit_JSOP_DEBUGAFTERYIELD()3934 bool BaselineCompiler::emit_JSOP_DEBUGAFTERYIELD() {
3935   if (!compileDebugInstrumentation_) return true;
3936 
3937   frame.assertSyncedStack();
3938   masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
3939   prepareVMCall();
3940   pushArg(R0.scratchReg());
3941   return callVM(DebugAfterYieldInfo);
3942 }
3943 
3944 typedef bool (*FinalSuspendFn)(JSContext*, HandleObject, jsbytecode*);
3945 static const VMFunction FinalSuspendInfo =
3946     FunctionInfo<FinalSuspendFn>(jit::FinalSuspend, "FinalSuspend");
3947 
emit_JSOP_FINALYIELDRVAL()3948 bool BaselineCompiler::emit_JSOP_FINALYIELDRVAL() {
3949   // Store generator in R0.
3950   frame.popRegsAndSync(1);
3951   masm.unboxObject(R0, R0.scratchReg());
3952 
3953   prepareVMCall();
3954   pushArg(ImmPtr(pc));
3955   pushArg(R0.scratchReg());
3956 
3957   if (!callVM(FinalSuspendInfo)) return false;
3958 
3959   masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
3960   return emitReturn();
3961 }
3962 
3963 typedef bool (*InterpretResumeFn)(JSContext*, HandleObject, HandleValue,
3964                                   HandlePropertyName, MutableHandleValue);
3965 static const VMFunction InterpretResumeInfo =
3966     FunctionInfo<InterpretResumeFn>(jit::InterpretResume, "InterpretResume");
3967 
3968 typedef bool (*GeneratorThrowFn)(JSContext*, BaselineFrame*,
3969                                  Handle<GeneratorObject*>, HandleValue,
3970                                  uint32_t);
3971 static const VMFunction GeneratorThrowInfo = FunctionInfo<GeneratorThrowFn>(
3972     jit::GeneratorThrowOrReturn, "GeneratorThrowOrReturn", TailCall);
3973 
emit_JSOP_RESUME()3974 bool BaselineCompiler::emit_JSOP_RESUME() {
3975   GeneratorObject::ResumeKind resumeKind = GeneratorObject::getResumeKind(pc);
3976 
3977   frame.syncStack(0);
3978   masm.assertStackAlignment(sizeof(Value), 0);
3979 
3980   AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
3981   regs.take(BaselineFrameReg);
3982 
3983   // Load generator object.
3984   Register genObj = regs.takeAny();
3985   masm.unboxObject(frame.addressOfStackValue(frame.peek(-2)), genObj);
3986 
3987   // Load callee.
3988   Register callee = regs.takeAny();
3989   masm.unboxObject(Address(genObj, GeneratorObject::offsetOfCalleeSlot()),
3990                    callee);
3991 
3992   // Load the script. Note that we don't relazify generator scripts, so it's
3993   // guaranteed to be non-lazy.
3994   Register scratch1 = regs.takeAny();
3995   masm.loadPtr(Address(callee, JSFunction::offsetOfScript()), scratch1);
3996 
3997   // Load the BaselineScript or call a stub if we don't have one.
3998   Label interpret;
3999   masm.loadPtr(Address(scratch1, JSScript::offsetOfBaselineScript()), scratch1);
4000   masm.branchPtr(Assembler::BelowOrEqual, scratch1,
4001                  ImmPtr(BASELINE_DISABLED_SCRIPT), &interpret);
4002 
4003 #ifdef JS_TRACE_LOGGING
4004   if (!emitTraceLoggerResume(scratch1, regs)) return false;
4005 #endif
4006 
4007   Register constructing = regs.takeAny();
4008   ValueOperand newTarget = regs.takeAnyValue();
4009   masm.loadValue(Address(genObj, GeneratorObject::offsetOfNewTargetSlot()),
4010                  newTarget);
4011   masm.move32(Imm32(0), constructing);
4012   {
4013     Label notConstructing;
4014     masm.branchTestObject(Assembler::NotEqual, newTarget, &notConstructing);
4015     masm.pushValue(newTarget);
4016     masm.move32(Imm32(CalleeToken_FunctionConstructing), constructing);
4017     masm.bind(&notConstructing);
4018   }
4019   regs.add(newTarget);
4020 
4021   // Push |undefined| for all formals.
4022   Register scratch2 = regs.takeAny();
4023   Label loop, loopDone;
4024   masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), scratch2);
4025   masm.bind(&loop);
4026   masm.branchTest32(Assembler::Zero, scratch2, scratch2, &loopDone);
4027   {
4028     masm.pushValue(UndefinedValue());
4029     masm.sub32(Imm32(1), scratch2);
4030     masm.jump(&loop);
4031   }
4032   masm.bind(&loopDone);
4033 
4034   // Push |undefined| for |this|.
4035   masm.pushValue(UndefinedValue());
4036 
4037   // Update BaselineFrame frameSize field and create the frame descriptor.
4038   masm.computeEffectiveAddress(
4039       Address(BaselineFrameReg, BaselineFrame::FramePointerOffset), scratch2);
4040   masm.subStackPtrFrom(scratch2);
4041   masm.store32(scratch2, Address(BaselineFrameReg,
4042                                  BaselineFrame::reverseOffsetOfFrameSize()));
4043   masm.makeFrameDescriptor(scratch2, JitFrame_BaselineJS,
4044                            JitFrameLayout::Size());
4045 
4046   masm.Push(Imm32(0));  // actual argc
4047 
4048   // Duplicate PushCalleeToken with a variable instead.
4049   masm.orPtr(constructing, callee);
4050   masm.Push(callee);
4051   masm.Push(scratch2);  // frame descriptor
4052 
4053   regs.add(callee);
4054   regs.add(constructing);
4055 
4056   // Load the return value.
4057   ValueOperand retVal = regs.takeAnyValue();
4058   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), retVal);
4059 
4060   // Push a fake return address on the stack. We will resume here when the
4061   // generator returns.
4062   Label genStart, returnTarget;
4063 #ifdef JS_USE_LINK_REGISTER
4064   masm.call(&genStart);
4065 #else
4066   masm.callAndPushReturnAddress(&genStart);
4067 #endif
4068 
4069   // Add an IC entry so the return offset -> pc mapping works.
4070   if (!appendICEntry(ICEntry::Kind_Op, masm.currentOffset())) return false;
4071 
4072   masm.jump(&returnTarget);
4073   masm.bind(&genStart);
4074 #ifdef JS_USE_LINK_REGISTER
4075   masm.pushReturnAddress();
4076 #endif
4077 
4078   // If profiler instrumentation is on, update lastProfilingFrame on
4079   // current JitActivation
4080   {
4081     Register scratchReg = scratch2;
4082     Label skip;
4083     AbsoluteAddress addressOfEnabled(
4084         cx->runtime()->geckoProfiler().addressOfEnabled());
4085     masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skip);
4086     masm.loadJSContext(scratchReg);
4087     masm.loadPtr(Address(scratchReg, JSContext::offsetOfProfilingActivation()),
4088                  scratchReg);
4089     masm.storeStackPtr(
4090         Address(scratchReg, JitActivation::offsetOfLastProfilingFrame()));
4091     masm.bind(&skip);
4092   }
4093 
4094   // Construct BaselineFrame.
4095   masm.push(BaselineFrameReg);
4096   masm.moveStackPtrTo(BaselineFrameReg);
4097   masm.subFromStackPtr(Imm32(BaselineFrame::Size()));
4098   masm.assertStackAlignment(sizeof(Value), 0);
4099 
4100   // Store flags and env chain.
4101   masm.store32(Imm32(BaselineFrame::HAS_INITIAL_ENV), frame.addressOfFlags());
4102   masm.unboxObject(
4103       Address(genObj, GeneratorObject::offsetOfEnvironmentChainSlot()),
4104       scratch2);
4105   masm.storePtr(scratch2, frame.addressOfEnvironmentChain());
4106 
4107   // Store the arguments object if there is one.
4108   Label noArgsObj;
4109   Address argsObjSlot(genObj, GeneratorObject::offsetOfArgsObjSlot());
4110   masm.branchTestUndefined(Assembler::Equal, argsObjSlot, &noArgsObj);
4111   masm.unboxObject(argsObjSlot, scratch2);
4112   {
4113     masm.storePtr(scratch2, frame.addressOfArgsObj());
4114     masm.or32(Imm32(BaselineFrame::HAS_ARGS_OBJ), frame.addressOfFlags());
4115   }
4116   masm.bind(&noArgsObj);
4117 
4118   // Push expression slots if needed.
4119   Label noExprStack;
4120   Address exprStackSlot(genObj, GeneratorObject::offsetOfExpressionStackSlot());
4121   masm.branchTestNull(Assembler::Equal, exprStackSlot, &noExprStack);
4122   {
4123     masm.unboxObject(exprStackSlot, scratch2);
4124 
4125     Register initLength = regs.takeAny();
4126     masm.loadPtr(Address(scratch2, NativeObject::offsetOfElements()), scratch2);
4127     masm.load32(Address(scratch2, ObjectElements::offsetOfInitializedLength()),
4128                 initLength);
4129     masm.store32(
4130         Imm32(0),
4131         Address(scratch2, ObjectElements::offsetOfInitializedLength()));
4132 
4133     Label loop, loopDone;
4134     masm.bind(&loop);
4135     masm.branchTest32(Assembler::Zero, initLength, initLength, &loopDone);
4136     {
4137       masm.pushValue(Address(scratch2, 0));
4138       masm.guardedCallPreBarrier(Address(scratch2, 0), MIRType::Value);
4139       masm.addPtr(Imm32(sizeof(Value)), scratch2);
4140       masm.sub32(Imm32(1), initLength);
4141       masm.jump(&loop);
4142     }
4143     masm.bind(&loopDone);
4144     regs.add(initLength);
4145   }
4146 
4147   masm.bind(&noExprStack);
4148   masm.pushValue(retVal);
4149 
4150   if (resumeKind == GeneratorObject::NEXT) {
4151     // Determine the resume address based on the yieldAndAwaitIndex and the
4152     // yieldAndAwaitIndex -> native table in the BaselineScript.
4153     masm.load32(Address(scratch1, BaselineScript::offsetOfYieldEntriesOffset()),
4154                 scratch2);
4155     masm.addPtr(scratch2, scratch1);
4156     masm.unboxInt32(
4157         Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()),
4158         scratch2);
4159     masm.loadPtr(
4160         BaseIndex(scratch1, scratch2, ScaleFromElemWidth(sizeof(uintptr_t))),
4161         scratch1);
4162 
4163     // Mark as running and jump to the generator's JIT code.
4164     masm.storeValue(
4165         Int32Value(GeneratorObject::YIELD_AND_AWAIT_INDEX_RUNNING),
4166         Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
4167     masm.jump(scratch1);
4168   } else {
4169     MOZ_ASSERT(resumeKind == GeneratorObject::THROW ||
4170                resumeKind == GeneratorObject::RETURN);
4171 
4172     // Update the frame's frameSize field.
4173     masm.computeEffectiveAddress(
4174         Address(BaselineFrameReg, BaselineFrame::FramePointerOffset), scratch2);
4175     masm.movePtr(scratch2, scratch1);
4176     masm.subStackPtrFrom(scratch2);
4177     masm.store32(scratch2, Address(BaselineFrameReg,
4178                                    BaselineFrame::reverseOffsetOfFrameSize()));
4179     masm.loadBaselineFramePtr(BaselineFrameReg, scratch2);
4180 
4181     prepareVMCall();
4182     pushArg(Imm32(resumeKind));
4183     pushArg(retVal);
4184     pushArg(genObj);
4185     pushArg(scratch2);
4186 
4187     TrampolinePtr code =
4188         cx->runtime()->jitRuntime()->getVMWrapper(GeneratorThrowInfo);
4189 
4190     // Create the frame descriptor.
4191     masm.subStackPtrFrom(scratch1);
4192     masm.makeFrameDescriptor(scratch1, JitFrame_BaselineJS,
4193                              ExitFrameLayout::Size());
4194 
4195     // Push the frame descriptor and a dummy return address (it doesn't
4196     // matter what we push here, frame iterators will use the frame pc
4197     // set in jit::GeneratorThrowOrReturn).
4198     masm.push(scratch1);
4199 
4200     // On ARM64, the callee will push the return address.
4201 #ifndef JS_CODEGEN_ARM64
4202     masm.push(ImmWord(0));
4203 #endif
4204     masm.jump(code);
4205   }
4206 
4207   // If the generator script has no JIT code, call into the VM.
4208   masm.bind(&interpret);
4209 
4210   prepareVMCall();
4211   if (resumeKind == GeneratorObject::NEXT) {
4212     pushArg(ImmGCPtr(cx->names().next));
4213   } else if (resumeKind == GeneratorObject::THROW) {
4214     pushArg(ImmGCPtr(cx->names().throw_));
4215   } else {
4216     MOZ_ASSERT(resumeKind == GeneratorObject::RETURN);
4217     pushArg(ImmGCPtr(cx->names().return_));
4218   }
4219 
4220   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), retVal);
4221   pushArg(retVal);
4222   pushArg(genObj);
4223 
4224   if (!callVM(InterpretResumeInfo)) return false;
4225 
4226   // After the generator returns, we restore the stack pointer, push the
4227   // return value and we're done.
4228   masm.bind(&returnTarget);
4229   masm.computeEffectiveAddress(frame.addressOfStackValue(frame.peek(-1)),
4230                                masm.getStackPointer());
4231   frame.popn(2);
4232   frame.push(R0);
4233   return true;
4234 }
4235 
4236 typedef bool (*CheckSelfHostedFn)(JSContext*, HandleValue);
4237 static const VMFunction CheckSelfHostedInfo = FunctionInfo<CheckSelfHostedFn>(
4238     js::Debug_CheckSelfHosted, "Debug_CheckSelfHosted");
4239 
emit_JSOP_DEBUGCHECKSELFHOSTED()4240 bool BaselineCompiler::emit_JSOP_DEBUGCHECKSELFHOSTED() {
4241 #ifdef DEBUG
4242   frame.syncStack(0);
4243 
4244   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
4245 
4246   prepareVMCall();
4247   pushArg(R0);
4248   if (!callVM(CheckSelfHostedInfo)) return false;
4249 #endif
4250   return true;
4251 }
4252 
emit_JSOP_IS_CONSTRUCTING()4253 bool BaselineCompiler::emit_JSOP_IS_CONSTRUCTING() {
4254   frame.push(MagicValue(JS_IS_CONSTRUCTING));
4255   return true;
4256 }
4257 
emit_JSOP_JUMPTARGET()4258 bool BaselineCompiler::emit_JSOP_JUMPTARGET() {
4259   if (!script->hasScriptCounts()) return true;
4260   PCCounts* counts = script->maybeGetPCCounts(pc);
4261   uint64_t* counterAddr = &counts->numExec();
4262   masm.inc64(AbsoluteAddress(counterAddr));
4263   return true;
4264 }
4265 
4266 typedef bool (*CheckClassHeritageOperationFn)(JSContext*, HandleValue);
4267 static const VMFunction CheckClassHeritageOperationInfo =
4268     FunctionInfo<CheckClassHeritageOperationFn>(js::CheckClassHeritageOperation,
4269                                                 "CheckClassHeritageOperation");
4270 
emit_JSOP_CHECKCLASSHERITAGE()4271 bool BaselineCompiler::emit_JSOP_CHECKCLASSHERITAGE() {
4272   frame.syncStack(0);
4273 
4274   // Leave the heritage value on the stack.
4275   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
4276 
4277   prepareVMCall();
4278   pushArg(R0);
4279   return callVM(CheckClassHeritageOperationInfo);
4280 }
4281 
emit_JSOP_INITHOMEOBJECT()4282 bool BaselineCompiler::emit_JSOP_INITHOMEOBJECT() {
4283   frame.syncStack(0);
4284 
4285   // Load HomeObject off stack
4286   unsigned skipOver = GET_UINT8(pc);
4287   MOZ_ASSERT(frame.stackDepth() >= skipOver + 2);
4288   masm.loadValue(frame.addressOfStackValue(frame.peek(-2 - skipOver)), R0);
4289 
4290   // Load function off stack
4291   Register func = R2.scratchReg();
4292   masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), func);
4293 
4294   // Set HOMEOBJECT_SLOT
4295   Address addr(func, FunctionExtended::offsetOfMethodHomeObjectSlot());
4296 #ifdef DEBUG
4297   Label isUndefined;
4298   masm.branchTestUndefined(Assembler::Equal, addr, &isUndefined);
4299   masm.assumeUnreachable("INITHOMEOBJECT expects undefined slot");
4300   masm.bind(&isUndefined);
4301 #endif
4302   masm.storeValue(R0, addr);
4303 
4304   Register temp = R1.scratchReg();
4305   Label skipBarrier;
4306   masm.branchPtrInNurseryChunk(Assembler::Equal, func, temp, &skipBarrier);
4307   masm.branchValueIsNurseryObject(Assembler::NotEqual, R0, temp, &skipBarrier);
4308   masm.call(&postBarrierSlot_);
4309   masm.bind(&skipBarrier);
4310 
4311   return true;
4312 }
4313 
emit_JSOP_BUILTINPROTO()4314 bool BaselineCompiler::emit_JSOP_BUILTINPROTO() {
4315   // The builtin prototype is a constant for a given global.
4316   JSProtoKey key = static_cast<JSProtoKey>(GET_UINT8(pc));
4317   MOZ_ASSERT(key < JSProto_LIMIT);
4318   JSObject* builtin = GlobalObject::getOrCreatePrototype(cx, key);
4319   if (!builtin) return false;
4320   frame.push(ObjectValue(*builtin));
4321   return true;
4322 }
4323 
4324 typedef JSObject* (*ObjectWithProtoOperationFn)(JSContext*, HandleValue);
4325 static const VMFunction ObjectWithProtoOperationInfo =
4326     FunctionInfo<ObjectWithProtoOperationFn>(js::ObjectWithProtoOperation,
4327                                              "ObjectWithProtoOperationInfo");
4328 
emit_JSOP_OBJWITHPROTO()4329 bool BaselineCompiler::emit_JSOP_OBJWITHPROTO() {
4330   frame.syncStack(0);
4331 
4332   // Leave the proto value on the stack for the decompiler
4333   masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
4334 
4335   prepareVMCall();
4336   pushArg(R0);
4337   if (!callVM(ObjectWithProtoOperationInfo)) return false;
4338 
4339   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
4340   frame.pop();
4341   frame.push(R0);
4342   return true;
4343 }
4344 
4345 typedef JSObject* (*FunWithProtoFn)(JSContext*, HandleFunction, HandleObject,
4346                                     HandleObject);
4347 static const VMFunction FunWithProtoInfo = FunctionInfo<FunWithProtoFn>(
4348     js::FunWithProtoOperation, "FunWithProtoOperation");
4349 
emit_JSOP_FUNWITHPROTO()4350 bool BaselineCompiler::emit_JSOP_FUNWITHPROTO() {
4351   frame.popRegsAndSync(1);
4352 
4353   masm.unboxObject(R0, R0.scratchReg());
4354   masm.loadPtr(frame.addressOfEnvironmentChain(), R1.scratchReg());
4355 
4356   prepareVMCall();
4357   pushArg(R0.scratchReg());
4358   pushArg(R1.scratchReg());
4359   pushArg(ImmGCPtr(script->getFunction(GET_UINT32_INDEX(pc))));
4360   if (!callVM(FunWithProtoInfo)) return false;
4361 
4362   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
4363   frame.push(R0);
4364   return true;
4365 }
4366 
4367 typedef JSFunction* (*MakeDefaultConstructorFn)(JSContext*, HandleScript,
4368                                                 jsbytecode*, HandleObject);
4369 static const VMFunction MakeDefaultConstructorInfo =
4370     FunctionInfo<MakeDefaultConstructorFn>(js::MakeDefaultConstructor,
4371                                            "MakeDefaultConstructor");
4372 
emit_JSOP_CLASSCONSTRUCTOR()4373 bool BaselineCompiler::emit_JSOP_CLASSCONSTRUCTOR() {
4374   frame.syncStack(0);
4375 
4376   // Pass nullptr as prototype to MakeDefaultConstructor
4377   prepareVMCall();
4378   pushArg(ImmPtr(nullptr));
4379   pushArg(ImmPtr(pc));
4380   pushArg(ImmGCPtr(script));
4381   if (!callVM(MakeDefaultConstructorInfo)) return false;
4382 
4383   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
4384   frame.push(R0);
4385   return true;
4386 }
4387 
emit_JSOP_DERIVEDCONSTRUCTOR()4388 bool BaselineCompiler::emit_JSOP_DERIVEDCONSTRUCTOR() {
4389   frame.popRegsAndSync(1);
4390 
4391   masm.unboxObject(R0, R0.scratchReg());
4392 
4393   prepareVMCall();
4394   pushArg(R0.scratchReg());
4395   pushArg(ImmPtr(pc));
4396   pushArg(ImmGCPtr(script));
4397   if (!callVM(MakeDefaultConstructorInfo)) return false;
4398 
4399   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
4400   frame.push(R0);
4401   return true;
4402 }
4403