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