js/src/jit/BaselineCompiler.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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/. */
     7 #include "jit/BaselineCompiler.h"
     9 #include "jit/BaselineHelpers.h"
    10 #include "jit/BaselineIC.h"
    11 #include "jit/BaselineJIT.h"
    12 #include "jit/FixedList.h"
    13 #include "jit/IonAnalysis.h"
    14 #include "jit/IonLinker.h"
    15 #include "jit/IonSpewer.h"
    16 #ifdef JS_ION_PERF
    17 # include "jit/PerfSpewer.h"
    18 #endif
    19 #include "jit/VMFunctions.h"
    20 #include "vm/TraceLogging.h"
    22 #include "jsscriptinlines.h"
    24 #include "vm/Interpreter-inl.h"
    26 using namespace js;
    27 using namespace js::jit;
    29 BaselineCompiler::BaselineCompiler(JSContext *cx, TempAllocator &alloc, JSScript *script)
    30   : BaselineCompilerSpecific(cx, alloc, script),
    31     modifiesArguments_(false)
    32 {
    33 }
    35 bool
    36 BaselineCompiler::init()
    37 {
    38     if (!analysis_.init(alloc_, cx->runtime()->gsnCache))
    39         return false;
    41     if (!labels_.init(alloc_, script->length()))
    42         return false;
    44     for (size_t i = 0; i < script->length(); i++)
    45         new (&labels_[i]) Label();
    47     if (!frame.init(alloc_))
    48         return false;
    50     return true;
    51 }
    53 bool
    54 BaselineCompiler::addPCMappingEntry(bool addIndexEntry)
    55 {
    56     // Don't add multiple entries for a single pc.
    57     size_t nentries = pcMappingEntries_.length();
    58     if (nentries > 0 && pcMappingEntries_[nentries - 1].pcOffset == script->pcToOffset(pc))
    59         return true;
    61     PCMappingEntry entry;
    62     entry.pcOffset = script->pcToOffset(pc);
    63     entry.nativeOffset = masm.currentOffset();
    64     entry.slotInfo = getStackTopSlotInfo();
    65     entry.addIndexEntry = addIndexEntry;
    67     return pcMappingEntries_.append(entry);
    68 }
    70 MethodStatus
    71 BaselineCompiler::compile()
    72 {
    73     IonSpew(IonSpew_BaselineScripts, "Baseline compiling script %s:%d (%p)",
    74             script->filename(), script->lineno(), script);
    76     IonSpew(IonSpew_Codegen, "# Emitting baseline code for script %s:%d",
    77             script->filename(), script->lineno());
    79     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
    80     AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script));
    81     AutoTraceLog logCompile(logger, TraceLogger::BaselineCompilation);
    83     if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
    84         return Method_Error;
    86     // Pin analysis info during compilation.
    87     types::AutoEnterAnalysis autoEnterAnalysis(cx);
    89     JS_ASSERT(!script->hasBaselineScript());
    91     if (!emitPrologue())
    92         return Method_Error;
    94     MethodStatus status = emitBody();
    95     if (status != Method_Compiled)
    96         return status;
    98     if (!emitEpilogue())
    99         return Method_Error;
   101 #ifdef JSGC_GENERATIONAL
   102     if (!emitOutOfLinePostBarrierSlot())
   103         return Method_Error;
   104 #endif
   106     if (masm.oom())
   107         return Method_Error;
   109     Linker linker(masm);
   110     AutoFlushICache afc("Baseline");
   111     JitCode *code = linker.newCode<CanGC>(cx, JSC::BASELINE_CODE);
   112     if (!code)
   113         return Method_Error;
   115     JSObject *templateScope = nullptr;
   116     if (script->functionNonDelazifying()) {
   117         RootedFunction fun(cx, script->functionNonDelazifying());
   118         if (fun->isHeavyweight()) {
   119             RootedScript scriptRoot(cx, script);
   120             templateScope = CallObject::createTemplateObject(cx, scriptRoot, gc::TenuredHeap);
   121             if (!templateScope)
   122                 return Method_Error;
   124             if (fun->isNamedLambda()) {
   125                 RootedObject declEnvObject(cx, DeclEnvObject::createTemplateObject(cx, fun, gc::TenuredHeap));
   126                 if (!declEnvObject)
   127                     return Method_Error;
   128                 templateScope->as<ScopeObject>().setEnclosingScope(declEnvObject);
   129             }
   130         }
   131     }
   133     // Encode the pc mapping table. See PCMappingIndexEntry for
   134     // more information.
   135     Vector<PCMappingIndexEntry> pcMappingIndexEntries(cx);
   136     CompactBufferWriter pcEntries;
   137     uint32_t previousOffset = 0;
   139     for (size_t i = 0; i < pcMappingEntries_.length(); i++) {
   140         PCMappingEntry &entry = pcMappingEntries_[i];
   141         entry.fixupNativeOffset(masm);
   143         if (entry.addIndexEntry) {
   144             PCMappingIndexEntry indexEntry;
   145             indexEntry.pcOffset = entry.pcOffset;
   146             indexEntry.nativeOffset = entry.nativeOffset;
   147             indexEntry.bufferOffset = pcEntries.length();
   148             if (!pcMappingIndexEntries.append(indexEntry))
   149                 return Method_Error;
   150             previousOffset = entry.nativeOffset;
   151         }
   153         // Use the high bit of the SlotInfo byte to indicate the
   154         // native code offset (relative to the previous op) > 0 and
   155         // comes next in the buffer.
   156         JS_ASSERT((entry.slotInfo.toByte() & 0x80) == 0);
   158         if (entry.nativeOffset == previousOffset) {
   159             pcEntries.writeByte(entry.slotInfo.toByte());
   160         } else {
   161             JS_ASSERT(entry.nativeOffset > previousOffset);
   162             pcEntries.writeByte(0x80 | entry.slotInfo.toByte());
   163             pcEntries.writeUnsigned(entry.nativeOffset - previousOffset);
   164         }
   166         previousOffset = entry.nativeOffset;
   167     }
   169     if (pcEntries.oom())
   170         return Method_Error;
   172     prologueOffset_.fixup(&masm);
   173     epilogueOffset_.fixup(&masm);
   174     spsPushToggleOffset_.fixup(&masm);
   175     postDebugPrologueOffset_.fixup(&masm);
   177     // Note: There is an extra entry in the bytecode type map for the search hint, see below.
   178     size_t bytecodeTypeMapEntries = script->nTypeSets() + 1;
   180     BaselineScript *baselineScript = BaselineScript::New(cx, prologueOffset_.offset(),
   181                                                          epilogueOffset_.offset(),
   182                                                          spsPushToggleOffset_.offset(),
   183                                                          postDebugPrologueOffset_.offset(),
   184                                                          icEntries_.length(),
   185                                                          pcMappingIndexEntries.length(),
   186                                                          pcEntries.length(),
   187                                                          bytecodeTypeMapEntries);
   188     if (!baselineScript)
   189         return Method_Error;
   191     baselineScript->setMethod(code);
   192     baselineScript->setTemplateScope(templateScope);
   194     IonSpew(IonSpew_BaselineScripts, "Created BaselineScript %p (raw %p) for %s:%d",
   195             (void *) baselineScript, (void *) code->raw(),
   196             script->filename(), script->lineno());
   198 #ifdef JS_ION_PERF
   199     writePerfSpewerBaselineProfile(script, code);
   200 #endif
   202     JS_ASSERT(pcMappingIndexEntries.length() > 0);
   203     baselineScript->copyPCMappingIndexEntries(&pcMappingIndexEntries[0]);
   205     JS_ASSERT(pcEntries.length() > 0);
   206     baselineScript->copyPCMappingEntries(pcEntries);
   208     // Copy IC entries
   209     if (icEntries_.length())
   210         baselineScript->copyICEntries(script, &icEntries_[0], masm);
   212     // Adopt fallback stubs from the compiler into the baseline script.
   213     baselineScript->adoptFallbackStubs(&stubSpace_);
   215     // Patch IC loads using IC entries
   216     for (size_t i = 0; i < icLoadLabels_.length(); i++) {
   217         CodeOffsetLabel label = icLoadLabels_[i].label;
   218         label.fixup(&masm);
   219         size_t icEntry = icLoadLabels_[i].icEntry;
   220         ICEntry *entryAddr = &(baselineScript->icEntry(icEntry));
   221         Assembler::patchDataWithValueCheck(CodeLocationLabel(code, label),
   222                                            ImmPtr(entryAddr),
   223                                            ImmPtr((void*)-1));
   224     }
   226     if (modifiesArguments_)
   227         baselineScript->setModifiesArguments();
   229     // All barriers are emitted off-by-default, toggle them on if needed.
   230     if (cx->zone()->needsBarrier())
   231         baselineScript->toggleBarriers(true);
   233     // All SPS instrumentation is emitted toggled off.  Toggle them on if needed.
   234     if (cx->runtime()->spsProfiler.enabled())
   235         baselineScript->toggleSPS(true);
   237     uint32_t *bytecodeMap = baselineScript->bytecodeTypeMap();
   238     types::FillBytecodeTypeMap(script, bytecodeMap);
   240     // The last entry in the last index found, and is used to avoid binary
   241     // searches for the sought entry when queries are in linear order.
   242     bytecodeMap[script->nTypeSets()] = 0;
   244     if (script->compartment()->debugMode())
   245         baselineScript->setDebugMode();
   247     script->setBaselineScript(cx, baselineScript);
   249     return Method_Compiled;
   250 }
   252 bool
   253 BaselineCompiler::emitPrologue()
   254 {
   255     masm.push(BaselineFrameReg);
   256     masm.mov(BaselineStackReg, BaselineFrameReg);
   258     masm.subPtr(Imm32(BaselineFrame::Size()), BaselineStackReg);
   259     masm.checkStackAlignment();
   261     // Initialize BaselineFrame. For eval scripts, the scope chain
   262     // is passed in R1, so we have to be careful not to clobber
   263     // it.
   265     // Initialize BaselineFrame::flags.
   266     uint32_t flags = 0;
   267     if (script->isForEval())
   268         flags |= BaselineFrame::EVAL;
   269     masm.store32(Imm32(flags), frame.addressOfFlags());
   271     if (script->isForEval())
   272         masm.storePtr(ImmGCPtr(script), frame.addressOfEvalScript());
   274     // Handle scope chain pre-initialization (in case GC gets run
   275     // during stack check).  For global and eval scripts, the scope
   276     // chain is in R1.  For function scripts, the scope chain is in
   277     // the callee, nullptr is stored for now so that GC doesn't choke
   278     // on a bogus ScopeChain value in the frame.
   279     if (function())
   280         masm.storePtr(ImmPtr(nullptr), frame.addressOfScopeChain());
   281     else
   282         masm.storePtr(R1.scratchReg(), frame.addressOfScopeChain());
   284     // Functions with a large number of locals require two stack checks.
   285     // The VMCall for a fallible stack check can only occur after the
   286     // scope chain has been initialized, as that is required for proper
   287     // exception handling if the VMCall returns false.  The scope chain
   288     // initialization can only happen after the UndefinedValues for the
   289     // local slots have been pushed.
   290     // However by that time, the stack might have grown too much.
   291     // In these cases, we emit an extra, early, infallible check
   292     // before pushing the locals.  The early check sets a flag on the
   293     // frame if the stack check fails (but otherwise doesn't throw an
   294     // exception).  If the flag is set, then the jitcode skips past
   295     // the pushing of the locals, and directly to scope chain initialization
   296     // followed by the actual stack check, which will throw the correct
   297     // exception.
   298     Label earlyStackCheckFailed;
   299     if (needsEarlyStackCheck()) {
   300         if (!emitStackCheck(/* earlyCheck = */ true))
   301             return false;
   302         masm.branchTest32(Assembler::NonZero,
   303                           frame.addressOfFlags(),
   304                           Imm32(BaselineFrame::OVER_RECURSED),
   305                           &earlyStackCheckFailed);
   306     }
   308     // Initialize locals to |undefined|. Use R0 to minimize code size.
   309     // If the number of locals to push is < LOOP_UNROLL_FACTOR, then the
   310     // initialization pushes are emitted directly and inline.  Otherwise,
   311     // they're emitted in a partially unrolled loop.
   312     if (frame.nlocals() > 0) {
   313         size_t LOOP_UNROLL_FACTOR = 4;
   314         size_t toPushExtra = frame.nlocals() % LOOP_UNROLL_FACTOR;
   316         masm.moveValue(UndefinedValue(), R0);
   318         // Handle any extra pushes left over by the optional unrolled loop below.
   319         for (size_t i = 0; i < toPushExtra; i++)
   320             masm.pushValue(R0);
   322         // Partially unrolled loop of pushes.
   323         if (frame.nlocals() >= LOOP_UNROLL_FACTOR) {
   324             size_t toPush = frame.nlocals() - toPushExtra;
   325             JS_ASSERT(toPush % LOOP_UNROLL_FACTOR == 0);
   326             JS_ASSERT(toPush >= LOOP_UNROLL_FACTOR);
   327             masm.move32(Imm32(toPush), R1.scratchReg());
   328             // Emit unrolled loop with 4 pushes per iteration.
   329             Label pushLoop;
   330             masm.bind(&pushLoop);
   331             for (size_t i = 0; i < LOOP_UNROLL_FACTOR; i++)
   332                 masm.pushValue(R0);
   333             masm.branchSub32(Assembler::NonZero,
   334                              Imm32(LOOP_UNROLL_FACTOR), R1.scratchReg(), &pushLoop);
   335         }
   336     }
   338     if (needsEarlyStackCheck())
   339         masm.bind(&earlyStackCheckFailed);
   341 #ifdef JS_TRACE_LOGGING
   342     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
   343     Register loggerReg = RegisterSet::Volatile().takeGeneral();
   344     masm.Push(loggerReg);
   345     masm.movePtr(ImmPtr(logger), loggerReg);
   346     masm.tracelogStart(loggerReg, TraceLogCreateTextId(logger, script.get()));
   347     masm.tracelogStart(loggerReg, TraceLogger::Baseline);
   348     masm.Pop(loggerReg);
   349 #endif
   351     // Record the offset of the prologue, because Ion can bailout before
   352     // the scope chain is initialized.
   353     prologueOffset_ = masm.currentOffset();
   355     // Initialize the scope chain before any operation that may
   356     // call into the VM and trigger a GC.
   357     if (!initScopeChain())
   358         return false;
   360     if (!emitStackCheck())
   361         return false;
   363     if (!emitDebugPrologue())
   364         return false;
   366     if (!emitUseCountIncrement())
   367         return false;
   369     if (!emitArgumentTypeChecks())
   370         return false;
   372     if (!emitSPSPush())
   373         return false;
   375     return true;
   376 }
   378 bool
   379 BaselineCompiler::emitEpilogue()
   380 {
   381     // Record the offset of the epilogue, so we can do early return from
   382     // Debugger handlers during on-stack recompile.
   383     epilogueOffset_ = masm.currentOffset();
   385     masm.bind(&return_);
   387 #ifdef JS_TRACE_LOGGING
   388     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
   389     Register loggerReg = RegisterSet::Volatile().takeGeneral();
   390     masm.Push(loggerReg);
   391     masm.movePtr(ImmPtr(logger), loggerReg);
   392     masm.tracelogStop(loggerReg, TraceLogger::Baseline);
   393     // Stop the script. Using a stop without checking the textId, since we
   394     // we didn't save the textId for the script.
   395     masm.tracelogStop(loggerReg);
   396     masm.Pop(loggerReg);
   397 #endif
   399     // Pop SPS frame if necessary
   400     emitSPSPop();
   402     masm.mov(BaselineFrameReg, BaselineStackReg);
   403     masm.pop(BaselineFrameReg);
   405     masm.ret();
   406     return true;
   407 }
   409 #ifdef JSGC_GENERATIONAL
   410 // On input:
   411 //  R2.scratchReg() contains object being written to.
   412 //  Otherwise, baseline stack will be synced, so all other registers are usable as scratch.
   413 // This calls:
   414 //    void PostWriteBarrier(JSRuntime *rt, JSObject *obj);
   415 bool
   416 BaselineCompiler::emitOutOfLinePostBarrierSlot()
   417 {
   418     masm.bind(&postBarrierSlot_);
   420     Register objReg = R2.scratchReg();
   421     GeneralRegisterSet regs(GeneralRegisterSet::All());
   422     regs.take(objReg);
   423     regs.take(BaselineFrameReg);
   424     Register scratch = regs.takeAny();
   425 #if defined(JS_CODEGEN_ARM)
   426     // On ARM, save the link register before calling.  It contains the return
   427     // address.  The |masm.ret()| later will pop this into |pc| to return.
   428     masm.push(lr);
   429 #elif defined(JS_CODEGEN_MIPS)
   430     masm.push(ra);
   431 #endif
   433     masm.setupUnalignedABICall(2, scratch);
   434     masm.movePtr(ImmPtr(cx->runtime()), scratch);
   435     masm.passABIArg(scratch);
   436     masm.passABIArg(objReg);
   437     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, PostWriteBarrier));
   439     masm.ret();
   440     return true;
   441 }
   442 #endif // JSGC_GENERATIONAL
   444 bool
   445 BaselineCompiler::emitIC(ICStub *stub, ICEntry::Kind kind)
   446 {
   447     ICEntry *entry = allocateICEntry(stub, kind);
   448     if (!entry)
   449         return false;
   451     CodeOffsetLabel patchOffset;
   452     EmitCallIC(&patchOffset, masm);
   453     entry->setReturnOffset(masm.currentOffset());
   454     if (!addICLoadLabel(patchOffset))
   455         return false;
   457     return true;
   458 }
   460 typedef bool (*CheckOverRecursedWithExtraFn)(JSContext *, BaselineFrame *, uint32_t, uint32_t);
   461 static const VMFunction CheckOverRecursedWithExtraInfo =
   462     FunctionInfo<CheckOverRecursedWithExtraFn>(CheckOverRecursedWithExtra);
   464 bool
   465 BaselineCompiler::emitStackCheck(bool earlyCheck)
   466 {
   467     Label skipCall;
   468     uintptr_t *limitAddr = &cx->runtime()->mainThread.jitStackLimit;
   469     uint32_t slotsSize = script->nslots() * sizeof(Value);
   470     uint32_t tolerance = earlyCheck ? slotsSize : 0;
   472     masm.movePtr(BaselineStackReg, R1.scratchReg());
   474     // If this is the early stack check, locals haven't been pushed yet.  Adjust the
   475     // stack pointer to account for the locals that would be pushed before performing
   476     // the guard around the vmcall to the stack check.
   477     if (earlyCheck)
   478         masm.subPtr(Imm32(tolerance), R1.scratchReg());
   480     // If this is the late stack check for a frame which contains an early stack check,
   481     // then the early stack check might have failed and skipped past the pushing of locals
   482     // on the stack.
   483     //
   484     // If this is a possibility, then the OVER_RECURSED flag should be checked, and the
   485     // VMCall to CheckOverRecursed done unconditionally if it's set.
   486     Label forceCall;
   487     if (!earlyCheck && needsEarlyStackCheck()) {
   488         masm.branchTest32(Assembler::NonZero,
   489                           frame.addressOfFlags(),
   490                           Imm32(BaselineFrame::OVER_RECURSED),
   491                           &forceCall);
   492     }
   494     masm.branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(limitAddr), R1.scratchReg(),
   495                    &skipCall);
   497     if (!earlyCheck && needsEarlyStackCheck())
   498         masm.bind(&forceCall);
   500     prepareVMCall();
   501     pushArg(Imm32(earlyCheck));
   502     pushArg(Imm32(tolerance));
   503     masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
   504     pushArg(R1.scratchReg());
   506     CallVMPhase phase = POST_INITIALIZE;
   507     if (earlyCheck)
   508         phase = PRE_INITIALIZE;
   509     else if (needsEarlyStackCheck())
   510         phase = CHECK_OVER_RECURSED;
   512     if (!callVM(CheckOverRecursedWithExtraInfo, phase))
   513         return false;
   515     masm.bind(&skipCall);
   516     return true;
   517 }
   519 typedef bool (*DebugPrologueFn)(JSContext *, BaselineFrame *, jsbytecode *, bool *);
   520 static const VMFunction DebugPrologueInfo = FunctionInfo<DebugPrologueFn>(jit::DebugPrologue);
   522 bool
   523 BaselineCompiler::emitDebugPrologue()
   524 {
   525     if (debugMode_) {
   526         // Load pointer to BaselineFrame in R0.
   527         masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
   529         prepareVMCall();
   530         pushArg(ImmPtr(pc));
   531         pushArg(R0.scratchReg());
   532         if (!callVM(DebugPrologueInfo))
   533             return false;
   535         // Fix up the fake ICEntry appended by callVM for on-stack recompilation.
   536         icEntries_.back().setForDebugPrologue();
   538         // If the stub returns |true|, we have to return the value stored in the
   539         // frame's return value slot.
   540         Label done;
   541         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &done);
   542         {
   543             masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
   544             masm.jump(&return_);
   545         }
   546         masm.bind(&done);
   547     }
   549     postDebugPrologueOffset_ = masm.currentOffset();
   551     return true;
   552 }
   554 typedef bool (*StrictEvalPrologueFn)(JSContext *, BaselineFrame *);
   555 static const VMFunction StrictEvalPrologueInfo =
   556     FunctionInfo<StrictEvalPrologueFn>(jit::StrictEvalPrologue);
   558 typedef bool (*HeavyweightFunPrologueFn)(JSContext *, BaselineFrame *);
   559 static const VMFunction HeavyweightFunPrologueInfo =
   560     FunctionInfo<HeavyweightFunPrologueFn>(jit::HeavyweightFunPrologue);
   562 bool
   563 BaselineCompiler::initScopeChain()
   564 {
   565     CallVMPhase phase = POST_INITIALIZE;
   566     if (needsEarlyStackCheck())
   567         phase = CHECK_OVER_RECURSED;
   569     RootedFunction fun(cx, function());
   570     if (fun) {
   571         // Use callee->environment as scope chain. Note that we do
   572         // this also for heavy-weight functions, so that the scope
   573         // chain slot is properly initialized if the call triggers GC.
   574         Register callee = R0.scratchReg();
   575         Register scope = R1.scratchReg();
   576         masm.loadPtr(frame.addressOfCallee(), callee);
   577         masm.loadPtr(Address(callee, JSFunction::offsetOfEnvironment()), scope);
   578         masm.storePtr(scope, frame.addressOfScopeChain());
   580         if (fun->isHeavyweight()) {
   581             // Call into the VM to create a new call object.
   582             prepareVMCall();
   584             masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
   585             pushArg(R0.scratchReg());
   587             if (!callVM(HeavyweightFunPrologueInfo, phase))
   588                 return false;
   589         }
   590     } else {
   591         // ScopeChain pointer in BaselineFrame has already been initialized
   592         // in prologue.
   594         if (script->isForEval() && script->strict()) {
   595             // Strict eval needs its own call object.
   596             prepareVMCall();
   598             masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
   599             pushArg(R0.scratchReg());
   601             if (!callVM(StrictEvalPrologueInfo, phase))
   602                 return false;
   603         }
   604     }
   606     return true;
   607 }
   609 typedef bool (*InterruptCheckFn)(JSContext *);
   610 static const VMFunction InterruptCheckInfo = FunctionInfo<InterruptCheckFn>(InterruptCheck);
   612 bool
   613 BaselineCompiler::emitInterruptCheck()
   614 {
   615     frame.syncStack(0);
   617     Label done;
   618     void *interrupt = (void *)&cx->runtime()->interrupt;
   619     masm.branch32(Assembler::Equal, AbsoluteAddress(interrupt), Imm32(0), &done);
   621     prepareVMCall();
   622     if (!callVM(InterruptCheckInfo))
   623         return false;
   625     masm.bind(&done);
   626     return true;
   627 }
   629 bool
   630 BaselineCompiler::emitUseCountIncrement(bool allowOsr)
   631 {
   632     // Emit no use count increments or bailouts if Ion is not
   633     // enabled, or if the script will never be Ion-compileable
   635     if (!ionCompileable_ && !ionOSRCompileable_)
   636         return true;
   638     Register scriptReg = R2.scratchReg();
   639     Register countReg = R0.scratchReg();
   640     Address useCountAddr(scriptReg, JSScript::offsetOfUseCount());
   642     masm.movePtr(ImmGCPtr(script), scriptReg);
   643     masm.load32(useCountAddr, countReg);
   644     masm.add32(Imm32(1), countReg);
   645     masm.store32(countReg, useCountAddr);
   647     // If this is a loop inside a catch or finally block, increment the use
   648     // count but don't attempt OSR (Ion only compiles the try block).
   649     if (analysis_.info(pc).loopEntryInCatchOrFinally) {
   650         JS_ASSERT(JSOp(*pc) == JSOP_LOOPENTRY);
   651         return true;
   652     }
   654     // OSR not possible at this loop entry.
   655     if (!allowOsr) {
   656         JS_ASSERT(JSOp(*pc) == JSOP_LOOPENTRY);
   657         return true;
   658     }
   660     Label skipCall;
   662     const OptimizationInfo *info = js_IonOptimizations.get(js_IonOptimizations.firstLevel());
   663     uint32_t minUses = info->usesBeforeCompile(script, pc);
   664     masm.branch32(Assembler::LessThan, countReg, Imm32(minUses), &skipCall);
   666     masm.branchPtr(Assembler::Equal,
   667                    Address(scriptReg, JSScript::offsetOfIonScript()),
   668                    ImmPtr(ION_COMPILING_SCRIPT), &skipCall);
   670     // Call IC.
   671     ICUseCount_Fallback::Compiler stubCompiler(cx);
   672     if (!emitNonOpIC(stubCompiler.getStub(&stubSpace_)))
   673         return false;
   675     masm.bind(&skipCall);
   677     return true;
   678 }
   680 bool
   681 BaselineCompiler::emitArgumentTypeChecks()
   682 {
   683     if (!function())
   684         return true;
   686     frame.pushThis();
   687     frame.popRegsAndSync(1);
   689     ICTypeMonitor_Fallback::Compiler compiler(cx, (uint32_t) 0);
   690     if (!emitNonOpIC(compiler.getStub(&stubSpace_)))
   691         return false;
   693     for (size_t i = 0; i < function()->nargs(); i++) {
   694         frame.pushArg(i);
   695         frame.popRegsAndSync(1);
   697         ICTypeMonitor_Fallback::Compiler compiler(cx, i + 1);
   698         if (!emitNonOpIC(compiler.getStub(&stubSpace_)))
   699             return false;
   700     }
   702     return true;
   703 }
   705 bool
   706 BaselineCompiler::emitDebugTrap()
   707 {
   708     JS_ASSERT(debugMode_);
   709     JS_ASSERT(frame.numUnsyncedSlots() == 0);
   711     bool enabled = script->stepModeEnabled() || script->hasBreakpointsAt(pc);
   713     // Emit patchable call to debug trap handler.
   714     JitCode *handler = cx->runtime()->jitRuntime()->debugTrapHandler(cx);
   715     mozilla::DebugOnly<CodeOffsetLabel> offset = masm.toggledCall(handler, enabled);
   717 #ifdef DEBUG
   718     // Patchable call offset has to match the pc mapping offset.
   719     PCMappingEntry &entry = pcMappingEntries_.back();
   720     JS_ASSERT((&offset)->offset() == entry.nativeOffset);
   721 #endif
   723     // Add an IC entry for the return offset -> pc mapping.
   724     ICEntry icEntry(script->pcToOffset(pc), ICEntry::Kind_DebugTrap);
   725     icEntry.setReturnOffset(masm.currentOffset());
   726     if (!icEntries_.append(icEntry))
   727         return false;
   729     return true;
   730 }
   732 bool
   733 BaselineCompiler::emitSPSPush()
   734 {
   735     // Enter the IC, guarded by a toggled jump (initially disabled).
   736     Label noPush;
   737     CodeOffsetLabel toggleOffset = masm.toggledJump(&noPush);
   738     JS_ASSERT(frame.numUnsyncedSlots() == 0);
   739     ICProfiler_Fallback::Compiler compiler(cx);
   740     if (!emitNonOpIC(compiler.getStub(&stubSpace_)))
   741         return false;
   742     masm.bind(&noPush);
   744     // Store the start offset in the appropriate location.
   745     JS_ASSERT(spsPushToggleOffset_.offset() == 0);
   746     spsPushToggleOffset_ = toggleOffset;
   747     return true;
   748 }
   750 void
   751 BaselineCompiler::emitSPSPop()
   752 {
   753     // If profiler entry was pushed on this frame, pop it.
   754     Label noPop;
   755     masm.branchTest32(Assembler::Zero, frame.addressOfFlags(),
   756                       Imm32(BaselineFrame::HAS_PUSHED_SPS_FRAME), &noPop);
   757     masm.spsPopFrameSafe(&cx->runtime()->spsProfiler, R1.scratchReg());
   758     masm.bind(&noPop);
   759 }
   761 MethodStatus
   762 BaselineCompiler::emitBody()
   763 {
   764     JS_ASSERT(pc == script->code());
   766     bool lastOpUnreachable = false;
   767     uint32_t emittedOps = 0;
   768     mozilla::DebugOnly<jsbytecode *> prevpc = pc;
   770     while (true) {
   771         JSOp op = JSOp(*pc);
   772         IonSpew(IonSpew_BaselineOp, "Compiling op @ %d: %s",
   773                 int(script->pcToOffset(pc)), js_CodeName[op]);
   775         BytecodeInfo *info = analysis_.maybeInfo(pc);
   777         // Skip unreachable ops.
   778         if (!info) {
   779             // Test if last instructions and stop emitting in that case.
   780             pc += GetBytecodeLength(pc);
   781             if (pc >= script->codeEnd())
   782                 break;
   784             lastOpUnreachable = true;
   785             prevpc = pc;
   786             continue;
   787         }
   789         // Fully sync the stack if there are incoming jumps.
   790         if (info->jumpTarget) {
   791             frame.syncStack(0);
   792             frame.setStackDepth(info->stackDepth);
   793         }
   795         // Always sync in debug mode.
   796         if (debugMode_)
   797             frame.syncStack(0);
   799         // At the beginning of any op, at most the top 2 stack-values are unsynced.
   800         if (frame.stackDepth() > 2)
   801             frame.syncStack(2);
   803         frame.assertValidState(*info);
   805         masm.bind(labelOf(pc));
   807         // Add a PC -> native mapping entry for the current op. These entries are
   808         // used when we need the native code address for a given pc, for instance
   809         // for bailouts from Ion, the debugger and exception handling. See
   810         // PCMappingIndexEntry for more information.
   811         bool addIndexEntry = (pc == script->code() || lastOpUnreachable || emittedOps > 100);
   812         if (addIndexEntry)
   813             emittedOps = 0;
   814         if (!addPCMappingEntry(addIndexEntry))
   815             return Method_Error;
   817         // Emit traps for breakpoints and step mode.
   818         if (debugMode_ && !emitDebugTrap())
   819             return Method_Error;
   821         switch (op) {
   822           default:
   823             IonSpew(IonSpew_BaselineAbort, "Unhandled op: %s", js_CodeName[op]);
   824             return Method_CantCompile;
   826 #define EMIT_OP(OP)                            \
   827           case OP:                             \
   828             if (!this->emit_##OP())            \
   829                 return Method_Error;           \
   830             break;
   831 OPCODE_LIST(EMIT_OP)
   832 #undef EMIT_OP
   833         }
   835         // Test if last instructions and stop emitting in that case.
   836         pc += GetBytecodeLength(pc);
   837         if (pc >= script->codeEnd())
   838             break;
   840         emittedOps++;
   841         lastOpUnreachable = false;
   842 #ifdef DEBUG
   843         prevpc = pc;
   844 #endif
   845     }
   847     JS_ASSERT(JSOp(*prevpc) == JSOP_RETRVAL);
   848     return Method_Compiled;
   849 }
   851 bool
   852 BaselineCompiler::emit_JSOP_NOP()
   853 {
   854     return true;
   855 }
   857 bool
   858 BaselineCompiler::emit_JSOP_LABEL()
   859 {
   860     return true;
   861 }
   863 bool
   864 BaselineCompiler::emit_JSOP_POP()
   865 {
   866     frame.pop();
   867     return true;
   868 }
   870 bool
   871 BaselineCompiler::emit_JSOP_POPN()
   872 {
   873     frame.popn(GET_UINT16(pc));
   874     return true;
   875 }
   877 bool
   878 BaselineCompiler::emit_JSOP_DUPAT()
   879 {
   880     frame.syncStack(0);
   882     // DUPAT takes a value on the stack and re-pushes it on top.  It's like
   883     // GETLOCAL but it addresses from the top of the stack instead of from the
   884     // stack frame.
   886     int depth = -(GET_UINT24(pc) + 1);
   887     masm.loadValue(frame.addressOfStackValue(frame.peek(depth)), R0);
   888     frame.push(R0);
   889     return true;
   890 }
   892 bool
   893 BaselineCompiler::emit_JSOP_DUP()
   894 {
   895     // Keep top stack value in R0, sync the rest so that we can use R1. We use
   896     // separate registers because every register can be used by at most one
   897     // StackValue.
   898     frame.popRegsAndSync(1);
   899     masm.moveValue(R0, R1);
   901     // inc/dec ops use DUP followed by ONE, ADD. Push R0 last to avoid a move.
   902     frame.push(R1);
   903     frame.push(R0);
   904     return true;
   905 }
   907 bool
   908 BaselineCompiler::emit_JSOP_DUP2()
   909 {
   910     frame.syncStack(0);
   912     masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
   913     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
   915     frame.push(R0);
   916     frame.push(R1);
   917     return true;
   918 }
   920 bool
   921 BaselineCompiler::emit_JSOP_SWAP()
   922 {
   923     // Keep top stack values in R0 and R1.
   924     frame.popRegsAndSync(2);
   926     frame.push(R1);
   927     frame.push(R0);
   928     return true;
   929 }
   931 bool
   932 BaselineCompiler::emit_JSOP_PICK()
   933 {
   934     frame.syncStack(0);
   936     // Pick takes a value on the stack and moves it to the top.
   937     // For instance, pick 2:
   938     //     before: A B C D E
   939     //     after : A B D E C
   941     // First, move value at -(amount + 1) into R0.
   942     int depth = -(GET_INT8(pc) + 1);
   943     masm.loadValue(frame.addressOfStackValue(frame.peek(depth)), R0);
   945     // Move the other values down.
   946     depth++;
   947     for (; depth < 0; depth++) {
   948         Address source = frame.addressOfStackValue(frame.peek(depth));
   949         Address dest = frame.addressOfStackValue(frame.peek(depth - 1));
   950         masm.loadValue(source, R1);
   951         masm.storeValue(R1, dest);
   952     }
   954     // Push R0.
   955     frame.pop();
   956     frame.push(R0);
   957     return true;
   958 }
   960 bool
   961 BaselineCompiler::emit_JSOP_GOTO()
   962 {
   963     frame.syncStack(0);
   965     jsbytecode *target = pc + GET_JUMP_OFFSET(pc);
   966     masm.jump(labelOf(target));
   967     return true;
   968 }
   970 bool
   971 BaselineCompiler::emitToBoolean()
   972 {
   973     Label skipIC;
   974     masm.branchTestBoolean(Assembler::Equal, R0, &skipIC);
   976     // Call IC
   977     ICToBool_Fallback::Compiler stubCompiler(cx);
   978     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
   979         return false;
   981     masm.bind(&skipIC);
   982     return true;
   983 }
   985 bool
   986 BaselineCompiler::emitTest(bool branchIfTrue)
   987 {
   988     bool knownBoolean = frame.peek(-1)->isKnownBoolean();
   990     // Keep top stack value in R0.
   991     frame.popRegsAndSync(1);
   993     if (!knownBoolean && !emitToBoolean())
   994         return false;
   996     // IC will leave a BooleanValue in R0, just need to branch on it.
   997     masm.branchTestBooleanTruthy(branchIfTrue, R0, labelOf(pc + GET_JUMP_OFFSET(pc)));
   998     return true;
   999 }
  1001 bool
  1002 BaselineCompiler::emit_JSOP_IFEQ()
  1004     return emitTest(false);
  1007 bool
  1008 BaselineCompiler::emit_JSOP_IFNE()
  1010     return emitTest(true);
  1013 bool
  1014 BaselineCompiler::emitAndOr(bool branchIfTrue)
  1016     bool knownBoolean = frame.peek(-1)->isKnownBoolean();
  1018     // AND and OR leave the original value on the stack.
  1019     frame.syncStack(0);
  1021     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
  1022     if (!knownBoolean && !emitToBoolean())
  1023         return false;
  1025     masm.branchTestBooleanTruthy(branchIfTrue, R0, labelOf(pc + GET_JUMP_OFFSET(pc)));
  1026     return true;
  1029 bool
  1030 BaselineCompiler::emit_JSOP_AND()
  1032     return emitAndOr(false);
  1035 bool
  1036 BaselineCompiler::emit_JSOP_OR()
  1038     return emitAndOr(true);
  1041 bool
  1042 BaselineCompiler::emit_JSOP_NOT()
  1044     bool knownBoolean = frame.peek(-1)->isKnownBoolean();
  1046     // Keep top stack value in R0.
  1047     frame.popRegsAndSync(1);
  1049     if (!knownBoolean && !emitToBoolean())
  1050         return false;
  1052     masm.notBoolean(R0);
  1054     frame.push(R0, JSVAL_TYPE_BOOLEAN);
  1055     return true;
  1058 bool
  1059 BaselineCompiler::emit_JSOP_POS()
  1061     // Keep top stack value in R0.
  1062     frame.popRegsAndSync(1);
  1064     // Inline path for int32 and double.
  1065     Label done;
  1066     masm.branchTestNumber(Assembler::Equal, R0, &done);
  1068     // Call IC.
  1069     ICToNumber_Fallback::Compiler stubCompiler(cx);
  1070     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1071         return false;
  1073     masm.bind(&done);
  1074     frame.push(R0);
  1075     return true;
  1078 bool
  1079 BaselineCompiler::emit_JSOP_LOOPHEAD()
  1081     return emitInterruptCheck();
  1084 bool
  1085 BaselineCompiler::emit_JSOP_LOOPENTRY()
  1087     frame.syncStack(0);
  1088     return emitUseCountIncrement(LoopEntryCanIonOsr(pc));
  1091 bool
  1092 BaselineCompiler::emit_JSOP_VOID()
  1094     frame.pop();
  1095     frame.push(UndefinedValue());
  1096     return true;
  1099 bool
  1100 BaselineCompiler::emit_JSOP_UNDEFINED()
  1102     frame.push(UndefinedValue());
  1103     return true;
  1106 bool
  1107 BaselineCompiler::emit_JSOP_HOLE()
  1109     frame.push(MagicValue(JS_ELEMENTS_HOLE));
  1110     return true;
  1113 bool
  1114 BaselineCompiler::emit_JSOP_NULL()
  1116     frame.push(NullValue());
  1117     return true;
  1120 bool
  1121 BaselineCompiler::emit_JSOP_THIS()
  1123     if (function() && function()->isArrow()) {
  1124         // Arrow functions store their (lexical) |this| value in an
  1125         // extended slot.
  1126         frame.syncStack(0);
  1127         Register scratch = R0.scratchReg();
  1128         masm.loadPtr(frame.addressOfCallee(), scratch);
  1129         masm.loadValue(Address(scratch, FunctionExtended::offsetOfArrowThisSlot()), R0);
  1130         frame.push(R0);
  1131         return true;
  1134     // Keep this value in R0
  1135     frame.pushThis();
  1137     // In strict mode code or self-hosted functions, |this| is left alone.
  1138     if (script->strict() || (function() && function()->isSelfHostedBuiltin()))
  1139         return true;
  1141     Label skipIC;
  1142     // Keep |thisv| in R0
  1143     frame.popRegsAndSync(1);
  1144     // If |this| is already an object, skip the IC.
  1145     masm.branchTestObject(Assembler::Equal, R0, &skipIC);
  1147     // Call IC
  1148     ICThis_Fallback::Compiler stubCompiler(cx);
  1149     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1150         return false;
  1152     masm.storeValue(R0, frame.addressOfThis());
  1154     // R0 is new pushed |this| value.
  1155     masm.bind(&skipIC);
  1156     frame.push(R0);
  1158     return true;
  1161 bool
  1162 BaselineCompiler::emit_JSOP_TRUE()
  1164     frame.push(BooleanValue(true));
  1165     return true;
  1168 bool
  1169 BaselineCompiler::emit_JSOP_FALSE()
  1171     frame.push(BooleanValue(false));
  1172     return true;
  1175 bool
  1176 BaselineCompiler::emit_JSOP_ZERO()
  1178     frame.push(Int32Value(0));
  1179     return true;
  1182 bool
  1183 BaselineCompiler::emit_JSOP_ONE()
  1185     frame.push(Int32Value(1));
  1186     return true;
  1189 bool
  1190 BaselineCompiler::emit_JSOP_INT8()
  1192     frame.push(Int32Value(GET_INT8(pc)));
  1193     return true;
  1196 bool
  1197 BaselineCompiler::emit_JSOP_INT32()
  1199     frame.push(Int32Value(GET_INT32(pc)));
  1200     return true;
  1203 bool
  1204 BaselineCompiler::emit_JSOP_UINT16()
  1206     frame.push(Int32Value(GET_UINT16(pc)));
  1207     return true;
  1210 bool
  1211 BaselineCompiler::emit_JSOP_UINT24()
  1213     frame.push(Int32Value(GET_UINT24(pc)));
  1214     return true;
  1217 bool
  1218 BaselineCompiler::emit_JSOP_DOUBLE()
  1220     frame.push(script->getConst(GET_UINT32_INDEX(pc)));
  1221     return true;
  1224 bool
  1225 BaselineCompiler::emit_JSOP_STRING()
  1227     frame.push(StringValue(script->getAtom(pc)));
  1228     return true;
  1231 typedef JSObject *(*DeepCloneObjectLiteralFn)(JSContext *, HandleObject, NewObjectKind);
  1232 static const VMFunction DeepCloneObjectLiteralInfo =
  1233     FunctionInfo<DeepCloneObjectLiteralFn>(DeepCloneObjectLiteral);
  1235 bool
  1236 BaselineCompiler::emit_JSOP_OBJECT()
  1238     if (JS::CompartmentOptionsRef(cx).cloneSingletons(cx)) {
  1239         RootedObject obj(cx, script->getObject(GET_UINT32_INDEX(pc)));
  1240         if (!obj)
  1241             return false;
  1243         prepareVMCall();
  1245         pushArg(ImmWord(js::MaybeSingletonObject));
  1246         pushArg(ImmGCPtr(obj));
  1248         if (!callVM(DeepCloneObjectLiteralInfo))
  1249             return false;
  1251         // Box and push return value.
  1252         masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
  1253         frame.push(R0);
  1254         return true;
  1257     JS::CompartmentOptionsRef(cx).setSingletonsAsValues();
  1258     frame.push(ObjectValue(*script->getObject(pc)));
  1259     return true;
  1262 typedef JSObject *(*CloneRegExpObjectFn)(JSContext *, JSObject *);
  1263 static const VMFunction CloneRegExpObjectInfo =
  1264     FunctionInfo<CloneRegExpObjectFn>(CloneRegExpObject);
  1266 bool
  1267 BaselineCompiler::emit_JSOP_REGEXP()
  1269     RootedObject reObj(cx, script->getRegExp(pc));
  1271     prepareVMCall();
  1272     pushArg(ImmGCPtr(reObj));
  1273     if (!callVM(CloneRegExpObjectInfo))
  1274         return false;
  1276     // Box and push return value.
  1277     masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
  1278     frame.push(R0);
  1279     return true;
  1282 typedef JSObject *(*LambdaFn)(JSContext *, HandleFunction, HandleObject);
  1283 static const VMFunction LambdaInfo = FunctionInfo<LambdaFn>(js::Lambda);
  1285 bool
  1286 BaselineCompiler::emit_JSOP_LAMBDA()
  1288     RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc)));
  1290     prepareVMCall();
  1291     masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  1293     pushArg(R0.scratchReg());
  1294     pushArg(ImmGCPtr(fun));
  1296     if (!callVM(LambdaInfo))
  1297         return false;
  1299     // Box and push return value.
  1300     masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
  1301     frame.push(R0);
  1302     return true;
  1305 typedef JSObject *(*LambdaArrowFn)(JSContext *, HandleFunction, HandleObject, HandleValue);
  1306 static const VMFunction LambdaArrowInfo = FunctionInfo<LambdaArrowFn>(js::LambdaArrow);
  1308 bool
  1309 BaselineCompiler::emit_JSOP_LAMBDA_ARROW()
  1311     // Keep pushed |this| in R0.
  1312     frame.popRegsAndSync(1);
  1314     RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc)));
  1316     prepareVMCall();
  1317     masm.loadPtr(frame.addressOfScopeChain(), R1.scratchReg());
  1319     pushArg(R0);
  1320     pushArg(R1.scratchReg());
  1321     pushArg(ImmGCPtr(fun));
  1323     if (!callVM(LambdaArrowInfo))
  1324         return false;
  1326     // Box and push return value.
  1327     masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
  1328     frame.push(R0);
  1329     return true;
  1332 void
  1333 BaselineCompiler::storeValue(const StackValue *source, const Address &dest,
  1334                              const ValueOperand &scratch)
  1336     switch (source->kind()) {
  1337       case StackValue::Constant:
  1338         masm.storeValue(source->constant(), dest);
  1339         break;
  1340       case StackValue::Register:
  1341         masm.storeValue(source->reg(), dest);
  1342         break;
  1343       case StackValue::LocalSlot:
  1344         masm.loadValue(frame.addressOfLocal(source->localSlot()), scratch);
  1345         masm.storeValue(scratch, dest);
  1346         break;
  1347       case StackValue::ArgSlot:
  1348         masm.loadValue(frame.addressOfArg(source->argSlot()), scratch);
  1349         masm.storeValue(scratch, dest);
  1350         break;
  1351       case StackValue::ThisSlot:
  1352         masm.loadValue(frame.addressOfThis(), scratch);
  1353         masm.storeValue(scratch, dest);
  1354         break;
  1355       case StackValue::Stack:
  1356         masm.loadValue(frame.addressOfStackValue(source), scratch);
  1357         masm.storeValue(scratch, dest);
  1358         break;
  1359       default:
  1360         MOZ_ASSUME_UNREACHABLE("Invalid kind");
  1364 bool
  1365 BaselineCompiler::emit_JSOP_BITOR()
  1367     return emitBinaryArith();
  1370 bool
  1371 BaselineCompiler::emit_JSOP_BITXOR()
  1373     return emitBinaryArith();
  1376 bool
  1377 BaselineCompiler::emit_JSOP_BITAND()
  1379     return emitBinaryArith();
  1382 bool
  1383 BaselineCompiler::emit_JSOP_LSH()
  1385     return emitBinaryArith();
  1388 bool
  1389 BaselineCompiler::emit_JSOP_RSH()
  1391     return emitBinaryArith();
  1394 bool
  1395 BaselineCompiler::emit_JSOP_URSH()
  1397     return emitBinaryArith();
  1400 bool
  1401 BaselineCompiler::emit_JSOP_ADD()
  1403     return emitBinaryArith();
  1406 bool
  1407 BaselineCompiler::emit_JSOP_SUB()
  1409     return emitBinaryArith();
  1412 bool
  1413 BaselineCompiler::emit_JSOP_MUL()
  1415     return emitBinaryArith();
  1418 bool
  1419 BaselineCompiler::emit_JSOP_DIV()
  1421     return emitBinaryArith();
  1424 bool
  1425 BaselineCompiler::emit_JSOP_MOD()
  1427     return emitBinaryArith();
  1430 bool
  1431 BaselineCompiler::emitBinaryArith()
  1433     // Keep top JSStack value in R0 and R2
  1434     frame.popRegsAndSync(2);
  1436     // Call IC
  1437     ICBinaryArith_Fallback::Compiler stubCompiler(cx);
  1438     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1439         return false;
  1441     // Mark R0 as pushed stack value.
  1442     frame.push(R0);
  1443     return true;
  1446 bool
  1447 BaselineCompiler::emitUnaryArith()
  1449     // Keep top stack value in R0.
  1450     frame.popRegsAndSync(1);
  1452     // Call IC
  1453     ICUnaryArith_Fallback::Compiler stubCompiler(cx);
  1454     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1455         return false;
  1457     // Mark R0 as pushed stack value.
  1458     frame.push(R0);
  1459     return true;
  1462 bool
  1463 BaselineCompiler::emit_JSOP_BITNOT()
  1465     return emitUnaryArith();
  1468 bool
  1469 BaselineCompiler::emit_JSOP_NEG()
  1471     return emitUnaryArith();
  1474 bool
  1475 BaselineCompiler::emit_JSOP_LT()
  1477     return emitCompare();
  1480 bool
  1481 BaselineCompiler::emit_JSOP_LE()
  1483     return emitCompare();
  1486 bool
  1487 BaselineCompiler::emit_JSOP_GT()
  1489     return emitCompare();
  1492 bool
  1493 BaselineCompiler::emit_JSOP_GE()
  1495     return emitCompare();
  1498 bool
  1499 BaselineCompiler::emit_JSOP_EQ()
  1501     return emitCompare();
  1504 bool
  1505 BaselineCompiler::emit_JSOP_NE()
  1507     return emitCompare();
  1510 bool
  1511 BaselineCompiler::emitCompare()
  1513     // CODEGEN
  1515     // Keep top JSStack value in R0 and R1.
  1516     frame.popRegsAndSync(2);
  1518     // Call IC.
  1519     ICCompare_Fallback::Compiler stubCompiler(cx);
  1520     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1521         return false;
  1523     // Mark R0 as pushed stack value.
  1524     frame.push(R0, JSVAL_TYPE_BOOLEAN);
  1525     return true;
  1528 bool
  1529 BaselineCompiler::emit_JSOP_STRICTEQ()
  1531     return emitCompare();
  1534 bool
  1535 BaselineCompiler::emit_JSOP_STRICTNE()
  1537     return emitCompare();
  1540 bool
  1541 BaselineCompiler::emit_JSOP_CONDSWITCH()
  1543     return true;
  1546 bool
  1547 BaselineCompiler::emit_JSOP_CASE()
  1549     frame.popRegsAndSync(2);
  1550     frame.push(R0);
  1551     frame.syncStack(0);
  1553     // Call IC.
  1554     ICCompare_Fallback::Compiler stubCompiler(cx);
  1555     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1556         return false;
  1558     Register payload = masm.extractInt32(R0, R0.scratchReg());
  1559     jsbytecode *target = pc + GET_JUMP_OFFSET(pc);
  1561     Label done;
  1562     masm.branch32(Assembler::Equal, payload, Imm32(0), &done);
  1564         // Pop the switch value if the case matches.
  1565         masm.addPtr(Imm32(sizeof(Value)), StackPointer);
  1566         masm.jump(labelOf(target));
  1568     masm.bind(&done);
  1569     return true;
  1572 bool
  1573 BaselineCompiler::emit_JSOP_DEFAULT()
  1575     frame.pop();
  1576     return emit_JSOP_GOTO();
  1579 bool
  1580 BaselineCompiler::emit_JSOP_LINENO()
  1582     return true;
  1585 bool
  1586 BaselineCompiler::emit_JSOP_NEWARRAY()
  1588     frame.syncStack(0);
  1590     uint32_t length = GET_UINT24(pc);
  1591     RootedTypeObject type(cx);
  1592     if (!types::UseNewTypeForInitializer(script, pc, JSProto_Array)) {
  1593         type = types::TypeScript::InitObject(cx, script, pc, JSProto_Array);
  1594         if (!type)
  1595             return false;
  1598     // Pass length in R0, type in R1.
  1599     masm.move32(Imm32(length), R0.scratchReg());
  1600     masm.movePtr(ImmGCPtr(type), R1.scratchReg());
  1602     JSObject *templateObject = NewDenseUnallocatedArray(cx, length, nullptr, TenuredObject);
  1603     if (!templateObject)
  1604         return false;
  1605     templateObject->setType(type);
  1607     ICNewArray_Fallback::Compiler stubCompiler(cx, templateObject);
  1608     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1609         return false;
  1611     frame.push(R0);
  1612     return true;
  1615 bool
  1616 BaselineCompiler::emit_JSOP_INITELEM_ARRAY()
  1618     // Keep the object and rhs on the stack.
  1619     frame.syncStack(0);
  1621     // Load object in R0, index in R1.
  1622     masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
  1623     masm.moveValue(Int32Value(GET_UINT24(pc)), R1);
  1625     // Call IC.
  1626     ICSetElem_Fallback::Compiler stubCompiler(cx);
  1627     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1628         return false;
  1630     // Pop the rhs, so that the object is on the top of the stack.
  1631     frame.pop();
  1632     return true;
  1635 bool
  1636 BaselineCompiler::emit_JSOP_NEWOBJECT()
  1638     frame.syncStack(0);
  1640     RootedTypeObject type(cx);
  1641     if (!types::UseNewTypeForInitializer(script, pc, JSProto_Object)) {
  1642         type = types::TypeScript::InitObject(cx, script, pc, JSProto_Object);
  1643         if (!type)
  1644             return false;
  1647     RootedObject baseObject(cx, script->getObject(pc));
  1648     RootedObject templateObject(cx, CopyInitializerObject(cx, baseObject, TenuredObject));
  1649     if (!templateObject)
  1650         return false;
  1652     if (type) {
  1653         templateObject->setType(type);
  1654     } else {
  1655         if (!JSObject::setSingletonType(cx, templateObject))
  1656             return false;
  1659     ICNewObject_Fallback::Compiler stubCompiler(cx, templateObject);
  1660     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1661         return false;
  1663     frame.push(R0);
  1664     return true;
  1667 bool
  1668 BaselineCompiler::emit_JSOP_NEWINIT()
  1670     frame.syncStack(0);
  1671     JSProtoKey key = JSProtoKey(GET_UINT8(pc));
  1673     RootedTypeObject type(cx);
  1674     if (!types::UseNewTypeForInitializer(script, pc, key)) {
  1675         type = types::TypeScript::InitObject(cx, script, pc, key);
  1676         if (!type)
  1677             return false;
  1680     if (key == JSProto_Array) {
  1681         // Pass length in R0, type in R1.
  1682         masm.move32(Imm32(0), R0.scratchReg());
  1683         masm.movePtr(ImmGCPtr(type), R1.scratchReg());
  1685         JSObject *templateObject = NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject);
  1686         if (!templateObject)
  1687             return false;
  1688         templateObject->setType(type);
  1690         ICNewArray_Fallback::Compiler stubCompiler(cx, templateObject);
  1691         if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1692             return false;
  1693     } else {
  1694         JS_ASSERT(key == JSProto_Object);
  1696         RootedObject templateObject(cx);
  1697         templateObject = NewBuiltinClassInstance(cx, &JSObject::class_, TenuredObject);
  1698         if (!templateObject)
  1699             return false;
  1701         if (type) {
  1702             templateObject->setType(type);
  1703         } else {
  1704             if (!JSObject::setSingletonType(cx, templateObject))
  1705                 return false;
  1708         ICNewObject_Fallback::Compiler stubCompiler(cx, templateObject);
  1709         if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1710             return false;
  1713     frame.push(R0);
  1714     return true;
  1717 bool
  1718 BaselineCompiler::emit_JSOP_INITELEM()
  1720     // Store RHS in the scratch slot.
  1721     storeValue(frame.peek(-1), frame.addressOfScratchValue(), R2);
  1722     frame.pop();
  1724     // Keep object and index in R0 and R1.
  1725     frame.popRegsAndSync(2);
  1727     // Push the object to store the result of the IC.
  1728     frame.push(R0);
  1729     frame.syncStack(0);
  1731     // Keep RHS on the stack.
  1732     frame.pushScratchValue();
  1734     // Call IC.
  1735     ICSetElem_Fallback::Compiler stubCompiler(cx);
  1736     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1737         return false;
  1739     // Pop the rhs, so that the object is on the top of the stack.
  1740     frame.pop();
  1741     return true;
  1744 typedef bool (*MutateProtoFn)(JSContext *cx, HandleObject obj, HandleValue newProto);
  1745 static const VMFunction MutateProtoInfo = FunctionInfo<MutateProtoFn>(MutatePrototype);
  1747 bool
  1748 BaselineCompiler::emit_JSOP_MUTATEPROTO()
  1750     // Keep values on the stack for the decompiler.
  1751     frame.syncStack(0);
  1753     masm.extractObject(frame.addressOfStackValue(frame.peek(-2)), R0.scratchReg());
  1754     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
  1756     prepareVMCall();
  1758     pushArg(R1);
  1759     pushArg(R0.scratchReg());
  1761     if (!callVM(MutateProtoInfo))
  1762         return false;
  1764     frame.pop();
  1765     return true;
  1768 bool
  1769 BaselineCompiler::emit_JSOP_INITPROP()
  1771     // Keep lhs in R0, rhs in R1.
  1772     frame.popRegsAndSync(2);
  1774     // Push the object to store the result of the IC.
  1775     frame.push(R0);
  1776     frame.syncStack(0);
  1778     // Call IC.
  1779     ICSetProp_Fallback::Compiler compiler(cx);
  1780     return emitOpIC(compiler.getStub(&stubSpace_));
  1783 bool
  1784 BaselineCompiler::emit_JSOP_ENDINIT()
  1786     return true;
  1789 typedef bool (*NewbornArrayPushFn)(JSContext *, HandleObject, const Value &);
  1790 static const VMFunction NewbornArrayPushInfo = FunctionInfo<NewbornArrayPushFn>(NewbornArrayPush);
  1792 bool
  1793 BaselineCompiler::emit_JSOP_ARRAYPUSH()
  1795     // Keep value in R0, object in R1.
  1796     frame.popRegsAndSync(2);
  1797     masm.unboxObject(R1, R1.scratchReg());
  1799     prepareVMCall();
  1801     pushArg(R0);
  1802     pushArg(R1.scratchReg());
  1804     return callVM(NewbornArrayPushInfo);
  1807 bool
  1808 BaselineCompiler::emit_JSOP_GETELEM()
  1810     // Keep top two stack values in R0 and R1.
  1811     frame.popRegsAndSync(2);
  1813     // Call IC.
  1814     ICGetElem_Fallback::Compiler stubCompiler(cx);
  1815     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1816         return false;
  1818     // Mark R0 as pushed stack value.
  1819     frame.push(R0);
  1820     return true;
  1823 bool
  1824 BaselineCompiler::emit_JSOP_CALLELEM()
  1826     return emit_JSOP_GETELEM();
  1829 bool
  1830 BaselineCompiler::emit_JSOP_SETELEM()
  1832     // Store RHS in the scratch slot.
  1833     storeValue(frame.peek(-1), frame.addressOfScratchValue(), R2);
  1834     frame.pop();
  1836     // Keep object and index in R0 and R1.
  1837     frame.popRegsAndSync(2);
  1839     // Keep RHS on the stack.
  1840     frame.pushScratchValue();
  1842     // Call IC.
  1843     ICSetElem_Fallback::Compiler stubCompiler(cx);
  1844     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1845         return false;
  1847     return true;
  1850 typedef bool (*DeleteElementFn)(JSContext *, HandleValue, HandleValue, bool *);
  1851 static const VMFunction DeleteElementStrictInfo = FunctionInfo<DeleteElementFn>(DeleteElement<true>);
  1852 static const VMFunction DeleteElementNonStrictInfo = FunctionInfo<DeleteElementFn>(DeleteElement<false>);
  1854 bool
  1855 BaselineCompiler::emit_JSOP_DELELEM()
  1857     // Keep values on the stack for the decompiler.
  1858     frame.syncStack(0);
  1859     masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
  1860     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
  1862     prepareVMCall();
  1864     pushArg(R1);
  1865     pushArg(R0);
  1867     if (!callVM(script->strict() ? DeleteElementStrictInfo : DeleteElementNonStrictInfo))
  1868         return false;
  1870     masm.boxNonDouble(JSVAL_TYPE_BOOLEAN, ReturnReg, R1);
  1871     frame.popn(2);
  1872     frame.push(R1);
  1873     return true;
  1876 bool
  1877 BaselineCompiler::emit_JSOP_IN()
  1879     frame.popRegsAndSync(2);
  1881     ICIn_Fallback::Compiler stubCompiler(cx);
  1882     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1883         return false;
  1885     frame.push(R0);
  1886     return true;
  1889 bool
  1890 BaselineCompiler::emit_JSOP_GETGNAME()
  1892     RootedPropertyName name(cx, script->getName(pc));
  1894     if (name == cx->names().undefined) {
  1895         frame.push(UndefinedValue());
  1896         return true;
  1898     if (name == cx->names().NaN) {
  1899         frame.push(cx->runtime()->NaNValue);
  1900         return true;
  1902     if (name == cx->names().Infinity) {
  1903         frame.push(cx->runtime()->positiveInfinityValue);
  1904         return true;
  1907     frame.syncStack(0);
  1909     masm.movePtr(ImmGCPtr(&script->global()), R0.scratchReg());
  1911     // Call IC.
  1912     ICGetName_Fallback::Compiler stubCompiler(cx);
  1913     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1914         return false;
  1916     // Mark R0 as pushed stack value.
  1917     frame.push(R0);
  1918     return true;
  1921 bool
  1922 BaselineCompiler::emit_JSOP_BINDGNAME()
  1924     frame.push(ObjectValue(script->global()));
  1925     return true;
  1928 bool
  1929 BaselineCompiler::emit_JSOP_SETPROP()
  1931     // Keep lhs in R0, rhs in R1.
  1932     frame.popRegsAndSync(2);
  1934     // Call IC.
  1935     ICSetProp_Fallback::Compiler compiler(cx);
  1936     if (!emitOpIC(compiler.getStub(&stubSpace_)))
  1937         return false;
  1939     // The IC will return the RHS value in R0, mark it as pushed value.
  1940     frame.push(R0);
  1941     return true;
  1944 bool
  1945 BaselineCompiler::emit_JSOP_SETNAME()
  1947     return emit_JSOP_SETPROP();
  1950 bool
  1951 BaselineCompiler::emit_JSOP_SETGNAME()
  1953     return emit_JSOP_SETPROP();
  1956 bool
  1957 BaselineCompiler::emit_JSOP_GETPROP()
  1959     // Keep object in R0.
  1960     frame.popRegsAndSync(1);
  1962     // Call IC.
  1963     ICGetProp_Fallback::Compiler compiler(cx);
  1964     if (!emitOpIC(compiler.getStub(&stubSpace_)))
  1965         return false;
  1967     // Mark R0 as pushed stack value.
  1968     frame.push(R0);
  1969     return true;
  1972 bool
  1973 BaselineCompiler::emit_JSOP_CALLPROP()
  1975     return emit_JSOP_GETPROP();
  1978 bool
  1979 BaselineCompiler::emit_JSOP_LENGTH()
  1981     return emit_JSOP_GETPROP();
  1984 bool
  1985 BaselineCompiler::emit_JSOP_GETXPROP()
  1987     return emit_JSOP_GETPROP();
  1990 typedef bool (*DeletePropertyFn)(JSContext *, HandleValue, HandlePropertyName, bool *);
  1991 static const VMFunction DeletePropertyStrictInfo = FunctionInfo<DeletePropertyFn>(DeleteProperty<true>);
  1992 static const VMFunction DeletePropertyNonStrictInfo = FunctionInfo<DeletePropertyFn>(DeleteProperty<false>);
  1994 bool
  1995 BaselineCompiler::emit_JSOP_DELPROP()
  1997     // Keep value on the stack for the decompiler.
  1998     frame.syncStack(0);
  1999     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
  2001     prepareVMCall();
  2003     pushArg(ImmGCPtr(script->getName(pc)));
  2004     pushArg(R0);
  2006     if (!callVM(script->strict() ? DeletePropertyStrictInfo : DeletePropertyNonStrictInfo))
  2007         return false;
  2009     masm.boxNonDouble(JSVAL_TYPE_BOOLEAN, ReturnReg, R1);
  2010     frame.pop();
  2011     frame.push(R1);
  2012     return true;
  2015 void
  2016 BaselineCompiler::getScopeCoordinateObject(Register reg)
  2018     ScopeCoordinate sc(pc);
  2020     masm.loadPtr(frame.addressOfScopeChain(), reg);
  2021     for (unsigned i = sc.hops(); i; i--)
  2022         masm.extractObject(Address(reg, ScopeObject::offsetOfEnclosingScope()), reg);
  2025 Address
  2026 BaselineCompiler::getScopeCoordinateAddressFromObject(Register objReg, Register reg)
  2028     ScopeCoordinate sc(pc);
  2029     Shape *shape = ScopeCoordinateToStaticScopeShape(script, pc);
  2031     Address addr;
  2032     if (shape->numFixedSlots() <= sc.slot()) {
  2033         masm.loadPtr(Address(objReg, JSObject::offsetOfSlots()), reg);
  2034         return Address(reg, (sc.slot() - shape->numFixedSlots()) * sizeof(Value));
  2037     return Address(objReg, JSObject::getFixedSlotOffset(sc.slot()));
  2040 Address
  2041 BaselineCompiler::getScopeCoordinateAddress(Register reg)
  2043     getScopeCoordinateObject(reg);
  2044     return getScopeCoordinateAddressFromObject(reg, reg);
  2047 bool
  2048 BaselineCompiler::emit_JSOP_GETALIASEDVAR()
  2050     frame.syncStack(0);
  2052     Address address = getScopeCoordinateAddress(R0.scratchReg());
  2053     masm.loadValue(address, R0);
  2055     ICTypeMonitor_Fallback::Compiler compiler(cx, (ICMonitoredFallbackStub *) nullptr);
  2056     if (!emitOpIC(compiler.getStub(&stubSpace_)))
  2057         return false;
  2059     frame.push(R0);
  2060     return true;
  2063 bool
  2064 BaselineCompiler::emit_JSOP_SETALIASEDVAR()
  2066     JSScript *outerScript = ScopeCoordinateFunctionScript(script, pc);
  2067     if (outerScript && outerScript->treatAsRunOnce()) {
  2068         // Type updates for this operation might need to be tracked, so treat
  2069         // this as a SETPROP.
  2071         // Load rhs into R1.
  2072         frame.syncStack(1);
  2073         frame.popValue(R1);
  2075         // Load and box lhs into R0.
  2076         getScopeCoordinateObject(R2.scratchReg());
  2077         masm.tagValue(JSVAL_TYPE_OBJECT, R2.scratchReg(), R0);
  2079         // Call SETPROP IC.
  2080         ICSetProp_Fallback::Compiler compiler(cx);
  2081         if (!emitOpIC(compiler.getStub(&stubSpace_)))
  2082             return false;
  2084         // The IC will return the RHS value in R0, mark it as pushed value.
  2085         frame.push(R0);
  2086         return true;
  2089     // Keep rvalue in R0.
  2090     frame.popRegsAndSync(1);
  2091     Register objReg = R2.scratchReg();
  2093     getScopeCoordinateObject(objReg);
  2094     Address address = getScopeCoordinateAddressFromObject(objReg, R1.scratchReg());
  2095     masm.patchableCallPreBarrier(address, MIRType_Value);
  2096     masm.storeValue(R0, address);
  2097     frame.push(R0);
  2099 #ifdef JSGC_GENERATIONAL
  2100     // Fully sync the stack if post-barrier is needed.
  2101     // Scope coordinate object is already in R2.scratchReg().
  2102     frame.syncStack(0);
  2103     Register temp = R1.scratchReg();
  2105     Label skipBarrier;
  2106     masm.branchTestObject(Assembler::NotEqual, R0, &skipBarrier);
  2107     masm.branchPtrInNurseryRange(objReg, temp, &skipBarrier);
  2109     masm.call(&postBarrierSlot_);
  2111     masm.bind(&skipBarrier);
  2112 #endif
  2114     return true;
  2117 bool
  2118 BaselineCompiler::emit_JSOP_NAME()
  2120     frame.syncStack(0);
  2122     masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  2124     // Call IC.
  2125     ICGetName_Fallback::Compiler stubCompiler(cx);
  2126     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  2127         return false;
  2129     // Mark R0 as pushed stack value.
  2130     frame.push(R0);
  2131     return true;
  2134 bool
  2135 BaselineCompiler::emit_JSOP_BINDNAME()
  2137     frame.syncStack(0);
  2139     masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  2141     // Call IC.
  2142     ICBindName_Fallback::Compiler stubCompiler(cx);
  2143     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  2144         return false;
  2146     // Mark R0 as pushed stack value.
  2147     frame.push(R0);
  2148     return true;
  2151 typedef bool (*DeleteNameFn)(JSContext *, HandlePropertyName, HandleObject,
  2152                              MutableHandleValue);
  2153 static const VMFunction DeleteNameInfo = FunctionInfo<DeleteNameFn>(DeleteNameOperation);
  2155 bool
  2156 BaselineCompiler::emit_JSOP_DELNAME()
  2158     frame.syncStack(0);
  2159     masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  2161     prepareVMCall();
  2163     pushArg(R0.scratchReg());
  2164     pushArg(ImmGCPtr(script->getName(pc)));
  2166     if (!callVM(DeleteNameInfo))
  2167         return false;
  2169     frame.push(R0);
  2170     return true;
  2173 bool
  2174 BaselineCompiler::emit_JSOP_GETINTRINSIC()
  2176     frame.syncStack(0);
  2178     ICGetIntrinsic_Fallback::Compiler stubCompiler(cx);
  2179     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  2180         return false;
  2182     frame.push(R0);
  2183     return true;
  2186 typedef bool (*DefVarOrConstFn)(JSContext *, HandlePropertyName, unsigned, HandleObject);
  2187 static const VMFunction DefVarOrConstInfo = FunctionInfo<DefVarOrConstFn>(DefVarOrConst);
  2189 bool
  2190 BaselineCompiler::emit_JSOP_DEFVAR()
  2192     frame.syncStack(0);
  2194     unsigned attrs = JSPROP_ENUMERATE;
  2195     if (!script->isForEval())
  2196         attrs |= JSPROP_PERMANENT;
  2197     if (JSOp(*pc) == JSOP_DEFCONST)
  2198         attrs |= JSPROP_READONLY;
  2199     JS_ASSERT(attrs <= UINT32_MAX);
  2201     masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  2203     prepareVMCall();
  2205     pushArg(R0.scratchReg());
  2206     pushArg(Imm32(attrs));
  2207     pushArg(ImmGCPtr(script->getName(pc)));
  2209     return callVM(DefVarOrConstInfo);
  2212 bool
  2213 BaselineCompiler::emit_JSOP_DEFCONST()
  2215     return emit_JSOP_DEFVAR();
  2218 typedef bool (*SetConstFn)(JSContext *, HandlePropertyName, HandleObject, HandleValue);
  2219 static const VMFunction SetConstInfo = FunctionInfo<SetConstFn>(SetConst);
  2221 bool
  2222 BaselineCompiler::emit_JSOP_SETCONST()
  2224     frame.popRegsAndSync(1);
  2225     frame.push(R0);
  2226     frame.syncStack(0);
  2228     masm.loadPtr(frame.addressOfScopeChain(), R1.scratchReg());
  2230     prepareVMCall();
  2232     pushArg(R0);
  2233     pushArg(R1.scratchReg());
  2234     pushArg(ImmGCPtr(script->getName(pc)));
  2236     return callVM(SetConstInfo);
  2239 typedef bool (*DefFunOperationFn)(JSContext *, HandleScript, HandleObject, HandleFunction);
  2240 static const VMFunction DefFunOperationInfo = FunctionInfo<DefFunOperationFn>(DefFunOperation);
  2242 bool
  2243 BaselineCompiler::emit_JSOP_DEFFUN()
  2245     RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc)));
  2247     frame.syncStack(0);
  2248     masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  2250     prepareVMCall();
  2252     pushArg(ImmGCPtr(fun));
  2253     pushArg(R0.scratchReg());
  2254     pushArg(ImmGCPtr(script));
  2256     return callVM(DefFunOperationInfo);
  2259 typedef bool (*InitPropGetterSetterFn)(JSContext *, jsbytecode *, HandleObject, HandlePropertyName,
  2260                                        HandleObject);
  2261 static const VMFunction InitPropGetterSetterInfo =
  2262     FunctionInfo<InitPropGetterSetterFn>(InitGetterSetterOperation);
  2264 bool
  2265 BaselineCompiler::emitInitPropGetterSetter()
  2267     JS_ASSERT(JSOp(*pc) == JSOP_INITPROP_GETTER ||
  2268               JSOp(*pc) == JSOP_INITPROP_SETTER);
  2270     // Keep values on the stack for the decompiler.
  2271     frame.syncStack(0);
  2273     prepareVMCall();
  2275     masm.extractObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
  2276     masm.extractObject(frame.addressOfStackValue(frame.peek(-2)), R1.scratchReg());
  2278     pushArg(R0.scratchReg());
  2279     pushArg(ImmGCPtr(script->getName(pc)));
  2280     pushArg(R1.scratchReg());
  2281     pushArg(ImmPtr(pc));
  2283     if (!callVM(InitPropGetterSetterInfo))
  2284         return false;
  2286     frame.pop();
  2287     return true;
  2290 bool
  2291 BaselineCompiler::emit_JSOP_INITPROP_GETTER()
  2293     return emitInitPropGetterSetter();
  2296 bool
  2297 BaselineCompiler::emit_JSOP_INITPROP_SETTER()
  2299     return emitInitPropGetterSetter();
  2302 typedef bool (*InitElemGetterSetterFn)(JSContext *, jsbytecode *, HandleObject, HandleValue,
  2303                                        HandleObject);
  2304 static const VMFunction InitElemGetterSetterInfo =
  2305     FunctionInfo<InitElemGetterSetterFn>(InitGetterSetterOperation);
  2307 bool
  2308 BaselineCompiler::emitInitElemGetterSetter()
  2310     JS_ASSERT(JSOp(*pc) == JSOP_INITELEM_GETTER ||
  2311               JSOp(*pc) == JSOP_INITELEM_SETTER);
  2313     // Load index and value in R0 and R1, but keep values on the stack for the
  2314     // decompiler.
  2315     frame.syncStack(0);
  2316     masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
  2317     masm.extractObject(frame.addressOfStackValue(frame.peek(-1)), R1.scratchReg());
  2319     prepareVMCall();
  2321     pushArg(R1.scratchReg());
  2322     pushArg(R0);
  2323     masm.extractObject(frame.addressOfStackValue(frame.peek(-3)), R0.scratchReg());
  2324     pushArg(R0.scratchReg());
  2325     pushArg(ImmPtr(pc));
  2327     if (!callVM(InitElemGetterSetterInfo))
  2328         return false;
  2330     frame.popn(2);
  2331     return true;
  2334 bool
  2335 BaselineCompiler::emit_JSOP_INITELEM_GETTER()
  2337     return emitInitElemGetterSetter();
  2340 bool
  2341 BaselineCompiler::emit_JSOP_INITELEM_SETTER()
  2343     return emitInitElemGetterSetter();
  2346 bool
  2347 BaselineCompiler::emit_JSOP_GETLOCAL()
  2349     frame.pushLocal(GET_LOCALNO(pc));
  2350     return true;
  2353 bool
  2354 BaselineCompiler::emit_JSOP_SETLOCAL()
  2356     // Ensure no other StackValue refers to the old value, for instance i + (i = 3).
  2357     // This also allows us to use R0 as scratch below.
  2358     frame.syncStack(1);
  2360     uint32_t local = GET_LOCALNO(pc);
  2361     storeValue(frame.peek(-1), frame.addressOfLocal(local), R0);
  2362     return true;
  2365 bool
  2366 BaselineCompiler::emitFormalArgAccess(uint32_t arg, bool get)
  2368     // Fast path: the script does not use |arguments|, or is strict. In strict
  2369     // mode, formals do not alias the arguments object.
  2370     if (!script->argumentsHasVarBinding() || script->strict()) {
  2371         if (get) {
  2372             frame.pushArg(arg);
  2373         } else {
  2374             // See the comment in emit_JSOP_SETLOCAL.
  2375             frame.syncStack(1);
  2376             storeValue(frame.peek(-1), frame.addressOfArg(arg), R0);
  2379         return true;
  2382     // Sync so that we can use R0.
  2383     frame.syncStack(0);
  2385     // If the script is known to have an arguments object, we can just use it.
  2386     // Else, we *may* have an arguments object (because we can't invalidate
  2387     // when needsArgsObj becomes |true|), so we have to test HAS_ARGS_OBJ.
  2388     Label done;
  2389     if (!script->needsArgsObj()) {
  2390         Label hasArgsObj;
  2391         masm.branchTest32(Assembler::NonZero, frame.addressOfFlags(),
  2392                           Imm32(BaselineFrame::HAS_ARGS_OBJ), &hasArgsObj);
  2393         if (get)
  2394             masm.loadValue(frame.addressOfArg(arg), R0);
  2395         else
  2396             storeValue(frame.peek(-1), frame.addressOfArg(arg), R0);
  2397         masm.jump(&done);
  2398         masm.bind(&hasArgsObj);
  2401     // Load the arguments object data vector.
  2402     Register reg = R2.scratchReg();
  2403     masm.loadPtr(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfArgsObj()), reg);
  2404     masm.loadPrivate(Address(reg, ArgumentsObject::getDataSlotOffset()), reg);
  2406     // Load/store the argument.
  2407     Address argAddr(reg, ArgumentsData::offsetOfArgs() + arg * sizeof(Value));
  2408     if (get) {
  2409         masm.loadValue(argAddr, R0);
  2410         frame.push(R0);
  2411     } else {
  2412         masm.patchableCallPreBarrier(argAddr, MIRType_Value);
  2413         storeValue(frame.peek(-1), argAddr, R0);
  2415 #ifdef JSGC_GENERATIONAL
  2416         // Fully sync the stack if post-barrier is needed.
  2417         frame.syncStack(0);
  2418         Register temp = R1.scratchReg();
  2420         // Reload the arguments object
  2421         Register reg = R2.scratchReg();
  2422         masm.loadPtr(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfArgsObj()), reg);
  2424         Label skipBarrier;
  2425         masm.branchPtrInNurseryRange(reg, temp, &skipBarrier);
  2427         masm.call(&postBarrierSlot_);
  2429         masm.bind(&skipBarrier);
  2430 #endif
  2433     masm.bind(&done);
  2434     return true;
  2437 bool
  2438 BaselineCompiler::emit_JSOP_GETARG()
  2440     uint32_t arg = GET_ARGNO(pc);
  2441     return emitFormalArgAccess(arg, /* get = */ true);
  2444 bool
  2445 BaselineCompiler::emit_JSOP_SETARG()
  2447     // Ionmonkey can't inline functions with SETARG with magic arguments.
  2448     if (!script->argsObjAliasesFormals() && script->argumentsAliasesFormals())
  2449         script->setUninlineable();
  2451     modifiesArguments_ = true;
  2453     uint32_t arg = GET_ARGNO(pc);
  2454     return emitFormalArgAccess(arg, /* get = */ false);
  2457 bool
  2458 BaselineCompiler::emitCall()
  2460     JS_ASSERT(IsCallPC(pc));
  2462     uint32_t argc = GET_ARGC(pc);
  2464     frame.syncStack(0);
  2465     masm.mov(ImmWord(argc), R0.scratchReg());
  2467     // Call IC
  2468     ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ JSOp(*pc) == JSOP_NEW);
  2469     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  2470         return false;
  2472     // Update FrameInfo.
  2473     frame.popn(argc + 2);
  2474     frame.push(R0);
  2475     return true;
  2478 bool
  2479 BaselineCompiler::emit_JSOP_CALL()
  2481     return emitCall();
  2484 bool
  2485 BaselineCompiler::emit_JSOP_NEW()
  2487     return emitCall();
  2490 bool
  2491 BaselineCompiler::emit_JSOP_FUNCALL()
  2493     return emitCall();
  2496 bool
  2497 BaselineCompiler::emit_JSOP_FUNAPPLY()
  2499     return emitCall();
  2502 bool
  2503 BaselineCompiler::emit_JSOP_EVAL()
  2505     return emitCall();
  2508 typedef bool (*ImplicitThisFn)(JSContext *, HandleObject, HandlePropertyName,
  2509                                MutableHandleValue);
  2510 static const VMFunction ImplicitThisInfo = FunctionInfo<ImplicitThisFn>(ImplicitThisOperation);
  2512 bool
  2513 BaselineCompiler::emit_JSOP_IMPLICITTHIS()
  2515     frame.syncStack(0);
  2516     masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  2518     prepareVMCall();
  2520     pushArg(ImmGCPtr(script->getName(pc)));
  2521     pushArg(R0.scratchReg());
  2523     if (!callVM(ImplicitThisInfo))
  2524         return false;
  2526     frame.push(R0);
  2527     return true;
  2530 bool
  2531 BaselineCompiler::emit_JSOP_INSTANCEOF()
  2533     frame.popRegsAndSync(2);
  2535     ICInstanceOf_Fallback::Compiler stubCompiler(cx);
  2536     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  2537         return false;
  2539     frame.push(R0);
  2540     return true;
  2543 bool
  2544 BaselineCompiler::emit_JSOP_TYPEOF()
  2546     frame.popRegsAndSync(1);
  2548     ICTypeOf_Fallback::Compiler stubCompiler(cx);
  2549     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  2550         return false;
  2552     frame.push(R0);
  2553     return true;
  2556 bool
  2557 BaselineCompiler::emit_JSOP_TYPEOFEXPR()
  2559     return emit_JSOP_TYPEOF();
  2562 typedef bool (*SetCallFn)(JSContext *);
  2563 static const VMFunction SetCallInfo = FunctionInfo<SetCallFn>(js::SetCallOperation);
  2565 bool
  2566 BaselineCompiler::emit_JSOP_SETCALL()
  2568     prepareVMCall();
  2569     return callVM(SetCallInfo);
  2572 typedef bool (*ThrowFn)(JSContext *, HandleValue);
  2573 static const VMFunction ThrowInfo = FunctionInfo<ThrowFn>(js::Throw);
  2575 bool
  2576 BaselineCompiler::emit_JSOP_THROW()
  2578     // Keep value to throw in R0.
  2579     frame.popRegsAndSync(1);
  2581     prepareVMCall();
  2582     pushArg(R0);
  2584     return callVM(ThrowInfo);
  2587 bool
  2588 BaselineCompiler::emit_JSOP_TRY()
  2590     // Ionmonkey can't inline function with JSOP_TRY.
  2591     script->setUninlineable();
  2592     return true;
  2595 bool
  2596 BaselineCompiler::emit_JSOP_FINALLY()
  2598     // JSOP_FINALLY has a def count of 2, but these values are already on the
  2599     // stack (they're pushed by JSOP_GOSUB). Update the compiler's stack state.
  2600     frame.setStackDepth(frame.stackDepth() + 2);
  2602     // To match the interpreter, emit an interrupt check at the start of the
  2603     // finally block.
  2604     return emitInterruptCheck();
  2607 bool
  2608 BaselineCompiler::emit_JSOP_GOSUB()
  2610     // Push |false| so that RETSUB knows the value on top of the
  2611     // stack is not an exception but the offset to the op following
  2612     // this GOSUB.
  2613     frame.push(BooleanValue(false));
  2615     int32_t nextOffset = script->pcToOffset(GetNextPc(pc));
  2616     frame.push(Int32Value(nextOffset));
  2618     // Jump to the finally block.
  2619     frame.syncStack(0);
  2620     jsbytecode *target = pc + GET_JUMP_OFFSET(pc);
  2621     masm.jump(labelOf(target));
  2622     return true;
  2625 bool
  2626 BaselineCompiler::emit_JSOP_RETSUB()
  2628     frame.popRegsAndSync(2);
  2630     ICRetSub_Fallback::Compiler stubCompiler(cx);
  2631     return emitOpIC(stubCompiler.getStub(&stubSpace_));
  2634 typedef bool (*PushBlockScopeFn)(JSContext *, BaselineFrame *, Handle<StaticBlockObject *>);
  2635 static const VMFunction PushBlockScopeInfo = FunctionInfo<PushBlockScopeFn>(jit::PushBlockScope);
  2637 bool
  2638 BaselineCompiler::emit_JSOP_PUSHBLOCKSCOPE()
  2640     StaticBlockObject &blockObj = script->getObject(pc)->as<StaticBlockObject>();
  2642     // Call a stub to push the block on the block chain.
  2643     prepareVMCall();
  2644     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  2646     pushArg(ImmGCPtr(&blockObj));
  2647     pushArg(R0.scratchReg());
  2649     return callVM(PushBlockScopeInfo);
  2652 typedef bool (*PopBlockScopeFn)(JSContext *, BaselineFrame *);
  2653 static const VMFunction PopBlockScopeInfo = FunctionInfo<PopBlockScopeFn>(jit::PopBlockScope);
  2655 bool
  2656 BaselineCompiler::emit_JSOP_POPBLOCKSCOPE()
  2658     // Call a stub to pop the block from the block chain.
  2659     prepareVMCall();
  2661     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  2662     pushArg(R0.scratchReg());
  2664     return callVM(PopBlockScopeInfo);
  2667 typedef bool (*DebugLeaveBlockFn)(JSContext *, BaselineFrame *, jsbytecode *);
  2668 static const VMFunction DebugLeaveBlockInfo = FunctionInfo<DebugLeaveBlockFn>(jit::DebugLeaveBlock);
  2670 bool
  2671 BaselineCompiler::emit_JSOP_DEBUGLEAVEBLOCK()
  2673     if (!debugMode_)
  2674         return true;
  2676     prepareVMCall();
  2677     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  2678     pushArg(ImmPtr(pc));
  2679     pushArg(R0.scratchReg());
  2681     return callVM(DebugLeaveBlockInfo);
  2684 typedef bool (*EnterWithFn)(JSContext *, BaselineFrame *, HandleValue, Handle<StaticWithObject *>);
  2685 static const VMFunction EnterWithInfo = FunctionInfo<EnterWithFn>(jit::EnterWith);
  2687 bool
  2688 BaselineCompiler::emit_JSOP_ENTERWITH()
  2690     StaticWithObject &withObj = script->getObject(pc)->as<StaticWithObject>();
  2692     // Pop "with" object to R0.
  2693     frame.popRegsAndSync(1);
  2695     // Call a stub to push the object onto the scope chain.
  2696     prepareVMCall();
  2697     masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
  2699     pushArg(ImmGCPtr(&withObj));
  2700     pushArg(R0);
  2701     pushArg(R1.scratchReg());
  2703     return callVM(EnterWithInfo);
  2706 typedef bool (*LeaveWithFn)(JSContext *, BaselineFrame *);
  2707 static const VMFunction LeaveWithInfo = FunctionInfo<LeaveWithFn>(jit::LeaveWith);
  2709 bool
  2710 BaselineCompiler::emit_JSOP_LEAVEWITH()
  2712     // Call a stub to pop the with object from the scope chain.
  2713     prepareVMCall();
  2715     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  2716     pushArg(R0.scratchReg());
  2718     return callVM(LeaveWithInfo);
  2721 typedef bool (*GetAndClearExceptionFn)(JSContext *, MutableHandleValue);
  2722 static const VMFunction GetAndClearExceptionInfo =
  2723     FunctionInfo<GetAndClearExceptionFn>(GetAndClearException);
  2725 bool
  2726 BaselineCompiler::emit_JSOP_EXCEPTION()
  2728     prepareVMCall();
  2730     if (!callVM(GetAndClearExceptionInfo))
  2731         return false;
  2733     frame.push(R0);
  2734     return true;
  2737 typedef bool (*OnDebuggerStatementFn)(JSContext *, BaselineFrame *, jsbytecode *pc, bool *);
  2738 static const VMFunction OnDebuggerStatementInfo =
  2739     FunctionInfo<OnDebuggerStatementFn>(jit::OnDebuggerStatement);
  2741 bool
  2742 BaselineCompiler::emit_JSOP_DEBUGGER()
  2744     if (!debugMode_)
  2745         return true;
  2747     prepareVMCall();
  2748     pushArg(ImmPtr(pc));
  2750     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  2751     pushArg(R0.scratchReg());
  2753     if (!callVM(OnDebuggerStatementInfo))
  2754         return false;
  2756     // If the stub returns |true|, return the frame's return value.
  2757     Label done;
  2758     masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &done);
  2760         masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
  2761         masm.jump(&return_);
  2763     masm.bind(&done);
  2764     return true;
  2767 typedef bool (*DebugEpilogueFn)(JSContext *, BaselineFrame *, jsbytecode *, bool);
  2768 static const VMFunction DebugEpilogueInfo = FunctionInfo<DebugEpilogueFn>(jit::DebugEpilogue);
  2770 bool
  2771 BaselineCompiler::emitReturn()
  2773     if (debugMode_) {
  2774         // Move return value into the frame's rval slot.
  2775         masm.storeValue(JSReturnOperand, frame.addressOfReturnValue());
  2776         masm.or32(Imm32(BaselineFrame::HAS_RVAL), frame.addressOfFlags());
  2778         // Load BaselineFrame pointer in R0.
  2779         frame.syncStack(0);
  2780         masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  2782         prepareVMCall();
  2783         pushArg(Imm32(1));
  2784         pushArg(ImmPtr(pc));
  2785         pushArg(R0.scratchReg());
  2786         if (!callVM(DebugEpilogueInfo))
  2787             return false;
  2789         // Fix up the fake ICEntry appended by callVM for on-stack recompilation.
  2790         icEntries_.back().setForDebugEpilogue();
  2792         masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
  2795     // Only emit the jump if this JSOP_RETRVAL is not the last instruction.
  2796     // Not needed for last instruction, because last instruction flows
  2797     // into return label.
  2798     if (pc + GetBytecodeLength(pc) < script->codeEnd())
  2799         masm.jump(&return_);
  2801     return true;
  2804 bool
  2805 BaselineCompiler::emit_JSOP_RETURN()
  2807     JS_ASSERT(frame.stackDepth() == 1);
  2809     frame.popValue(JSReturnOperand);
  2810     return emitReturn();
  2813 bool
  2814 BaselineCompiler::emit_JSOP_RETRVAL()
  2816     JS_ASSERT(frame.stackDepth() == 0);
  2818     masm.moveValue(UndefinedValue(), JSReturnOperand);
  2820     if (!script->noScriptRval()) {
  2821         // Return the value in the return value slot, if any.
  2822         Label done;
  2823         Address flags = frame.addressOfFlags();
  2824         masm.branchTest32(Assembler::Zero, flags, Imm32(BaselineFrame::HAS_RVAL), &done);
  2825         masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
  2826         masm.bind(&done);
  2829     return emitReturn();
  2832 typedef bool (*ToIdFn)(JSContext *, HandleScript, jsbytecode *, HandleValue, HandleValue,
  2833                        MutableHandleValue);
  2834 static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(js::ToIdOperation);
  2836 bool
  2837 BaselineCompiler::emit_JSOP_TOID()
  2839     // Load index in R0, but keep values on the stack for the decompiler.
  2840     frame.syncStack(0);
  2841     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
  2843     // No-op if index is int32.
  2844     Label done;
  2845     masm.branchTestInt32(Assembler::Equal, R0, &done);
  2847     prepareVMCall();
  2849     masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R1);
  2851     pushArg(R0);
  2852     pushArg(R1);
  2853     pushArg(ImmPtr(pc));
  2854     pushArg(ImmGCPtr(script));
  2856     if (!callVM(ToIdInfo))
  2857         return false;
  2859     masm.bind(&done);
  2860     frame.pop(); // Pop index.
  2861     frame.push(R0);
  2862     return true;
  2865 bool
  2866 BaselineCompiler::emit_JSOP_TABLESWITCH()
  2868     frame.popRegsAndSync(1);
  2870     // Call IC.
  2871     ICTableSwitch::Compiler compiler(cx, pc);
  2872     return emitOpIC(compiler.getStub(&stubSpace_));
  2875 bool
  2876 BaselineCompiler::emit_JSOP_ITER()
  2878     frame.popRegsAndSync(1);
  2880     ICIteratorNew_Fallback::Compiler compiler(cx);
  2881     if (!emitOpIC(compiler.getStub(&stubSpace_)))
  2882         return false;
  2884     frame.push(R0);
  2885     return true;
  2888 bool
  2889 BaselineCompiler::emit_JSOP_MOREITER()
  2891     frame.syncStack(0);
  2892     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
  2894     ICIteratorMore_Fallback::Compiler compiler(cx);
  2895     if (!emitOpIC(compiler.getStub(&stubSpace_)))
  2896         return false;
  2898     frame.push(R0);
  2899     return true;
  2902 bool
  2903 BaselineCompiler::emit_JSOP_ITERNEXT()
  2905     frame.syncStack(0);
  2906     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
  2908     ICIteratorNext_Fallback::Compiler compiler(cx);
  2909     if (!emitOpIC(compiler.getStub(&stubSpace_)))
  2910         return false;
  2912     frame.push(R0);
  2913     return true;
  2916 bool
  2917 BaselineCompiler::emit_JSOP_ENDITER()
  2919     frame.popRegsAndSync(1);
  2921     ICIteratorClose_Fallback::Compiler compiler(cx);
  2922     return emitOpIC(compiler.getStub(&stubSpace_));
  2925 bool
  2926 BaselineCompiler::emit_JSOP_SETRVAL()
  2928     // Store to the frame's return value slot.
  2929     storeValue(frame.peek(-1), frame.addressOfReturnValue(), R2);
  2930     masm.or32(Imm32(BaselineFrame::HAS_RVAL), frame.addressOfFlags());
  2931     frame.pop();
  2932     return true;
  2935 bool
  2936 BaselineCompiler::emit_JSOP_CALLEE()
  2938     JS_ASSERT(function());
  2939     frame.syncStack(0);
  2940     masm.loadPtr(frame.addressOfCallee(), R0.scratchReg());
  2941     masm.tagValue(JSVAL_TYPE_OBJECT, R0.scratchReg(), R0);
  2942     frame.push(R0);
  2943     return true;
  2946 typedef bool (*NewArgumentsObjectFn)(JSContext *, BaselineFrame *, MutableHandleValue);
  2947 static const VMFunction NewArgumentsObjectInfo =
  2948     FunctionInfo<NewArgumentsObjectFn>(jit::NewArgumentsObject);
  2950 bool
  2951 BaselineCompiler::emit_JSOP_ARGUMENTS()
  2953     frame.syncStack(0);
  2955     Label done;
  2956     if (!script->argumentsHasVarBinding() || !script->needsArgsObj()) {
  2957         // We assume the script does not need an arguments object. However, this
  2958         // assumption can be invalidated later, see argumentsOptimizationFailed
  2959         // in JSScript. Because we can't invalidate baseline JIT code, we set a
  2960         // flag on BaselineScript when that happens and guard on it here.
  2961         masm.moveValue(MagicValue(JS_OPTIMIZED_ARGUMENTS), R0);
  2963         // Load script->baseline.
  2964         Register scratch = R1.scratchReg();
  2965         masm.movePtr(ImmGCPtr(script), scratch);
  2966         masm.loadPtr(Address(scratch, JSScript::offsetOfBaselineScript()), scratch);
  2968         // If we don't need an arguments object, skip the VM call.
  2969         masm.branchTest32(Assembler::Zero, Address(scratch, BaselineScript::offsetOfFlags()),
  2970                           Imm32(BaselineScript::NEEDS_ARGS_OBJ), &done);
  2973     prepareVMCall();
  2975     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  2976     pushArg(R0.scratchReg());
  2978     if (!callVM(NewArgumentsObjectInfo))
  2979         return false;
  2981     masm.bind(&done);
  2982     frame.push(R0);
  2983     return true;
  2986 typedef bool (*RunOnceScriptPrologueFn)(JSContext *, HandleScript);
  2987 static const VMFunction RunOnceScriptPrologueInfo =
  2988     FunctionInfo<RunOnceScriptPrologueFn>(js::RunOnceScriptPrologue);
  2990 bool
  2991 BaselineCompiler::emit_JSOP_RUNONCE()
  2993     frame.syncStack(0);
  2995     prepareVMCall();
  2997     masm.movePtr(ImmGCPtr(script), R0.scratchReg());
  2998     pushArg(R0.scratchReg());
  3000     return callVM(RunOnceScriptPrologueInfo);
  3003 bool
  3004 BaselineCompiler::emit_JSOP_REST()
  3006     frame.syncStack(0);
  3008     JSObject *templateObject = NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject);
  3009     if (!templateObject)
  3010         return false;
  3011     types::FixRestArgumentsType(cx, templateObject);
  3013     // Call IC.
  3014     ICRest_Fallback::Compiler compiler(cx, templateObject);
  3015     if (!emitOpIC(compiler.getStub(&stubSpace_)))
  3016         return false;
  3018     // Mark R0 as pushed stack value.
  3019     frame.push(R0);
  3020     return true;

mercurial