js/src/jit/BaselineCompiler.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/BaselineCompiler.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3021 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "jit/BaselineCompiler.h"
    1.11 +
    1.12 +#include "jit/BaselineHelpers.h"
    1.13 +#include "jit/BaselineIC.h"
    1.14 +#include "jit/BaselineJIT.h"
    1.15 +#include "jit/FixedList.h"
    1.16 +#include "jit/IonAnalysis.h"
    1.17 +#include "jit/IonLinker.h"
    1.18 +#include "jit/IonSpewer.h"
    1.19 +#ifdef JS_ION_PERF
    1.20 +# include "jit/PerfSpewer.h"
    1.21 +#endif
    1.22 +#include "jit/VMFunctions.h"
    1.23 +#include "vm/TraceLogging.h"
    1.24 +
    1.25 +#include "jsscriptinlines.h"
    1.26 +
    1.27 +#include "vm/Interpreter-inl.h"
    1.28 +
    1.29 +using namespace js;
    1.30 +using namespace js::jit;
    1.31 +
    1.32 +BaselineCompiler::BaselineCompiler(JSContext *cx, TempAllocator &alloc, JSScript *script)
    1.33 +  : BaselineCompilerSpecific(cx, alloc, script),
    1.34 +    modifiesArguments_(false)
    1.35 +{
    1.36 +}
    1.37 +
    1.38 +bool
    1.39 +BaselineCompiler::init()
    1.40 +{
    1.41 +    if (!analysis_.init(alloc_, cx->runtime()->gsnCache))
    1.42 +        return false;
    1.43 +
    1.44 +    if (!labels_.init(alloc_, script->length()))
    1.45 +        return false;
    1.46 +
    1.47 +    for (size_t i = 0; i < script->length(); i++)
    1.48 +        new (&labels_[i]) Label();
    1.49 +
    1.50 +    if (!frame.init(alloc_))
    1.51 +        return false;
    1.52 +
    1.53 +    return true;
    1.54 +}
    1.55 +
    1.56 +bool
    1.57 +BaselineCompiler::addPCMappingEntry(bool addIndexEntry)
    1.58 +{
    1.59 +    // Don't add multiple entries for a single pc.
    1.60 +    size_t nentries = pcMappingEntries_.length();
    1.61 +    if (nentries > 0 && pcMappingEntries_[nentries - 1].pcOffset == script->pcToOffset(pc))
    1.62 +        return true;
    1.63 +
    1.64 +    PCMappingEntry entry;
    1.65 +    entry.pcOffset = script->pcToOffset(pc);
    1.66 +    entry.nativeOffset = masm.currentOffset();
    1.67 +    entry.slotInfo = getStackTopSlotInfo();
    1.68 +    entry.addIndexEntry = addIndexEntry;
    1.69 +
    1.70 +    return pcMappingEntries_.append(entry);
    1.71 +}
    1.72 +
    1.73 +MethodStatus
    1.74 +BaselineCompiler::compile()
    1.75 +{
    1.76 +    IonSpew(IonSpew_BaselineScripts, "Baseline compiling script %s:%d (%p)",
    1.77 +            script->filename(), script->lineno(), script);
    1.78 +
    1.79 +    IonSpew(IonSpew_Codegen, "# Emitting baseline code for script %s:%d",
    1.80 +            script->filename(), script->lineno());
    1.81 +
    1.82 +    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
    1.83 +    AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script));
    1.84 +    AutoTraceLog logCompile(logger, TraceLogger::BaselineCompilation);
    1.85 +
    1.86 +    if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
    1.87 +        return Method_Error;
    1.88 +
    1.89 +    // Pin analysis info during compilation.
    1.90 +    types::AutoEnterAnalysis autoEnterAnalysis(cx);
    1.91 +
    1.92 +    JS_ASSERT(!script->hasBaselineScript());
    1.93 +
    1.94 +    if (!emitPrologue())
    1.95 +        return Method_Error;
    1.96 +
    1.97 +    MethodStatus status = emitBody();
    1.98 +    if (status != Method_Compiled)
    1.99 +        return status;
   1.100 +
   1.101 +    if (!emitEpilogue())
   1.102 +        return Method_Error;
   1.103 +
   1.104 +#ifdef JSGC_GENERATIONAL
   1.105 +    if (!emitOutOfLinePostBarrierSlot())
   1.106 +        return Method_Error;
   1.107 +#endif
   1.108 +
   1.109 +    if (masm.oom())
   1.110 +        return Method_Error;
   1.111 +
   1.112 +    Linker linker(masm);
   1.113 +    AutoFlushICache afc("Baseline");
   1.114 +    JitCode *code = linker.newCode<CanGC>(cx, JSC::BASELINE_CODE);
   1.115 +    if (!code)
   1.116 +        return Method_Error;
   1.117 +
   1.118 +    JSObject *templateScope = nullptr;
   1.119 +    if (script->functionNonDelazifying()) {
   1.120 +        RootedFunction fun(cx, script->functionNonDelazifying());
   1.121 +        if (fun->isHeavyweight()) {
   1.122 +            RootedScript scriptRoot(cx, script);
   1.123 +            templateScope = CallObject::createTemplateObject(cx, scriptRoot, gc::TenuredHeap);
   1.124 +            if (!templateScope)
   1.125 +                return Method_Error;
   1.126 +
   1.127 +            if (fun->isNamedLambda()) {
   1.128 +                RootedObject declEnvObject(cx, DeclEnvObject::createTemplateObject(cx, fun, gc::TenuredHeap));
   1.129 +                if (!declEnvObject)
   1.130 +                    return Method_Error;
   1.131 +                templateScope->as<ScopeObject>().setEnclosingScope(declEnvObject);
   1.132 +            }
   1.133 +        }
   1.134 +    }
   1.135 +
   1.136 +    // Encode the pc mapping table. See PCMappingIndexEntry for
   1.137 +    // more information.
   1.138 +    Vector<PCMappingIndexEntry> pcMappingIndexEntries(cx);
   1.139 +    CompactBufferWriter pcEntries;
   1.140 +    uint32_t previousOffset = 0;
   1.141 +
   1.142 +    for (size_t i = 0; i < pcMappingEntries_.length(); i++) {
   1.143 +        PCMappingEntry &entry = pcMappingEntries_[i];
   1.144 +        entry.fixupNativeOffset(masm);
   1.145 +
   1.146 +        if (entry.addIndexEntry) {
   1.147 +            PCMappingIndexEntry indexEntry;
   1.148 +            indexEntry.pcOffset = entry.pcOffset;
   1.149 +            indexEntry.nativeOffset = entry.nativeOffset;
   1.150 +            indexEntry.bufferOffset = pcEntries.length();
   1.151 +            if (!pcMappingIndexEntries.append(indexEntry))
   1.152 +                return Method_Error;
   1.153 +            previousOffset = entry.nativeOffset;
   1.154 +        }
   1.155 +
   1.156 +        // Use the high bit of the SlotInfo byte to indicate the
   1.157 +        // native code offset (relative to the previous op) > 0 and
   1.158 +        // comes next in the buffer.
   1.159 +        JS_ASSERT((entry.slotInfo.toByte() & 0x80) == 0);
   1.160 +
   1.161 +        if (entry.nativeOffset == previousOffset) {
   1.162 +            pcEntries.writeByte(entry.slotInfo.toByte());
   1.163 +        } else {
   1.164 +            JS_ASSERT(entry.nativeOffset > previousOffset);
   1.165 +            pcEntries.writeByte(0x80 | entry.slotInfo.toByte());
   1.166 +            pcEntries.writeUnsigned(entry.nativeOffset - previousOffset);
   1.167 +        }
   1.168 +
   1.169 +        previousOffset = entry.nativeOffset;
   1.170 +    }
   1.171 +
   1.172 +    if (pcEntries.oom())
   1.173 +        return Method_Error;
   1.174 +
   1.175 +    prologueOffset_.fixup(&masm);
   1.176 +    epilogueOffset_.fixup(&masm);
   1.177 +    spsPushToggleOffset_.fixup(&masm);
   1.178 +    postDebugPrologueOffset_.fixup(&masm);
   1.179 +
   1.180 +    // Note: There is an extra entry in the bytecode type map for the search hint, see below.
   1.181 +    size_t bytecodeTypeMapEntries = script->nTypeSets() + 1;
   1.182 +
   1.183 +    BaselineScript *baselineScript = BaselineScript::New(cx, prologueOffset_.offset(),
   1.184 +                                                         epilogueOffset_.offset(),
   1.185 +                                                         spsPushToggleOffset_.offset(),
   1.186 +                                                         postDebugPrologueOffset_.offset(),
   1.187 +                                                         icEntries_.length(),
   1.188 +                                                         pcMappingIndexEntries.length(),
   1.189 +                                                         pcEntries.length(),
   1.190 +                                                         bytecodeTypeMapEntries);
   1.191 +    if (!baselineScript)
   1.192 +        return Method_Error;
   1.193 +
   1.194 +    baselineScript->setMethod(code);
   1.195 +    baselineScript->setTemplateScope(templateScope);
   1.196 +
   1.197 +    IonSpew(IonSpew_BaselineScripts, "Created BaselineScript %p (raw %p) for %s:%d",
   1.198 +            (void *) baselineScript, (void *) code->raw(),
   1.199 +            script->filename(), script->lineno());
   1.200 +
   1.201 +#ifdef JS_ION_PERF
   1.202 +    writePerfSpewerBaselineProfile(script, code);
   1.203 +#endif
   1.204 +
   1.205 +    JS_ASSERT(pcMappingIndexEntries.length() > 0);
   1.206 +    baselineScript->copyPCMappingIndexEntries(&pcMappingIndexEntries[0]);
   1.207 +
   1.208 +    JS_ASSERT(pcEntries.length() > 0);
   1.209 +    baselineScript->copyPCMappingEntries(pcEntries);
   1.210 +
   1.211 +    // Copy IC entries
   1.212 +    if (icEntries_.length())
   1.213 +        baselineScript->copyICEntries(script, &icEntries_[0], masm);
   1.214 +
   1.215 +    // Adopt fallback stubs from the compiler into the baseline script.
   1.216 +    baselineScript->adoptFallbackStubs(&stubSpace_);
   1.217 +
   1.218 +    // Patch IC loads using IC entries
   1.219 +    for (size_t i = 0; i < icLoadLabels_.length(); i++) {
   1.220 +        CodeOffsetLabel label = icLoadLabels_[i].label;
   1.221 +        label.fixup(&masm);
   1.222 +        size_t icEntry = icLoadLabels_[i].icEntry;
   1.223 +        ICEntry *entryAddr = &(baselineScript->icEntry(icEntry));
   1.224 +        Assembler::patchDataWithValueCheck(CodeLocationLabel(code, label),
   1.225 +                                           ImmPtr(entryAddr),
   1.226 +                                           ImmPtr((void*)-1));
   1.227 +    }
   1.228 +
   1.229 +    if (modifiesArguments_)
   1.230 +        baselineScript->setModifiesArguments();
   1.231 +
   1.232 +    // All barriers are emitted off-by-default, toggle them on if needed.
   1.233 +    if (cx->zone()->needsBarrier())
   1.234 +        baselineScript->toggleBarriers(true);
   1.235 +
   1.236 +    // All SPS instrumentation is emitted toggled off.  Toggle them on if needed.
   1.237 +    if (cx->runtime()->spsProfiler.enabled())
   1.238 +        baselineScript->toggleSPS(true);
   1.239 +
   1.240 +    uint32_t *bytecodeMap = baselineScript->bytecodeTypeMap();
   1.241 +    types::FillBytecodeTypeMap(script, bytecodeMap);
   1.242 +
   1.243 +    // The last entry in the last index found, and is used to avoid binary
   1.244 +    // searches for the sought entry when queries are in linear order.
   1.245 +    bytecodeMap[script->nTypeSets()] = 0;
   1.246 +
   1.247 +    if (script->compartment()->debugMode())
   1.248 +        baselineScript->setDebugMode();
   1.249 +
   1.250 +    script->setBaselineScript(cx, baselineScript);
   1.251 +
   1.252 +    return Method_Compiled;
   1.253 +}
   1.254 +
   1.255 +bool
   1.256 +BaselineCompiler::emitPrologue()
   1.257 +{
   1.258 +    masm.push(BaselineFrameReg);
   1.259 +    masm.mov(BaselineStackReg, BaselineFrameReg);
   1.260 +
   1.261 +    masm.subPtr(Imm32(BaselineFrame::Size()), BaselineStackReg);
   1.262 +    masm.checkStackAlignment();
   1.263 +
   1.264 +    // Initialize BaselineFrame. For eval scripts, the scope chain
   1.265 +    // is passed in R1, so we have to be careful not to clobber
   1.266 +    // it.
   1.267 +
   1.268 +    // Initialize BaselineFrame::flags.
   1.269 +    uint32_t flags = 0;
   1.270 +    if (script->isForEval())
   1.271 +        flags |= BaselineFrame::EVAL;
   1.272 +    masm.store32(Imm32(flags), frame.addressOfFlags());
   1.273 +
   1.274 +    if (script->isForEval())
   1.275 +        masm.storePtr(ImmGCPtr(script), frame.addressOfEvalScript());
   1.276 +
   1.277 +    // Handle scope chain pre-initialization (in case GC gets run
   1.278 +    // during stack check).  For global and eval scripts, the scope
   1.279 +    // chain is in R1.  For function scripts, the scope chain is in
   1.280 +    // the callee, nullptr is stored for now so that GC doesn't choke
   1.281 +    // on a bogus ScopeChain value in the frame.
   1.282 +    if (function())
   1.283 +        masm.storePtr(ImmPtr(nullptr), frame.addressOfScopeChain());
   1.284 +    else
   1.285 +        masm.storePtr(R1.scratchReg(), frame.addressOfScopeChain());
   1.286 +
   1.287 +    // Functions with a large number of locals require two stack checks.
   1.288 +    // The VMCall for a fallible stack check can only occur after the
   1.289 +    // scope chain has been initialized, as that is required for proper
   1.290 +    // exception handling if the VMCall returns false.  The scope chain
   1.291 +    // initialization can only happen after the UndefinedValues for the
   1.292 +    // local slots have been pushed.
   1.293 +    // However by that time, the stack might have grown too much.
   1.294 +    // In these cases, we emit an extra, early, infallible check
   1.295 +    // before pushing the locals.  The early check sets a flag on the
   1.296 +    // frame if the stack check fails (but otherwise doesn't throw an
   1.297 +    // exception).  If the flag is set, then the jitcode skips past
   1.298 +    // the pushing of the locals, and directly to scope chain initialization
   1.299 +    // followed by the actual stack check, which will throw the correct
   1.300 +    // exception.
   1.301 +    Label earlyStackCheckFailed;
   1.302 +    if (needsEarlyStackCheck()) {
   1.303 +        if (!emitStackCheck(/* earlyCheck = */ true))
   1.304 +            return false;
   1.305 +        masm.branchTest32(Assembler::NonZero,
   1.306 +                          frame.addressOfFlags(),
   1.307 +                          Imm32(BaselineFrame::OVER_RECURSED),
   1.308 +                          &earlyStackCheckFailed);
   1.309 +    }
   1.310 +
   1.311 +    // Initialize locals to |undefined|. Use R0 to minimize code size.
   1.312 +    // If the number of locals to push is < LOOP_UNROLL_FACTOR, then the
   1.313 +    // initialization pushes are emitted directly and inline.  Otherwise,
   1.314 +    // they're emitted in a partially unrolled loop.
   1.315 +    if (frame.nlocals() > 0) {
   1.316 +        size_t LOOP_UNROLL_FACTOR = 4;
   1.317 +        size_t toPushExtra = frame.nlocals() % LOOP_UNROLL_FACTOR;
   1.318 +
   1.319 +        masm.moveValue(UndefinedValue(), R0);
   1.320 +
   1.321 +        // Handle any extra pushes left over by the optional unrolled loop below.
   1.322 +        for (size_t i = 0; i < toPushExtra; i++)
   1.323 +            masm.pushValue(R0);
   1.324 +
   1.325 +        // Partially unrolled loop of pushes.
   1.326 +        if (frame.nlocals() >= LOOP_UNROLL_FACTOR) {
   1.327 +            size_t toPush = frame.nlocals() - toPushExtra;
   1.328 +            JS_ASSERT(toPush % LOOP_UNROLL_FACTOR == 0);
   1.329 +            JS_ASSERT(toPush >= LOOP_UNROLL_FACTOR);
   1.330 +            masm.move32(Imm32(toPush), R1.scratchReg());
   1.331 +            // Emit unrolled loop with 4 pushes per iteration.
   1.332 +            Label pushLoop;
   1.333 +            masm.bind(&pushLoop);
   1.334 +            for (size_t i = 0; i < LOOP_UNROLL_FACTOR; i++)
   1.335 +                masm.pushValue(R0);
   1.336 +            masm.branchSub32(Assembler::NonZero,
   1.337 +                             Imm32(LOOP_UNROLL_FACTOR), R1.scratchReg(), &pushLoop);
   1.338 +        }
   1.339 +    }
   1.340 +
   1.341 +    if (needsEarlyStackCheck())
   1.342 +        masm.bind(&earlyStackCheckFailed);
   1.343 +
   1.344 +#ifdef JS_TRACE_LOGGING
   1.345 +    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
   1.346 +    Register loggerReg = RegisterSet::Volatile().takeGeneral();
   1.347 +    masm.Push(loggerReg);
   1.348 +    masm.movePtr(ImmPtr(logger), loggerReg);
   1.349 +    masm.tracelogStart(loggerReg, TraceLogCreateTextId(logger, script.get()));
   1.350 +    masm.tracelogStart(loggerReg, TraceLogger::Baseline);
   1.351 +    masm.Pop(loggerReg);
   1.352 +#endif
   1.353 +
   1.354 +    // Record the offset of the prologue, because Ion can bailout before
   1.355 +    // the scope chain is initialized.
   1.356 +    prologueOffset_ = masm.currentOffset();
   1.357 +
   1.358 +    // Initialize the scope chain before any operation that may
   1.359 +    // call into the VM and trigger a GC.
   1.360 +    if (!initScopeChain())
   1.361 +        return false;
   1.362 +
   1.363 +    if (!emitStackCheck())
   1.364 +        return false;
   1.365 +
   1.366 +    if (!emitDebugPrologue())
   1.367 +        return false;
   1.368 +
   1.369 +    if (!emitUseCountIncrement())
   1.370 +        return false;
   1.371 +
   1.372 +    if (!emitArgumentTypeChecks())
   1.373 +        return false;
   1.374 +
   1.375 +    if (!emitSPSPush())
   1.376 +        return false;
   1.377 +
   1.378 +    return true;
   1.379 +}
   1.380 +
   1.381 +bool
   1.382 +BaselineCompiler::emitEpilogue()
   1.383 +{
   1.384 +    // Record the offset of the epilogue, so we can do early return from
   1.385 +    // Debugger handlers during on-stack recompile.
   1.386 +    epilogueOffset_ = masm.currentOffset();
   1.387 +
   1.388 +    masm.bind(&return_);
   1.389 +
   1.390 +#ifdef JS_TRACE_LOGGING
   1.391 +    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
   1.392 +    Register loggerReg = RegisterSet::Volatile().takeGeneral();
   1.393 +    masm.Push(loggerReg);
   1.394 +    masm.movePtr(ImmPtr(logger), loggerReg);
   1.395 +    masm.tracelogStop(loggerReg, TraceLogger::Baseline);
   1.396 +    // Stop the script. Using a stop without checking the textId, since we
   1.397 +    // we didn't save the textId for the script.
   1.398 +    masm.tracelogStop(loggerReg);
   1.399 +    masm.Pop(loggerReg);
   1.400 +#endif
   1.401 +
   1.402 +    // Pop SPS frame if necessary
   1.403 +    emitSPSPop();
   1.404 +
   1.405 +    masm.mov(BaselineFrameReg, BaselineStackReg);
   1.406 +    masm.pop(BaselineFrameReg);
   1.407 +
   1.408 +    masm.ret();
   1.409 +    return true;
   1.410 +}
   1.411 +
   1.412 +#ifdef JSGC_GENERATIONAL
   1.413 +// On input:
   1.414 +//  R2.scratchReg() contains object being written to.
   1.415 +//  Otherwise, baseline stack will be synced, so all other registers are usable as scratch.
   1.416 +// This calls:
   1.417 +//    void PostWriteBarrier(JSRuntime *rt, JSObject *obj);
   1.418 +bool
   1.419 +BaselineCompiler::emitOutOfLinePostBarrierSlot()
   1.420 +{
   1.421 +    masm.bind(&postBarrierSlot_);
   1.422 +
   1.423 +    Register objReg = R2.scratchReg();
   1.424 +    GeneralRegisterSet regs(GeneralRegisterSet::All());
   1.425 +    regs.take(objReg);
   1.426 +    regs.take(BaselineFrameReg);
   1.427 +    Register scratch = regs.takeAny();
   1.428 +#if defined(JS_CODEGEN_ARM)
   1.429 +    // On ARM, save the link register before calling.  It contains the return
   1.430 +    // address.  The |masm.ret()| later will pop this into |pc| to return.
   1.431 +    masm.push(lr);
   1.432 +#elif defined(JS_CODEGEN_MIPS)
   1.433 +    masm.push(ra);
   1.434 +#endif
   1.435 +
   1.436 +    masm.setupUnalignedABICall(2, scratch);
   1.437 +    masm.movePtr(ImmPtr(cx->runtime()), scratch);
   1.438 +    masm.passABIArg(scratch);
   1.439 +    masm.passABIArg(objReg);
   1.440 +    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, PostWriteBarrier));
   1.441 +
   1.442 +    masm.ret();
   1.443 +    return true;
   1.444 +}
   1.445 +#endif // JSGC_GENERATIONAL
   1.446 +
   1.447 +bool
   1.448 +BaselineCompiler::emitIC(ICStub *stub, ICEntry::Kind kind)
   1.449 +{
   1.450 +    ICEntry *entry = allocateICEntry(stub, kind);
   1.451 +    if (!entry)
   1.452 +        return false;
   1.453 +
   1.454 +    CodeOffsetLabel patchOffset;
   1.455 +    EmitCallIC(&patchOffset, masm);
   1.456 +    entry->setReturnOffset(masm.currentOffset());
   1.457 +    if (!addICLoadLabel(patchOffset))
   1.458 +        return false;
   1.459 +
   1.460 +    return true;
   1.461 +}
   1.462 +
   1.463 +typedef bool (*CheckOverRecursedWithExtraFn)(JSContext *, BaselineFrame *, uint32_t, uint32_t);
   1.464 +static const VMFunction CheckOverRecursedWithExtraInfo =
   1.465 +    FunctionInfo<CheckOverRecursedWithExtraFn>(CheckOverRecursedWithExtra);
   1.466 +
   1.467 +bool
   1.468 +BaselineCompiler::emitStackCheck(bool earlyCheck)
   1.469 +{
   1.470 +    Label skipCall;
   1.471 +    uintptr_t *limitAddr = &cx->runtime()->mainThread.jitStackLimit;
   1.472 +    uint32_t slotsSize = script->nslots() * sizeof(Value);
   1.473 +    uint32_t tolerance = earlyCheck ? slotsSize : 0;
   1.474 +
   1.475 +    masm.movePtr(BaselineStackReg, R1.scratchReg());
   1.476 +
   1.477 +    // If this is the early stack check, locals haven't been pushed yet.  Adjust the
   1.478 +    // stack pointer to account for the locals that would be pushed before performing
   1.479 +    // the guard around the vmcall to the stack check.
   1.480 +    if (earlyCheck)
   1.481 +        masm.subPtr(Imm32(tolerance), R1.scratchReg());
   1.482 +
   1.483 +    // If this is the late stack check for a frame which contains an early stack check,
   1.484 +    // then the early stack check might have failed and skipped past the pushing of locals
   1.485 +    // on the stack.
   1.486 +    //
   1.487 +    // If this is a possibility, then the OVER_RECURSED flag should be checked, and the
   1.488 +    // VMCall to CheckOverRecursed done unconditionally if it's set.
   1.489 +    Label forceCall;
   1.490 +    if (!earlyCheck && needsEarlyStackCheck()) {
   1.491 +        masm.branchTest32(Assembler::NonZero,
   1.492 +                          frame.addressOfFlags(),
   1.493 +                          Imm32(BaselineFrame::OVER_RECURSED),
   1.494 +                          &forceCall);
   1.495 +    }
   1.496 +
   1.497 +    masm.branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(limitAddr), R1.scratchReg(),
   1.498 +                   &skipCall);
   1.499 +
   1.500 +    if (!earlyCheck && needsEarlyStackCheck())
   1.501 +        masm.bind(&forceCall);
   1.502 +
   1.503 +    prepareVMCall();
   1.504 +    pushArg(Imm32(earlyCheck));
   1.505 +    pushArg(Imm32(tolerance));
   1.506 +    masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
   1.507 +    pushArg(R1.scratchReg());
   1.508 +
   1.509 +    CallVMPhase phase = POST_INITIALIZE;
   1.510 +    if (earlyCheck)
   1.511 +        phase = PRE_INITIALIZE;
   1.512 +    else if (needsEarlyStackCheck())
   1.513 +        phase = CHECK_OVER_RECURSED;
   1.514 +
   1.515 +    if (!callVM(CheckOverRecursedWithExtraInfo, phase))
   1.516 +        return false;
   1.517 +
   1.518 +    masm.bind(&skipCall);
   1.519 +    return true;
   1.520 +}
   1.521 +
   1.522 +typedef bool (*DebugPrologueFn)(JSContext *, BaselineFrame *, jsbytecode *, bool *);
   1.523 +static const VMFunction DebugPrologueInfo = FunctionInfo<DebugPrologueFn>(jit::DebugPrologue);
   1.524 +
   1.525 +bool
   1.526 +BaselineCompiler::emitDebugPrologue()
   1.527 +{
   1.528 +    if (debugMode_) {
   1.529 +        // Load pointer to BaselineFrame in R0.
   1.530 +        masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
   1.531 +
   1.532 +        prepareVMCall();
   1.533 +        pushArg(ImmPtr(pc));
   1.534 +        pushArg(R0.scratchReg());
   1.535 +        if (!callVM(DebugPrologueInfo))
   1.536 +            return false;
   1.537 +
   1.538 +        // Fix up the fake ICEntry appended by callVM for on-stack recompilation.
   1.539 +        icEntries_.back().setForDebugPrologue();
   1.540 +
   1.541 +        // If the stub returns |true|, we have to return the value stored in the
   1.542 +        // frame's return value slot.
   1.543 +        Label done;
   1.544 +        masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &done);
   1.545 +        {
   1.546 +            masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
   1.547 +            masm.jump(&return_);
   1.548 +        }
   1.549 +        masm.bind(&done);
   1.550 +    }
   1.551 +
   1.552 +    postDebugPrologueOffset_ = masm.currentOffset();
   1.553 +
   1.554 +    return true;
   1.555 +}
   1.556 +
   1.557 +typedef bool (*StrictEvalPrologueFn)(JSContext *, BaselineFrame *);
   1.558 +static const VMFunction StrictEvalPrologueInfo =
   1.559 +    FunctionInfo<StrictEvalPrologueFn>(jit::StrictEvalPrologue);
   1.560 +
   1.561 +typedef bool (*HeavyweightFunPrologueFn)(JSContext *, BaselineFrame *);
   1.562 +static const VMFunction HeavyweightFunPrologueInfo =
   1.563 +    FunctionInfo<HeavyweightFunPrologueFn>(jit::HeavyweightFunPrologue);
   1.564 +
   1.565 +bool
   1.566 +BaselineCompiler::initScopeChain()
   1.567 +{
   1.568 +    CallVMPhase phase = POST_INITIALIZE;
   1.569 +    if (needsEarlyStackCheck())
   1.570 +        phase = CHECK_OVER_RECURSED;
   1.571 +
   1.572 +    RootedFunction fun(cx, function());
   1.573 +    if (fun) {
   1.574 +        // Use callee->environment as scope chain. Note that we do
   1.575 +        // this also for heavy-weight functions, so that the scope
   1.576 +        // chain slot is properly initialized if the call triggers GC.
   1.577 +        Register callee = R0.scratchReg();
   1.578 +        Register scope = R1.scratchReg();
   1.579 +        masm.loadPtr(frame.addressOfCallee(), callee);
   1.580 +        masm.loadPtr(Address(callee, JSFunction::offsetOfEnvironment()), scope);
   1.581 +        masm.storePtr(scope, frame.addressOfScopeChain());
   1.582 +
   1.583 +        if (fun->isHeavyweight()) {
   1.584 +            // Call into the VM to create a new call object.
   1.585 +            prepareVMCall();
   1.586 +
   1.587 +            masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
   1.588 +            pushArg(R0.scratchReg());
   1.589 +
   1.590 +            if (!callVM(HeavyweightFunPrologueInfo, phase))
   1.591 +                return false;
   1.592 +        }
   1.593 +    } else {
   1.594 +        // ScopeChain pointer in BaselineFrame has already been initialized
   1.595 +        // in prologue.
   1.596 +
   1.597 +        if (script->isForEval() && script->strict()) {
   1.598 +            // Strict eval needs its own call object.
   1.599 +            prepareVMCall();
   1.600 +
   1.601 +            masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
   1.602 +            pushArg(R0.scratchReg());
   1.603 +
   1.604 +            if (!callVM(StrictEvalPrologueInfo, phase))
   1.605 +                return false;
   1.606 +        }
   1.607 +    }
   1.608 +
   1.609 +    return true;
   1.610 +}
   1.611 +
   1.612 +typedef bool (*InterruptCheckFn)(JSContext *);
   1.613 +static const VMFunction InterruptCheckInfo = FunctionInfo<InterruptCheckFn>(InterruptCheck);
   1.614 +
   1.615 +bool
   1.616 +BaselineCompiler::emitInterruptCheck()
   1.617 +{
   1.618 +    frame.syncStack(0);
   1.619 +
   1.620 +    Label done;
   1.621 +    void *interrupt = (void *)&cx->runtime()->interrupt;
   1.622 +    masm.branch32(Assembler::Equal, AbsoluteAddress(interrupt), Imm32(0), &done);
   1.623 +
   1.624 +    prepareVMCall();
   1.625 +    if (!callVM(InterruptCheckInfo))
   1.626 +        return false;
   1.627 +
   1.628 +    masm.bind(&done);
   1.629 +    return true;
   1.630 +}
   1.631 +
   1.632 +bool
   1.633 +BaselineCompiler::emitUseCountIncrement(bool allowOsr)
   1.634 +{
   1.635 +    // Emit no use count increments or bailouts if Ion is not
   1.636 +    // enabled, or if the script will never be Ion-compileable
   1.637 +
   1.638 +    if (!ionCompileable_ && !ionOSRCompileable_)
   1.639 +        return true;
   1.640 +
   1.641 +    Register scriptReg = R2.scratchReg();
   1.642 +    Register countReg = R0.scratchReg();
   1.643 +    Address useCountAddr(scriptReg, JSScript::offsetOfUseCount());
   1.644 +
   1.645 +    masm.movePtr(ImmGCPtr(script), scriptReg);
   1.646 +    masm.load32(useCountAddr, countReg);
   1.647 +    masm.add32(Imm32(1), countReg);
   1.648 +    masm.store32(countReg, useCountAddr);
   1.649 +
   1.650 +    // If this is a loop inside a catch or finally block, increment the use
   1.651 +    // count but don't attempt OSR (Ion only compiles the try block).
   1.652 +    if (analysis_.info(pc).loopEntryInCatchOrFinally) {
   1.653 +        JS_ASSERT(JSOp(*pc) == JSOP_LOOPENTRY);
   1.654 +        return true;
   1.655 +    }
   1.656 +
   1.657 +    // OSR not possible at this loop entry.
   1.658 +    if (!allowOsr) {
   1.659 +        JS_ASSERT(JSOp(*pc) == JSOP_LOOPENTRY);
   1.660 +        return true;
   1.661 +    }
   1.662 +
   1.663 +    Label skipCall;
   1.664 +
   1.665 +    const OptimizationInfo *info = js_IonOptimizations.get(js_IonOptimizations.firstLevel());
   1.666 +    uint32_t minUses = info->usesBeforeCompile(script, pc);
   1.667 +    masm.branch32(Assembler::LessThan, countReg, Imm32(minUses), &skipCall);
   1.668 +
   1.669 +    masm.branchPtr(Assembler::Equal,
   1.670 +                   Address(scriptReg, JSScript::offsetOfIonScript()),
   1.671 +                   ImmPtr(ION_COMPILING_SCRIPT), &skipCall);
   1.672 +
   1.673 +    // Call IC.
   1.674 +    ICUseCount_Fallback::Compiler stubCompiler(cx);
   1.675 +    if (!emitNonOpIC(stubCompiler.getStub(&stubSpace_)))
   1.676 +        return false;
   1.677 +
   1.678 +    masm.bind(&skipCall);
   1.679 +
   1.680 +    return true;
   1.681 +}
   1.682 +
   1.683 +bool
   1.684 +BaselineCompiler::emitArgumentTypeChecks()
   1.685 +{
   1.686 +    if (!function())
   1.687 +        return true;
   1.688 +
   1.689 +    frame.pushThis();
   1.690 +    frame.popRegsAndSync(1);
   1.691 +
   1.692 +    ICTypeMonitor_Fallback::Compiler compiler(cx, (uint32_t) 0);
   1.693 +    if (!emitNonOpIC(compiler.getStub(&stubSpace_)))
   1.694 +        return false;
   1.695 +
   1.696 +    for (size_t i = 0; i < function()->nargs(); i++) {
   1.697 +        frame.pushArg(i);
   1.698 +        frame.popRegsAndSync(1);
   1.699 +
   1.700 +        ICTypeMonitor_Fallback::Compiler compiler(cx, i + 1);
   1.701 +        if (!emitNonOpIC(compiler.getStub(&stubSpace_)))
   1.702 +            return false;
   1.703 +    }
   1.704 +
   1.705 +    return true;
   1.706 +}
   1.707 +
   1.708 +bool
   1.709 +BaselineCompiler::emitDebugTrap()
   1.710 +{
   1.711 +    JS_ASSERT(debugMode_);
   1.712 +    JS_ASSERT(frame.numUnsyncedSlots() == 0);
   1.713 +
   1.714 +    bool enabled = script->stepModeEnabled() || script->hasBreakpointsAt(pc);
   1.715 +
   1.716 +    // Emit patchable call to debug trap handler.
   1.717 +    JitCode *handler = cx->runtime()->jitRuntime()->debugTrapHandler(cx);
   1.718 +    mozilla::DebugOnly<CodeOffsetLabel> offset = masm.toggledCall(handler, enabled);
   1.719 +
   1.720 +#ifdef DEBUG
   1.721 +    // Patchable call offset has to match the pc mapping offset.
   1.722 +    PCMappingEntry &entry = pcMappingEntries_.back();
   1.723 +    JS_ASSERT((&offset)->offset() == entry.nativeOffset);
   1.724 +#endif
   1.725 +
   1.726 +    // Add an IC entry for the return offset -> pc mapping.
   1.727 +    ICEntry icEntry(script->pcToOffset(pc), ICEntry::Kind_DebugTrap);
   1.728 +    icEntry.setReturnOffset(masm.currentOffset());
   1.729 +    if (!icEntries_.append(icEntry))
   1.730 +        return false;
   1.731 +
   1.732 +    return true;
   1.733 +}
   1.734 +
   1.735 +bool
   1.736 +BaselineCompiler::emitSPSPush()
   1.737 +{
   1.738 +    // Enter the IC, guarded by a toggled jump (initially disabled).
   1.739 +    Label noPush;
   1.740 +    CodeOffsetLabel toggleOffset = masm.toggledJump(&noPush);
   1.741 +    JS_ASSERT(frame.numUnsyncedSlots() == 0);
   1.742 +    ICProfiler_Fallback::Compiler compiler(cx);
   1.743 +    if (!emitNonOpIC(compiler.getStub(&stubSpace_)))
   1.744 +        return false;
   1.745 +    masm.bind(&noPush);
   1.746 +
   1.747 +    // Store the start offset in the appropriate location.
   1.748 +    JS_ASSERT(spsPushToggleOffset_.offset() == 0);
   1.749 +    spsPushToggleOffset_ = toggleOffset;
   1.750 +    return true;
   1.751 +}
   1.752 +
   1.753 +void
   1.754 +BaselineCompiler::emitSPSPop()
   1.755 +{
   1.756 +    // If profiler entry was pushed on this frame, pop it.
   1.757 +    Label noPop;
   1.758 +    masm.branchTest32(Assembler::Zero, frame.addressOfFlags(),
   1.759 +                      Imm32(BaselineFrame::HAS_PUSHED_SPS_FRAME), &noPop);
   1.760 +    masm.spsPopFrameSafe(&cx->runtime()->spsProfiler, R1.scratchReg());
   1.761 +    masm.bind(&noPop);
   1.762 +}
   1.763 +
   1.764 +MethodStatus
   1.765 +BaselineCompiler::emitBody()
   1.766 +{
   1.767 +    JS_ASSERT(pc == script->code());
   1.768 +
   1.769 +    bool lastOpUnreachable = false;
   1.770 +    uint32_t emittedOps = 0;
   1.771 +    mozilla::DebugOnly<jsbytecode *> prevpc = pc;
   1.772 +
   1.773 +    while (true) {
   1.774 +        JSOp op = JSOp(*pc);
   1.775 +        IonSpew(IonSpew_BaselineOp, "Compiling op @ %d: %s",
   1.776 +                int(script->pcToOffset(pc)), js_CodeName[op]);
   1.777 +
   1.778 +        BytecodeInfo *info = analysis_.maybeInfo(pc);
   1.779 +
   1.780 +        // Skip unreachable ops.
   1.781 +        if (!info) {
   1.782 +            // Test if last instructions and stop emitting in that case.
   1.783 +            pc += GetBytecodeLength(pc);
   1.784 +            if (pc >= script->codeEnd())
   1.785 +                break;
   1.786 +
   1.787 +            lastOpUnreachable = true;
   1.788 +            prevpc = pc;
   1.789 +            continue;
   1.790 +        }
   1.791 +
   1.792 +        // Fully sync the stack if there are incoming jumps.
   1.793 +        if (info->jumpTarget) {
   1.794 +            frame.syncStack(0);
   1.795 +            frame.setStackDepth(info->stackDepth);
   1.796 +        }
   1.797 +
   1.798 +        // Always sync in debug mode.
   1.799 +        if (debugMode_)
   1.800 +            frame.syncStack(0);
   1.801 +
   1.802 +        // At the beginning of any op, at most the top 2 stack-values are unsynced.
   1.803 +        if (frame.stackDepth() > 2)
   1.804 +            frame.syncStack(2);
   1.805 +
   1.806 +        frame.assertValidState(*info);
   1.807 +
   1.808 +        masm.bind(labelOf(pc));
   1.809 +
   1.810 +        // Add a PC -> native mapping entry for the current op. These entries are
   1.811 +        // used when we need the native code address for a given pc, for instance
   1.812 +        // for bailouts from Ion, the debugger and exception handling. See
   1.813 +        // PCMappingIndexEntry for more information.
   1.814 +        bool addIndexEntry = (pc == script->code() || lastOpUnreachable || emittedOps > 100);
   1.815 +        if (addIndexEntry)
   1.816 +            emittedOps = 0;
   1.817 +        if (!addPCMappingEntry(addIndexEntry))
   1.818 +            return Method_Error;
   1.819 +
   1.820 +        // Emit traps for breakpoints and step mode.
   1.821 +        if (debugMode_ && !emitDebugTrap())
   1.822 +            return Method_Error;
   1.823 +
   1.824 +        switch (op) {
   1.825 +          default:
   1.826 +            IonSpew(IonSpew_BaselineAbort, "Unhandled op: %s", js_CodeName[op]);
   1.827 +            return Method_CantCompile;
   1.828 +
   1.829 +#define EMIT_OP(OP)                            \
   1.830 +          case OP:                             \
   1.831 +            if (!this->emit_##OP())            \
   1.832 +                return Method_Error;           \
   1.833 +            break;
   1.834 +OPCODE_LIST(EMIT_OP)
   1.835 +#undef EMIT_OP
   1.836 +        }
   1.837 +
   1.838 +        // Test if last instructions and stop emitting in that case.
   1.839 +        pc += GetBytecodeLength(pc);
   1.840 +        if (pc >= script->codeEnd())
   1.841 +            break;
   1.842 +
   1.843 +        emittedOps++;
   1.844 +        lastOpUnreachable = false;
   1.845 +#ifdef DEBUG
   1.846 +        prevpc = pc;
   1.847 +#endif
   1.848 +    }
   1.849 +
   1.850 +    JS_ASSERT(JSOp(*prevpc) == JSOP_RETRVAL);
   1.851 +    return Method_Compiled;
   1.852 +}
   1.853 +
   1.854 +bool
   1.855 +BaselineCompiler::emit_JSOP_NOP()
   1.856 +{
   1.857 +    return true;
   1.858 +}
   1.859 +
   1.860 +bool
   1.861 +BaselineCompiler::emit_JSOP_LABEL()
   1.862 +{
   1.863 +    return true;
   1.864 +}
   1.865 +
   1.866 +bool
   1.867 +BaselineCompiler::emit_JSOP_POP()
   1.868 +{
   1.869 +    frame.pop();
   1.870 +    return true;
   1.871 +}
   1.872 +
   1.873 +bool
   1.874 +BaselineCompiler::emit_JSOP_POPN()
   1.875 +{
   1.876 +    frame.popn(GET_UINT16(pc));
   1.877 +    return true;
   1.878 +}
   1.879 +
   1.880 +bool
   1.881 +BaselineCompiler::emit_JSOP_DUPAT()
   1.882 +{
   1.883 +    frame.syncStack(0);
   1.884 +
   1.885 +    // DUPAT takes a value on the stack and re-pushes it on top.  It's like
   1.886 +    // GETLOCAL but it addresses from the top of the stack instead of from the
   1.887 +    // stack frame.
   1.888 +
   1.889 +    int depth = -(GET_UINT24(pc) + 1);
   1.890 +    masm.loadValue(frame.addressOfStackValue(frame.peek(depth)), R0);
   1.891 +    frame.push(R0);
   1.892 +    return true;
   1.893 +}
   1.894 +
   1.895 +bool
   1.896 +BaselineCompiler::emit_JSOP_DUP()
   1.897 +{
   1.898 +    // Keep top stack value in R0, sync the rest so that we can use R1. We use
   1.899 +    // separate registers because every register can be used by at most one
   1.900 +    // StackValue.
   1.901 +    frame.popRegsAndSync(1);
   1.902 +    masm.moveValue(R0, R1);
   1.903 +
   1.904 +    // inc/dec ops use DUP followed by ONE, ADD. Push R0 last to avoid a move.
   1.905 +    frame.push(R1);
   1.906 +    frame.push(R0);
   1.907 +    return true;
   1.908 +}
   1.909 +
   1.910 +bool
   1.911 +BaselineCompiler::emit_JSOP_DUP2()
   1.912 +{
   1.913 +    frame.syncStack(0);
   1.914 +
   1.915 +    masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
   1.916 +    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
   1.917 +
   1.918 +    frame.push(R0);
   1.919 +    frame.push(R1);
   1.920 +    return true;
   1.921 +}
   1.922 +
   1.923 +bool
   1.924 +BaselineCompiler::emit_JSOP_SWAP()
   1.925 +{
   1.926 +    // Keep top stack values in R0 and R1.
   1.927 +    frame.popRegsAndSync(2);
   1.928 +
   1.929 +    frame.push(R1);
   1.930 +    frame.push(R0);
   1.931 +    return true;
   1.932 +}
   1.933 +
   1.934 +bool
   1.935 +BaselineCompiler::emit_JSOP_PICK()
   1.936 +{
   1.937 +    frame.syncStack(0);
   1.938 +
   1.939 +    // Pick takes a value on the stack and moves it to the top.
   1.940 +    // For instance, pick 2:
   1.941 +    //     before: A B C D E
   1.942 +    //     after : A B D E C
   1.943 +
   1.944 +    // First, move value at -(amount + 1) into R0.
   1.945 +    int depth = -(GET_INT8(pc) + 1);
   1.946 +    masm.loadValue(frame.addressOfStackValue(frame.peek(depth)), R0);
   1.947 +
   1.948 +    // Move the other values down.
   1.949 +    depth++;
   1.950 +    for (; depth < 0; depth++) {
   1.951 +        Address source = frame.addressOfStackValue(frame.peek(depth));
   1.952 +        Address dest = frame.addressOfStackValue(frame.peek(depth - 1));
   1.953 +        masm.loadValue(source, R1);
   1.954 +        masm.storeValue(R1, dest);
   1.955 +    }
   1.956 +
   1.957 +    // Push R0.
   1.958 +    frame.pop();
   1.959 +    frame.push(R0);
   1.960 +    return true;
   1.961 +}
   1.962 +
   1.963 +bool
   1.964 +BaselineCompiler::emit_JSOP_GOTO()
   1.965 +{
   1.966 +    frame.syncStack(0);
   1.967 +
   1.968 +    jsbytecode *target = pc + GET_JUMP_OFFSET(pc);
   1.969 +    masm.jump(labelOf(target));
   1.970 +    return true;
   1.971 +}
   1.972 +
   1.973 +bool
   1.974 +BaselineCompiler::emitToBoolean()
   1.975 +{
   1.976 +    Label skipIC;
   1.977 +    masm.branchTestBoolean(Assembler::Equal, R0, &skipIC);
   1.978 +
   1.979 +    // Call IC
   1.980 +    ICToBool_Fallback::Compiler stubCompiler(cx);
   1.981 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
   1.982 +        return false;
   1.983 +
   1.984 +    masm.bind(&skipIC);
   1.985 +    return true;
   1.986 +}
   1.987 +
   1.988 +bool
   1.989 +BaselineCompiler::emitTest(bool branchIfTrue)
   1.990 +{
   1.991 +    bool knownBoolean = frame.peek(-1)->isKnownBoolean();
   1.992 +
   1.993 +    // Keep top stack value in R0.
   1.994 +    frame.popRegsAndSync(1);
   1.995 +
   1.996 +    if (!knownBoolean && !emitToBoolean())
   1.997 +        return false;
   1.998 +
   1.999 +    // IC will leave a BooleanValue in R0, just need to branch on it.
  1.1000 +    masm.branchTestBooleanTruthy(branchIfTrue, R0, labelOf(pc + GET_JUMP_OFFSET(pc)));
  1.1001 +    return true;
  1.1002 +}
  1.1003 +
  1.1004 +bool
  1.1005 +BaselineCompiler::emit_JSOP_IFEQ()
  1.1006 +{
  1.1007 +    return emitTest(false);
  1.1008 +}
  1.1009 +
  1.1010 +bool
  1.1011 +BaselineCompiler::emit_JSOP_IFNE()
  1.1012 +{
  1.1013 +    return emitTest(true);
  1.1014 +}
  1.1015 +
  1.1016 +bool
  1.1017 +BaselineCompiler::emitAndOr(bool branchIfTrue)
  1.1018 +{
  1.1019 +    bool knownBoolean = frame.peek(-1)->isKnownBoolean();
  1.1020 +
  1.1021 +    // AND and OR leave the original value on the stack.
  1.1022 +    frame.syncStack(0);
  1.1023 +
  1.1024 +    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
  1.1025 +    if (!knownBoolean && !emitToBoolean())
  1.1026 +        return false;
  1.1027 +
  1.1028 +    masm.branchTestBooleanTruthy(branchIfTrue, R0, labelOf(pc + GET_JUMP_OFFSET(pc)));
  1.1029 +    return true;
  1.1030 +}
  1.1031 +
  1.1032 +bool
  1.1033 +BaselineCompiler::emit_JSOP_AND()
  1.1034 +{
  1.1035 +    return emitAndOr(false);
  1.1036 +}
  1.1037 +
  1.1038 +bool
  1.1039 +BaselineCompiler::emit_JSOP_OR()
  1.1040 +{
  1.1041 +    return emitAndOr(true);
  1.1042 +}
  1.1043 +
  1.1044 +bool
  1.1045 +BaselineCompiler::emit_JSOP_NOT()
  1.1046 +{
  1.1047 +    bool knownBoolean = frame.peek(-1)->isKnownBoolean();
  1.1048 +
  1.1049 +    // Keep top stack value in R0.
  1.1050 +    frame.popRegsAndSync(1);
  1.1051 +
  1.1052 +    if (!knownBoolean && !emitToBoolean())
  1.1053 +        return false;
  1.1054 +
  1.1055 +    masm.notBoolean(R0);
  1.1056 +
  1.1057 +    frame.push(R0, JSVAL_TYPE_BOOLEAN);
  1.1058 +    return true;
  1.1059 +}
  1.1060 +
  1.1061 +bool
  1.1062 +BaselineCompiler::emit_JSOP_POS()
  1.1063 +{
  1.1064 +    // Keep top stack value in R0.
  1.1065 +    frame.popRegsAndSync(1);
  1.1066 +
  1.1067 +    // Inline path for int32 and double.
  1.1068 +    Label done;
  1.1069 +    masm.branchTestNumber(Assembler::Equal, R0, &done);
  1.1070 +
  1.1071 +    // Call IC.
  1.1072 +    ICToNumber_Fallback::Compiler stubCompiler(cx);
  1.1073 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1074 +        return false;
  1.1075 +
  1.1076 +    masm.bind(&done);
  1.1077 +    frame.push(R0);
  1.1078 +    return true;
  1.1079 +}
  1.1080 +
  1.1081 +bool
  1.1082 +BaselineCompiler::emit_JSOP_LOOPHEAD()
  1.1083 +{
  1.1084 +    return emitInterruptCheck();
  1.1085 +}
  1.1086 +
  1.1087 +bool
  1.1088 +BaselineCompiler::emit_JSOP_LOOPENTRY()
  1.1089 +{
  1.1090 +    frame.syncStack(0);
  1.1091 +    return emitUseCountIncrement(LoopEntryCanIonOsr(pc));
  1.1092 +}
  1.1093 +
  1.1094 +bool
  1.1095 +BaselineCompiler::emit_JSOP_VOID()
  1.1096 +{
  1.1097 +    frame.pop();
  1.1098 +    frame.push(UndefinedValue());
  1.1099 +    return true;
  1.1100 +}
  1.1101 +
  1.1102 +bool
  1.1103 +BaselineCompiler::emit_JSOP_UNDEFINED()
  1.1104 +{
  1.1105 +    frame.push(UndefinedValue());
  1.1106 +    return true;
  1.1107 +}
  1.1108 +
  1.1109 +bool
  1.1110 +BaselineCompiler::emit_JSOP_HOLE()
  1.1111 +{
  1.1112 +    frame.push(MagicValue(JS_ELEMENTS_HOLE));
  1.1113 +    return true;
  1.1114 +}
  1.1115 +
  1.1116 +bool
  1.1117 +BaselineCompiler::emit_JSOP_NULL()
  1.1118 +{
  1.1119 +    frame.push(NullValue());
  1.1120 +    return true;
  1.1121 +}
  1.1122 +
  1.1123 +bool
  1.1124 +BaselineCompiler::emit_JSOP_THIS()
  1.1125 +{
  1.1126 +    if (function() && function()->isArrow()) {
  1.1127 +        // Arrow functions store their (lexical) |this| value in an
  1.1128 +        // extended slot.
  1.1129 +        frame.syncStack(0);
  1.1130 +        Register scratch = R0.scratchReg();
  1.1131 +        masm.loadPtr(frame.addressOfCallee(), scratch);
  1.1132 +        masm.loadValue(Address(scratch, FunctionExtended::offsetOfArrowThisSlot()), R0);
  1.1133 +        frame.push(R0);
  1.1134 +        return true;
  1.1135 +    }
  1.1136 +
  1.1137 +    // Keep this value in R0
  1.1138 +    frame.pushThis();
  1.1139 +
  1.1140 +    // In strict mode code or self-hosted functions, |this| is left alone.
  1.1141 +    if (script->strict() || (function() && function()->isSelfHostedBuiltin()))
  1.1142 +        return true;
  1.1143 +
  1.1144 +    Label skipIC;
  1.1145 +    // Keep |thisv| in R0
  1.1146 +    frame.popRegsAndSync(1);
  1.1147 +    // If |this| is already an object, skip the IC.
  1.1148 +    masm.branchTestObject(Assembler::Equal, R0, &skipIC);
  1.1149 +
  1.1150 +    // Call IC
  1.1151 +    ICThis_Fallback::Compiler stubCompiler(cx);
  1.1152 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1153 +        return false;
  1.1154 +
  1.1155 +    masm.storeValue(R0, frame.addressOfThis());
  1.1156 +
  1.1157 +    // R0 is new pushed |this| value.
  1.1158 +    masm.bind(&skipIC);
  1.1159 +    frame.push(R0);
  1.1160 +
  1.1161 +    return true;
  1.1162 +}
  1.1163 +
  1.1164 +bool
  1.1165 +BaselineCompiler::emit_JSOP_TRUE()
  1.1166 +{
  1.1167 +    frame.push(BooleanValue(true));
  1.1168 +    return true;
  1.1169 +}
  1.1170 +
  1.1171 +bool
  1.1172 +BaselineCompiler::emit_JSOP_FALSE()
  1.1173 +{
  1.1174 +    frame.push(BooleanValue(false));
  1.1175 +    return true;
  1.1176 +}
  1.1177 +
  1.1178 +bool
  1.1179 +BaselineCompiler::emit_JSOP_ZERO()
  1.1180 +{
  1.1181 +    frame.push(Int32Value(0));
  1.1182 +    return true;
  1.1183 +}
  1.1184 +
  1.1185 +bool
  1.1186 +BaselineCompiler::emit_JSOP_ONE()
  1.1187 +{
  1.1188 +    frame.push(Int32Value(1));
  1.1189 +    return true;
  1.1190 +}
  1.1191 +
  1.1192 +bool
  1.1193 +BaselineCompiler::emit_JSOP_INT8()
  1.1194 +{
  1.1195 +    frame.push(Int32Value(GET_INT8(pc)));
  1.1196 +    return true;
  1.1197 +}
  1.1198 +
  1.1199 +bool
  1.1200 +BaselineCompiler::emit_JSOP_INT32()
  1.1201 +{
  1.1202 +    frame.push(Int32Value(GET_INT32(pc)));
  1.1203 +    return true;
  1.1204 +}
  1.1205 +
  1.1206 +bool
  1.1207 +BaselineCompiler::emit_JSOP_UINT16()
  1.1208 +{
  1.1209 +    frame.push(Int32Value(GET_UINT16(pc)));
  1.1210 +    return true;
  1.1211 +}
  1.1212 +
  1.1213 +bool
  1.1214 +BaselineCompiler::emit_JSOP_UINT24()
  1.1215 +{
  1.1216 +    frame.push(Int32Value(GET_UINT24(pc)));
  1.1217 +    return true;
  1.1218 +}
  1.1219 +
  1.1220 +bool
  1.1221 +BaselineCompiler::emit_JSOP_DOUBLE()
  1.1222 +{
  1.1223 +    frame.push(script->getConst(GET_UINT32_INDEX(pc)));
  1.1224 +    return true;
  1.1225 +}
  1.1226 +
  1.1227 +bool
  1.1228 +BaselineCompiler::emit_JSOP_STRING()
  1.1229 +{
  1.1230 +    frame.push(StringValue(script->getAtom(pc)));
  1.1231 +    return true;
  1.1232 +}
  1.1233 +
  1.1234 +typedef JSObject *(*DeepCloneObjectLiteralFn)(JSContext *, HandleObject, NewObjectKind);
  1.1235 +static const VMFunction DeepCloneObjectLiteralInfo =
  1.1236 +    FunctionInfo<DeepCloneObjectLiteralFn>(DeepCloneObjectLiteral);
  1.1237 +
  1.1238 +bool
  1.1239 +BaselineCompiler::emit_JSOP_OBJECT()
  1.1240 +{
  1.1241 +    if (JS::CompartmentOptionsRef(cx).cloneSingletons(cx)) {
  1.1242 +        RootedObject obj(cx, script->getObject(GET_UINT32_INDEX(pc)));
  1.1243 +        if (!obj)
  1.1244 +            return false;
  1.1245 +
  1.1246 +        prepareVMCall();
  1.1247 +
  1.1248 +        pushArg(ImmWord(js::MaybeSingletonObject));
  1.1249 +        pushArg(ImmGCPtr(obj));
  1.1250 +
  1.1251 +        if (!callVM(DeepCloneObjectLiteralInfo))
  1.1252 +            return false;
  1.1253 +
  1.1254 +        // Box and push return value.
  1.1255 +        masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
  1.1256 +        frame.push(R0);
  1.1257 +        return true;
  1.1258 +    }
  1.1259 +
  1.1260 +    JS::CompartmentOptionsRef(cx).setSingletonsAsValues();
  1.1261 +    frame.push(ObjectValue(*script->getObject(pc)));
  1.1262 +    return true;
  1.1263 +}
  1.1264 +
  1.1265 +typedef JSObject *(*CloneRegExpObjectFn)(JSContext *, JSObject *);
  1.1266 +static const VMFunction CloneRegExpObjectInfo =
  1.1267 +    FunctionInfo<CloneRegExpObjectFn>(CloneRegExpObject);
  1.1268 +
  1.1269 +bool
  1.1270 +BaselineCompiler::emit_JSOP_REGEXP()
  1.1271 +{
  1.1272 +    RootedObject reObj(cx, script->getRegExp(pc));
  1.1273 +
  1.1274 +    prepareVMCall();
  1.1275 +    pushArg(ImmGCPtr(reObj));
  1.1276 +    if (!callVM(CloneRegExpObjectInfo))
  1.1277 +        return false;
  1.1278 +
  1.1279 +    // Box and push return value.
  1.1280 +    masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
  1.1281 +    frame.push(R0);
  1.1282 +    return true;
  1.1283 +}
  1.1284 +
  1.1285 +typedef JSObject *(*LambdaFn)(JSContext *, HandleFunction, HandleObject);
  1.1286 +static const VMFunction LambdaInfo = FunctionInfo<LambdaFn>(js::Lambda);
  1.1287 +
  1.1288 +bool
  1.1289 +BaselineCompiler::emit_JSOP_LAMBDA()
  1.1290 +{
  1.1291 +    RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc)));
  1.1292 +
  1.1293 +    prepareVMCall();
  1.1294 +    masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  1.1295 +
  1.1296 +    pushArg(R0.scratchReg());
  1.1297 +    pushArg(ImmGCPtr(fun));
  1.1298 +
  1.1299 +    if (!callVM(LambdaInfo))
  1.1300 +        return false;
  1.1301 +
  1.1302 +    // Box and push return value.
  1.1303 +    masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
  1.1304 +    frame.push(R0);
  1.1305 +    return true;
  1.1306 +}
  1.1307 +
  1.1308 +typedef JSObject *(*LambdaArrowFn)(JSContext *, HandleFunction, HandleObject, HandleValue);
  1.1309 +static const VMFunction LambdaArrowInfo = FunctionInfo<LambdaArrowFn>(js::LambdaArrow);
  1.1310 +
  1.1311 +bool
  1.1312 +BaselineCompiler::emit_JSOP_LAMBDA_ARROW()
  1.1313 +{
  1.1314 +    // Keep pushed |this| in R0.
  1.1315 +    frame.popRegsAndSync(1);
  1.1316 +
  1.1317 +    RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc)));
  1.1318 +
  1.1319 +    prepareVMCall();
  1.1320 +    masm.loadPtr(frame.addressOfScopeChain(), R1.scratchReg());
  1.1321 +
  1.1322 +    pushArg(R0);
  1.1323 +    pushArg(R1.scratchReg());
  1.1324 +    pushArg(ImmGCPtr(fun));
  1.1325 +
  1.1326 +    if (!callVM(LambdaArrowInfo))
  1.1327 +        return false;
  1.1328 +
  1.1329 +    // Box and push return value.
  1.1330 +    masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
  1.1331 +    frame.push(R0);
  1.1332 +    return true;
  1.1333 +}
  1.1334 +
  1.1335 +void
  1.1336 +BaselineCompiler::storeValue(const StackValue *source, const Address &dest,
  1.1337 +                             const ValueOperand &scratch)
  1.1338 +{
  1.1339 +    switch (source->kind()) {
  1.1340 +      case StackValue::Constant:
  1.1341 +        masm.storeValue(source->constant(), dest);
  1.1342 +        break;
  1.1343 +      case StackValue::Register:
  1.1344 +        masm.storeValue(source->reg(), dest);
  1.1345 +        break;
  1.1346 +      case StackValue::LocalSlot:
  1.1347 +        masm.loadValue(frame.addressOfLocal(source->localSlot()), scratch);
  1.1348 +        masm.storeValue(scratch, dest);
  1.1349 +        break;
  1.1350 +      case StackValue::ArgSlot:
  1.1351 +        masm.loadValue(frame.addressOfArg(source->argSlot()), scratch);
  1.1352 +        masm.storeValue(scratch, dest);
  1.1353 +        break;
  1.1354 +      case StackValue::ThisSlot:
  1.1355 +        masm.loadValue(frame.addressOfThis(), scratch);
  1.1356 +        masm.storeValue(scratch, dest);
  1.1357 +        break;
  1.1358 +      case StackValue::Stack:
  1.1359 +        masm.loadValue(frame.addressOfStackValue(source), scratch);
  1.1360 +        masm.storeValue(scratch, dest);
  1.1361 +        break;
  1.1362 +      default:
  1.1363 +        MOZ_ASSUME_UNREACHABLE("Invalid kind");
  1.1364 +    }
  1.1365 +}
  1.1366 +
  1.1367 +bool
  1.1368 +BaselineCompiler::emit_JSOP_BITOR()
  1.1369 +{
  1.1370 +    return emitBinaryArith();
  1.1371 +}
  1.1372 +
  1.1373 +bool
  1.1374 +BaselineCompiler::emit_JSOP_BITXOR()
  1.1375 +{
  1.1376 +    return emitBinaryArith();
  1.1377 +}
  1.1378 +
  1.1379 +bool
  1.1380 +BaselineCompiler::emit_JSOP_BITAND()
  1.1381 +{
  1.1382 +    return emitBinaryArith();
  1.1383 +}
  1.1384 +
  1.1385 +bool
  1.1386 +BaselineCompiler::emit_JSOP_LSH()
  1.1387 +{
  1.1388 +    return emitBinaryArith();
  1.1389 +}
  1.1390 +
  1.1391 +bool
  1.1392 +BaselineCompiler::emit_JSOP_RSH()
  1.1393 +{
  1.1394 +    return emitBinaryArith();
  1.1395 +}
  1.1396 +
  1.1397 +bool
  1.1398 +BaselineCompiler::emit_JSOP_URSH()
  1.1399 +{
  1.1400 +    return emitBinaryArith();
  1.1401 +}
  1.1402 +
  1.1403 +bool
  1.1404 +BaselineCompiler::emit_JSOP_ADD()
  1.1405 +{
  1.1406 +    return emitBinaryArith();
  1.1407 +}
  1.1408 +
  1.1409 +bool
  1.1410 +BaselineCompiler::emit_JSOP_SUB()
  1.1411 +{
  1.1412 +    return emitBinaryArith();
  1.1413 +}
  1.1414 +
  1.1415 +bool
  1.1416 +BaselineCompiler::emit_JSOP_MUL()
  1.1417 +{
  1.1418 +    return emitBinaryArith();
  1.1419 +}
  1.1420 +
  1.1421 +bool
  1.1422 +BaselineCompiler::emit_JSOP_DIV()
  1.1423 +{
  1.1424 +    return emitBinaryArith();
  1.1425 +}
  1.1426 +
  1.1427 +bool
  1.1428 +BaselineCompiler::emit_JSOP_MOD()
  1.1429 +{
  1.1430 +    return emitBinaryArith();
  1.1431 +}
  1.1432 +
  1.1433 +bool
  1.1434 +BaselineCompiler::emitBinaryArith()
  1.1435 +{
  1.1436 +    // Keep top JSStack value in R0 and R2
  1.1437 +    frame.popRegsAndSync(2);
  1.1438 +
  1.1439 +    // Call IC
  1.1440 +    ICBinaryArith_Fallback::Compiler stubCompiler(cx);
  1.1441 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1442 +        return false;
  1.1443 +
  1.1444 +    // Mark R0 as pushed stack value.
  1.1445 +    frame.push(R0);
  1.1446 +    return true;
  1.1447 +}
  1.1448 +
  1.1449 +bool
  1.1450 +BaselineCompiler::emitUnaryArith()
  1.1451 +{
  1.1452 +    // Keep top stack value in R0.
  1.1453 +    frame.popRegsAndSync(1);
  1.1454 +
  1.1455 +    // Call IC
  1.1456 +    ICUnaryArith_Fallback::Compiler stubCompiler(cx);
  1.1457 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1458 +        return false;
  1.1459 +
  1.1460 +    // Mark R0 as pushed stack value.
  1.1461 +    frame.push(R0);
  1.1462 +    return true;
  1.1463 +}
  1.1464 +
  1.1465 +bool
  1.1466 +BaselineCompiler::emit_JSOP_BITNOT()
  1.1467 +{
  1.1468 +    return emitUnaryArith();
  1.1469 +}
  1.1470 +
  1.1471 +bool
  1.1472 +BaselineCompiler::emit_JSOP_NEG()
  1.1473 +{
  1.1474 +    return emitUnaryArith();
  1.1475 +}
  1.1476 +
  1.1477 +bool
  1.1478 +BaselineCompiler::emit_JSOP_LT()
  1.1479 +{
  1.1480 +    return emitCompare();
  1.1481 +}
  1.1482 +
  1.1483 +bool
  1.1484 +BaselineCompiler::emit_JSOP_LE()
  1.1485 +{
  1.1486 +    return emitCompare();
  1.1487 +}
  1.1488 +
  1.1489 +bool
  1.1490 +BaselineCompiler::emit_JSOP_GT()
  1.1491 +{
  1.1492 +    return emitCompare();
  1.1493 +}
  1.1494 +
  1.1495 +bool
  1.1496 +BaselineCompiler::emit_JSOP_GE()
  1.1497 +{
  1.1498 +    return emitCompare();
  1.1499 +}
  1.1500 +
  1.1501 +bool
  1.1502 +BaselineCompiler::emit_JSOP_EQ()
  1.1503 +{
  1.1504 +    return emitCompare();
  1.1505 +}
  1.1506 +
  1.1507 +bool
  1.1508 +BaselineCompiler::emit_JSOP_NE()
  1.1509 +{
  1.1510 +    return emitCompare();
  1.1511 +}
  1.1512 +
  1.1513 +bool
  1.1514 +BaselineCompiler::emitCompare()
  1.1515 +{
  1.1516 +    // CODEGEN
  1.1517 +
  1.1518 +    // Keep top JSStack value in R0 and R1.
  1.1519 +    frame.popRegsAndSync(2);
  1.1520 +
  1.1521 +    // Call IC.
  1.1522 +    ICCompare_Fallback::Compiler stubCompiler(cx);
  1.1523 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1524 +        return false;
  1.1525 +
  1.1526 +    // Mark R0 as pushed stack value.
  1.1527 +    frame.push(R0, JSVAL_TYPE_BOOLEAN);
  1.1528 +    return true;
  1.1529 +}
  1.1530 +
  1.1531 +bool
  1.1532 +BaselineCompiler::emit_JSOP_STRICTEQ()
  1.1533 +{
  1.1534 +    return emitCompare();
  1.1535 +}
  1.1536 +
  1.1537 +bool
  1.1538 +BaselineCompiler::emit_JSOP_STRICTNE()
  1.1539 +{
  1.1540 +    return emitCompare();
  1.1541 +}
  1.1542 +
  1.1543 +bool
  1.1544 +BaselineCompiler::emit_JSOP_CONDSWITCH()
  1.1545 +{
  1.1546 +    return true;
  1.1547 +}
  1.1548 +
  1.1549 +bool
  1.1550 +BaselineCompiler::emit_JSOP_CASE()
  1.1551 +{
  1.1552 +    frame.popRegsAndSync(2);
  1.1553 +    frame.push(R0);
  1.1554 +    frame.syncStack(0);
  1.1555 +
  1.1556 +    // Call IC.
  1.1557 +    ICCompare_Fallback::Compiler stubCompiler(cx);
  1.1558 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1559 +        return false;
  1.1560 +
  1.1561 +    Register payload = masm.extractInt32(R0, R0.scratchReg());
  1.1562 +    jsbytecode *target = pc + GET_JUMP_OFFSET(pc);
  1.1563 +
  1.1564 +    Label done;
  1.1565 +    masm.branch32(Assembler::Equal, payload, Imm32(0), &done);
  1.1566 +    {
  1.1567 +        // Pop the switch value if the case matches.
  1.1568 +        masm.addPtr(Imm32(sizeof(Value)), StackPointer);
  1.1569 +        masm.jump(labelOf(target));
  1.1570 +    }
  1.1571 +    masm.bind(&done);
  1.1572 +    return true;
  1.1573 +}
  1.1574 +
  1.1575 +bool
  1.1576 +BaselineCompiler::emit_JSOP_DEFAULT()
  1.1577 +{
  1.1578 +    frame.pop();
  1.1579 +    return emit_JSOP_GOTO();
  1.1580 +}
  1.1581 +
  1.1582 +bool
  1.1583 +BaselineCompiler::emit_JSOP_LINENO()
  1.1584 +{
  1.1585 +    return true;
  1.1586 +}
  1.1587 +
  1.1588 +bool
  1.1589 +BaselineCompiler::emit_JSOP_NEWARRAY()
  1.1590 +{
  1.1591 +    frame.syncStack(0);
  1.1592 +
  1.1593 +    uint32_t length = GET_UINT24(pc);
  1.1594 +    RootedTypeObject type(cx);
  1.1595 +    if (!types::UseNewTypeForInitializer(script, pc, JSProto_Array)) {
  1.1596 +        type = types::TypeScript::InitObject(cx, script, pc, JSProto_Array);
  1.1597 +        if (!type)
  1.1598 +            return false;
  1.1599 +    }
  1.1600 +
  1.1601 +    // Pass length in R0, type in R1.
  1.1602 +    masm.move32(Imm32(length), R0.scratchReg());
  1.1603 +    masm.movePtr(ImmGCPtr(type), R1.scratchReg());
  1.1604 +
  1.1605 +    JSObject *templateObject = NewDenseUnallocatedArray(cx, length, nullptr, TenuredObject);
  1.1606 +    if (!templateObject)
  1.1607 +        return false;
  1.1608 +    templateObject->setType(type);
  1.1609 +
  1.1610 +    ICNewArray_Fallback::Compiler stubCompiler(cx, templateObject);
  1.1611 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1612 +        return false;
  1.1613 +
  1.1614 +    frame.push(R0);
  1.1615 +    return true;
  1.1616 +}
  1.1617 +
  1.1618 +bool
  1.1619 +BaselineCompiler::emit_JSOP_INITELEM_ARRAY()
  1.1620 +{
  1.1621 +    // Keep the object and rhs on the stack.
  1.1622 +    frame.syncStack(0);
  1.1623 +
  1.1624 +    // Load object in R0, index in R1.
  1.1625 +    masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
  1.1626 +    masm.moveValue(Int32Value(GET_UINT24(pc)), R1);
  1.1627 +
  1.1628 +    // Call IC.
  1.1629 +    ICSetElem_Fallback::Compiler stubCompiler(cx);
  1.1630 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1631 +        return false;
  1.1632 +
  1.1633 +    // Pop the rhs, so that the object is on the top of the stack.
  1.1634 +    frame.pop();
  1.1635 +    return true;
  1.1636 +}
  1.1637 +
  1.1638 +bool
  1.1639 +BaselineCompiler::emit_JSOP_NEWOBJECT()
  1.1640 +{
  1.1641 +    frame.syncStack(0);
  1.1642 +
  1.1643 +    RootedTypeObject type(cx);
  1.1644 +    if (!types::UseNewTypeForInitializer(script, pc, JSProto_Object)) {
  1.1645 +        type = types::TypeScript::InitObject(cx, script, pc, JSProto_Object);
  1.1646 +        if (!type)
  1.1647 +            return false;
  1.1648 +    }
  1.1649 +
  1.1650 +    RootedObject baseObject(cx, script->getObject(pc));
  1.1651 +    RootedObject templateObject(cx, CopyInitializerObject(cx, baseObject, TenuredObject));
  1.1652 +    if (!templateObject)
  1.1653 +        return false;
  1.1654 +
  1.1655 +    if (type) {
  1.1656 +        templateObject->setType(type);
  1.1657 +    } else {
  1.1658 +        if (!JSObject::setSingletonType(cx, templateObject))
  1.1659 +            return false;
  1.1660 +    }
  1.1661 +
  1.1662 +    ICNewObject_Fallback::Compiler stubCompiler(cx, templateObject);
  1.1663 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1664 +        return false;
  1.1665 +
  1.1666 +    frame.push(R0);
  1.1667 +    return true;
  1.1668 +}
  1.1669 +
  1.1670 +bool
  1.1671 +BaselineCompiler::emit_JSOP_NEWINIT()
  1.1672 +{
  1.1673 +    frame.syncStack(0);
  1.1674 +    JSProtoKey key = JSProtoKey(GET_UINT8(pc));
  1.1675 +
  1.1676 +    RootedTypeObject type(cx);
  1.1677 +    if (!types::UseNewTypeForInitializer(script, pc, key)) {
  1.1678 +        type = types::TypeScript::InitObject(cx, script, pc, key);
  1.1679 +        if (!type)
  1.1680 +            return false;
  1.1681 +    }
  1.1682 +
  1.1683 +    if (key == JSProto_Array) {
  1.1684 +        // Pass length in R0, type in R1.
  1.1685 +        masm.move32(Imm32(0), R0.scratchReg());
  1.1686 +        masm.movePtr(ImmGCPtr(type), R1.scratchReg());
  1.1687 +
  1.1688 +        JSObject *templateObject = NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject);
  1.1689 +        if (!templateObject)
  1.1690 +            return false;
  1.1691 +        templateObject->setType(type);
  1.1692 +
  1.1693 +        ICNewArray_Fallback::Compiler stubCompiler(cx, templateObject);
  1.1694 +        if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1695 +            return false;
  1.1696 +    } else {
  1.1697 +        JS_ASSERT(key == JSProto_Object);
  1.1698 +
  1.1699 +        RootedObject templateObject(cx);
  1.1700 +        templateObject = NewBuiltinClassInstance(cx, &JSObject::class_, TenuredObject);
  1.1701 +        if (!templateObject)
  1.1702 +            return false;
  1.1703 +
  1.1704 +        if (type) {
  1.1705 +            templateObject->setType(type);
  1.1706 +        } else {
  1.1707 +            if (!JSObject::setSingletonType(cx, templateObject))
  1.1708 +                return false;
  1.1709 +        }
  1.1710 +
  1.1711 +        ICNewObject_Fallback::Compiler stubCompiler(cx, templateObject);
  1.1712 +        if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1713 +            return false;
  1.1714 +    }
  1.1715 +
  1.1716 +    frame.push(R0);
  1.1717 +    return true;
  1.1718 +}
  1.1719 +
  1.1720 +bool
  1.1721 +BaselineCompiler::emit_JSOP_INITELEM()
  1.1722 +{
  1.1723 +    // Store RHS in the scratch slot.
  1.1724 +    storeValue(frame.peek(-1), frame.addressOfScratchValue(), R2);
  1.1725 +    frame.pop();
  1.1726 +
  1.1727 +    // Keep object and index in R0 and R1.
  1.1728 +    frame.popRegsAndSync(2);
  1.1729 +
  1.1730 +    // Push the object to store the result of the IC.
  1.1731 +    frame.push(R0);
  1.1732 +    frame.syncStack(0);
  1.1733 +
  1.1734 +    // Keep RHS on the stack.
  1.1735 +    frame.pushScratchValue();
  1.1736 +
  1.1737 +    // Call IC.
  1.1738 +    ICSetElem_Fallback::Compiler stubCompiler(cx);
  1.1739 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1740 +        return false;
  1.1741 +
  1.1742 +    // Pop the rhs, so that the object is on the top of the stack.
  1.1743 +    frame.pop();
  1.1744 +    return true;
  1.1745 +}
  1.1746 +
  1.1747 +typedef bool (*MutateProtoFn)(JSContext *cx, HandleObject obj, HandleValue newProto);
  1.1748 +static const VMFunction MutateProtoInfo = FunctionInfo<MutateProtoFn>(MutatePrototype);
  1.1749 +
  1.1750 +bool
  1.1751 +BaselineCompiler::emit_JSOP_MUTATEPROTO()
  1.1752 +{
  1.1753 +    // Keep values on the stack for the decompiler.
  1.1754 +    frame.syncStack(0);
  1.1755 +
  1.1756 +    masm.extractObject(frame.addressOfStackValue(frame.peek(-2)), R0.scratchReg());
  1.1757 +    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
  1.1758 +
  1.1759 +    prepareVMCall();
  1.1760 +
  1.1761 +    pushArg(R1);
  1.1762 +    pushArg(R0.scratchReg());
  1.1763 +
  1.1764 +    if (!callVM(MutateProtoInfo))
  1.1765 +        return false;
  1.1766 +
  1.1767 +    frame.pop();
  1.1768 +    return true;
  1.1769 +}
  1.1770 +
  1.1771 +bool
  1.1772 +BaselineCompiler::emit_JSOP_INITPROP()
  1.1773 +{
  1.1774 +    // Keep lhs in R0, rhs in R1.
  1.1775 +    frame.popRegsAndSync(2);
  1.1776 +
  1.1777 +    // Push the object to store the result of the IC.
  1.1778 +    frame.push(R0);
  1.1779 +    frame.syncStack(0);
  1.1780 +
  1.1781 +    // Call IC.
  1.1782 +    ICSetProp_Fallback::Compiler compiler(cx);
  1.1783 +    return emitOpIC(compiler.getStub(&stubSpace_));
  1.1784 +}
  1.1785 +
  1.1786 +bool
  1.1787 +BaselineCompiler::emit_JSOP_ENDINIT()
  1.1788 +{
  1.1789 +    return true;
  1.1790 +}
  1.1791 +
  1.1792 +typedef bool (*NewbornArrayPushFn)(JSContext *, HandleObject, const Value &);
  1.1793 +static const VMFunction NewbornArrayPushInfo = FunctionInfo<NewbornArrayPushFn>(NewbornArrayPush);
  1.1794 +
  1.1795 +bool
  1.1796 +BaselineCompiler::emit_JSOP_ARRAYPUSH()
  1.1797 +{
  1.1798 +    // Keep value in R0, object in R1.
  1.1799 +    frame.popRegsAndSync(2);
  1.1800 +    masm.unboxObject(R1, R1.scratchReg());
  1.1801 +
  1.1802 +    prepareVMCall();
  1.1803 +
  1.1804 +    pushArg(R0);
  1.1805 +    pushArg(R1.scratchReg());
  1.1806 +
  1.1807 +    return callVM(NewbornArrayPushInfo);
  1.1808 +}
  1.1809 +
  1.1810 +bool
  1.1811 +BaselineCompiler::emit_JSOP_GETELEM()
  1.1812 +{
  1.1813 +    // Keep top two stack values in R0 and R1.
  1.1814 +    frame.popRegsAndSync(2);
  1.1815 +
  1.1816 +    // Call IC.
  1.1817 +    ICGetElem_Fallback::Compiler stubCompiler(cx);
  1.1818 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1819 +        return false;
  1.1820 +
  1.1821 +    // Mark R0 as pushed stack value.
  1.1822 +    frame.push(R0);
  1.1823 +    return true;
  1.1824 +}
  1.1825 +
  1.1826 +bool
  1.1827 +BaselineCompiler::emit_JSOP_CALLELEM()
  1.1828 +{
  1.1829 +    return emit_JSOP_GETELEM();
  1.1830 +}
  1.1831 +
  1.1832 +bool
  1.1833 +BaselineCompiler::emit_JSOP_SETELEM()
  1.1834 +{
  1.1835 +    // Store RHS in the scratch slot.
  1.1836 +    storeValue(frame.peek(-1), frame.addressOfScratchValue(), R2);
  1.1837 +    frame.pop();
  1.1838 +
  1.1839 +    // Keep object and index in R0 and R1.
  1.1840 +    frame.popRegsAndSync(2);
  1.1841 +
  1.1842 +    // Keep RHS on the stack.
  1.1843 +    frame.pushScratchValue();
  1.1844 +
  1.1845 +    // Call IC.
  1.1846 +    ICSetElem_Fallback::Compiler stubCompiler(cx);
  1.1847 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1848 +        return false;
  1.1849 +
  1.1850 +    return true;
  1.1851 +}
  1.1852 +
  1.1853 +typedef bool (*DeleteElementFn)(JSContext *, HandleValue, HandleValue, bool *);
  1.1854 +static const VMFunction DeleteElementStrictInfo = FunctionInfo<DeleteElementFn>(DeleteElement<true>);
  1.1855 +static const VMFunction DeleteElementNonStrictInfo = FunctionInfo<DeleteElementFn>(DeleteElement<false>);
  1.1856 +
  1.1857 +bool
  1.1858 +BaselineCompiler::emit_JSOP_DELELEM()
  1.1859 +{
  1.1860 +    // Keep values on the stack for the decompiler.
  1.1861 +    frame.syncStack(0);
  1.1862 +    masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
  1.1863 +    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
  1.1864 +
  1.1865 +    prepareVMCall();
  1.1866 +
  1.1867 +    pushArg(R1);
  1.1868 +    pushArg(R0);
  1.1869 +
  1.1870 +    if (!callVM(script->strict() ? DeleteElementStrictInfo : DeleteElementNonStrictInfo))
  1.1871 +        return false;
  1.1872 +
  1.1873 +    masm.boxNonDouble(JSVAL_TYPE_BOOLEAN, ReturnReg, R1);
  1.1874 +    frame.popn(2);
  1.1875 +    frame.push(R1);
  1.1876 +    return true;
  1.1877 +}
  1.1878 +
  1.1879 +bool
  1.1880 +BaselineCompiler::emit_JSOP_IN()
  1.1881 +{
  1.1882 +    frame.popRegsAndSync(2);
  1.1883 +
  1.1884 +    ICIn_Fallback::Compiler stubCompiler(cx);
  1.1885 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1886 +        return false;
  1.1887 +
  1.1888 +    frame.push(R0);
  1.1889 +    return true;
  1.1890 +}
  1.1891 +
  1.1892 +bool
  1.1893 +BaselineCompiler::emit_JSOP_GETGNAME()
  1.1894 +{
  1.1895 +    RootedPropertyName name(cx, script->getName(pc));
  1.1896 +
  1.1897 +    if (name == cx->names().undefined) {
  1.1898 +        frame.push(UndefinedValue());
  1.1899 +        return true;
  1.1900 +    }
  1.1901 +    if (name == cx->names().NaN) {
  1.1902 +        frame.push(cx->runtime()->NaNValue);
  1.1903 +        return true;
  1.1904 +    }
  1.1905 +    if (name == cx->names().Infinity) {
  1.1906 +        frame.push(cx->runtime()->positiveInfinityValue);
  1.1907 +        return true;
  1.1908 +    }
  1.1909 +
  1.1910 +    frame.syncStack(0);
  1.1911 +
  1.1912 +    masm.movePtr(ImmGCPtr(&script->global()), R0.scratchReg());
  1.1913 +
  1.1914 +    // Call IC.
  1.1915 +    ICGetName_Fallback::Compiler stubCompiler(cx);
  1.1916 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.1917 +        return false;
  1.1918 +
  1.1919 +    // Mark R0 as pushed stack value.
  1.1920 +    frame.push(R0);
  1.1921 +    return true;
  1.1922 +}
  1.1923 +
  1.1924 +bool
  1.1925 +BaselineCompiler::emit_JSOP_BINDGNAME()
  1.1926 +{
  1.1927 +    frame.push(ObjectValue(script->global()));
  1.1928 +    return true;
  1.1929 +}
  1.1930 +
  1.1931 +bool
  1.1932 +BaselineCompiler::emit_JSOP_SETPROP()
  1.1933 +{
  1.1934 +    // Keep lhs in R0, rhs in R1.
  1.1935 +    frame.popRegsAndSync(2);
  1.1936 +
  1.1937 +    // Call IC.
  1.1938 +    ICSetProp_Fallback::Compiler compiler(cx);
  1.1939 +    if (!emitOpIC(compiler.getStub(&stubSpace_)))
  1.1940 +        return false;
  1.1941 +
  1.1942 +    // The IC will return the RHS value in R0, mark it as pushed value.
  1.1943 +    frame.push(R0);
  1.1944 +    return true;
  1.1945 +}
  1.1946 +
  1.1947 +bool
  1.1948 +BaselineCompiler::emit_JSOP_SETNAME()
  1.1949 +{
  1.1950 +    return emit_JSOP_SETPROP();
  1.1951 +}
  1.1952 +
  1.1953 +bool
  1.1954 +BaselineCompiler::emit_JSOP_SETGNAME()
  1.1955 +{
  1.1956 +    return emit_JSOP_SETPROP();
  1.1957 +}
  1.1958 +
  1.1959 +bool
  1.1960 +BaselineCompiler::emit_JSOP_GETPROP()
  1.1961 +{
  1.1962 +    // Keep object in R0.
  1.1963 +    frame.popRegsAndSync(1);
  1.1964 +
  1.1965 +    // Call IC.
  1.1966 +    ICGetProp_Fallback::Compiler compiler(cx);
  1.1967 +    if (!emitOpIC(compiler.getStub(&stubSpace_)))
  1.1968 +        return false;
  1.1969 +
  1.1970 +    // Mark R0 as pushed stack value.
  1.1971 +    frame.push(R0);
  1.1972 +    return true;
  1.1973 +}
  1.1974 +
  1.1975 +bool
  1.1976 +BaselineCompiler::emit_JSOP_CALLPROP()
  1.1977 +{
  1.1978 +    return emit_JSOP_GETPROP();
  1.1979 +}
  1.1980 +
  1.1981 +bool
  1.1982 +BaselineCompiler::emit_JSOP_LENGTH()
  1.1983 +{
  1.1984 +    return emit_JSOP_GETPROP();
  1.1985 +}
  1.1986 +
  1.1987 +bool
  1.1988 +BaselineCompiler::emit_JSOP_GETXPROP()
  1.1989 +{
  1.1990 +    return emit_JSOP_GETPROP();
  1.1991 +}
  1.1992 +
  1.1993 +typedef bool (*DeletePropertyFn)(JSContext *, HandleValue, HandlePropertyName, bool *);
  1.1994 +static const VMFunction DeletePropertyStrictInfo = FunctionInfo<DeletePropertyFn>(DeleteProperty<true>);
  1.1995 +static const VMFunction DeletePropertyNonStrictInfo = FunctionInfo<DeletePropertyFn>(DeleteProperty<false>);
  1.1996 +
  1.1997 +bool
  1.1998 +BaselineCompiler::emit_JSOP_DELPROP()
  1.1999 +{
  1.2000 +    // Keep value on the stack for the decompiler.
  1.2001 +    frame.syncStack(0);
  1.2002 +    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
  1.2003 +
  1.2004 +    prepareVMCall();
  1.2005 +
  1.2006 +    pushArg(ImmGCPtr(script->getName(pc)));
  1.2007 +    pushArg(R0);
  1.2008 +
  1.2009 +    if (!callVM(script->strict() ? DeletePropertyStrictInfo : DeletePropertyNonStrictInfo))
  1.2010 +        return false;
  1.2011 +
  1.2012 +    masm.boxNonDouble(JSVAL_TYPE_BOOLEAN, ReturnReg, R1);
  1.2013 +    frame.pop();
  1.2014 +    frame.push(R1);
  1.2015 +    return true;
  1.2016 +}
  1.2017 +
  1.2018 +void
  1.2019 +BaselineCompiler::getScopeCoordinateObject(Register reg)
  1.2020 +{
  1.2021 +    ScopeCoordinate sc(pc);
  1.2022 +
  1.2023 +    masm.loadPtr(frame.addressOfScopeChain(), reg);
  1.2024 +    for (unsigned i = sc.hops(); i; i--)
  1.2025 +        masm.extractObject(Address(reg, ScopeObject::offsetOfEnclosingScope()), reg);
  1.2026 +}
  1.2027 +
  1.2028 +Address
  1.2029 +BaselineCompiler::getScopeCoordinateAddressFromObject(Register objReg, Register reg)
  1.2030 +{
  1.2031 +    ScopeCoordinate sc(pc);
  1.2032 +    Shape *shape = ScopeCoordinateToStaticScopeShape(script, pc);
  1.2033 +
  1.2034 +    Address addr;
  1.2035 +    if (shape->numFixedSlots() <= sc.slot()) {
  1.2036 +        masm.loadPtr(Address(objReg, JSObject::offsetOfSlots()), reg);
  1.2037 +        return Address(reg, (sc.slot() - shape->numFixedSlots()) * sizeof(Value));
  1.2038 +    }
  1.2039 +
  1.2040 +    return Address(objReg, JSObject::getFixedSlotOffset(sc.slot()));
  1.2041 +}
  1.2042 +
  1.2043 +Address
  1.2044 +BaselineCompiler::getScopeCoordinateAddress(Register reg)
  1.2045 +{
  1.2046 +    getScopeCoordinateObject(reg);
  1.2047 +    return getScopeCoordinateAddressFromObject(reg, reg);
  1.2048 +}
  1.2049 +
  1.2050 +bool
  1.2051 +BaselineCompiler::emit_JSOP_GETALIASEDVAR()
  1.2052 +{
  1.2053 +    frame.syncStack(0);
  1.2054 +
  1.2055 +    Address address = getScopeCoordinateAddress(R0.scratchReg());
  1.2056 +    masm.loadValue(address, R0);
  1.2057 +
  1.2058 +    ICTypeMonitor_Fallback::Compiler compiler(cx, (ICMonitoredFallbackStub *) nullptr);
  1.2059 +    if (!emitOpIC(compiler.getStub(&stubSpace_)))
  1.2060 +        return false;
  1.2061 +
  1.2062 +    frame.push(R0);
  1.2063 +    return true;
  1.2064 +}
  1.2065 +
  1.2066 +bool
  1.2067 +BaselineCompiler::emit_JSOP_SETALIASEDVAR()
  1.2068 +{
  1.2069 +    JSScript *outerScript = ScopeCoordinateFunctionScript(script, pc);
  1.2070 +    if (outerScript && outerScript->treatAsRunOnce()) {
  1.2071 +        // Type updates for this operation might need to be tracked, so treat
  1.2072 +        // this as a SETPROP.
  1.2073 +
  1.2074 +        // Load rhs into R1.
  1.2075 +        frame.syncStack(1);
  1.2076 +        frame.popValue(R1);
  1.2077 +
  1.2078 +        // Load and box lhs into R0.
  1.2079 +        getScopeCoordinateObject(R2.scratchReg());
  1.2080 +        masm.tagValue(JSVAL_TYPE_OBJECT, R2.scratchReg(), R0);
  1.2081 +
  1.2082 +        // Call SETPROP IC.
  1.2083 +        ICSetProp_Fallback::Compiler compiler(cx);
  1.2084 +        if (!emitOpIC(compiler.getStub(&stubSpace_)))
  1.2085 +            return false;
  1.2086 +
  1.2087 +        // The IC will return the RHS value in R0, mark it as pushed value.
  1.2088 +        frame.push(R0);
  1.2089 +        return true;
  1.2090 +    }
  1.2091 +
  1.2092 +    // Keep rvalue in R0.
  1.2093 +    frame.popRegsAndSync(1);
  1.2094 +    Register objReg = R2.scratchReg();
  1.2095 +
  1.2096 +    getScopeCoordinateObject(objReg);
  1.2097 +    Address address = getScopeCoordinateAddressFromObject(objReg, R1.scratchReg());
  1.2098 +    masm.patchableCallPreBarrier(address, MIRType_Value);
  1.2099 +    masm.storeValue(R0, address);
  1.2100 +    frame.push(R0);
  1.2101 +
  1.2102 +#ifdef JSGC_GENERATIONAL
  1.2103 +    // Fully sync the stack if post-barrier is needed.
  1.2104 +    // Scope coordinate object is already in R2.scratchReg().
  1.2105 +    frame.syncStack(0);
  1.2106 +    Register temp = R1.scratchReg();
  1.2107 +
  1.2108 +    Label skipBarrier;
  1.2109 +    masm.branchTestObject(Assembler::NotEqual, R0, &skipBarrier);
  1.2110 +    masm.branchPtrInNurseryRange(objReg, temp, &skipBarrier);
  1.2111 +
  1.2112 +    masm.call(&postBarrierSlot_);
  1.2113 +
  1.2114 +    masm.bind(&skipBarrier);
  1.2115 +#endif
  1.2116 +
  1.2117 +    return true;
  1.2118 +}
  1.2119 +
  1.2120 +bool
  1.2121 +BaselineCompiler::emit_JSOP_NAME()
  1.2122 +{
  1.2123 +    frame.syncStack(0);
  1.2124 +
  1.2125 +    masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  1.2126 +
  1.2127 +    // Call IC.
  1.2128 +    ICGetName_Fallback::Compiler stubCompiler(cx);
  1.2129 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.2130 +        return false;
  1.2131 +
  1.2132 +    // Mark R0 as pushed stack value.
  1.2133 +    frame.push(R0);
  1.2134 +    return true;
  1.2135 +}
  1.2136 +
  1.2137 +bool
  1.2138 +BaselineCompiler::emit_JSOP_BINDNAME()
  1.2139 +{
  1.2140 +    frame.syncStack(0);
  1.2141 +
  1.2142 +    masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  1.2143 +
  1.2144 +    // Call IC.
  1.2145 +    ICBindName_Fallback::Compiler stubCompiler(cx);
  1.2146 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.2147 +        return false;
  1.2148 +
  1.2149 +    // Mark R0 as pushed stack value.
  1.2150 +    frame.push(R0);
  1.2151 +    return true;
  1.2152 +}
  1.2153 +
  1.2154 +typedef bool (*DeleteNameFn)(JSContext *, HandlePropertyName, HandleObject,
  1.2155 +                             MutableHandleValue);
  1.2156 +static const VMFunction DeleteNameInfo = FunctionInfo<DeleteNameFn>(DeleteNameOperation);
  1.2157 +
  1.2158 +bool
  1.2159 +BaselineCompiler::emit_JSOP_DELNAME()
  1.2160 +{
  1.2161 +    frame.syncStack(0);
  1.2162 +    masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  1.2163 +
  1.2164 +    prepareVMCall();
  1.2165 +
  1.2166 +    pushArg(R0.scratchReg());
  1.2167 +    pushArg(ImmGCPtr(script->getName(pc)));
  1.2168 +
  1.2169 +    if (!callVM(DeleteNameInfo))
  1.2170 +        return false;
  1.2171 +
  1.2172 +    frame.push(R0);
  1.2173 +    return true;
  1.2174 +}
  1.2175 +
  1.2176 +bool
  1.2177 +BaselineCompiler::emit_JSOP_GETINTRINSIC()
  1.2178 +{
  1.2179 +    frame.syncStack(0);
  1.2180 +
  1.2181 +    ICGetIntrinsic_Fallback::Compiler stubCompiler(cx);
  1.2182 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.2183 +        return false;
  1.2184 +
  1.2185 +    frame.push(R0);
  1.2186 +    return true;
  1.2187 +}
  1.2188 +
  1.2189 +typedef bool (*DefVarOrConstFn)(JSContext *, HandlePropertyName, unsigned, HandleObject);
  1.2190 +static const VMFunction DefVarOrConstInfo = FunctionInfo<DefVarOrConstFn>(DefVarOrConst);
  1.2191 +
  1.2192 +bool
  1.2193 +BaselineCompiler::emit_JSOP_DEFVAR()
  1.2194 +{
  1.2195 +    frame.syncStack(0);
  1.2196 +
  1.2197 +    unsigned attrs = JSPROP_ENUMERATE;
  1.2198 +    if (!script->isForEval())
  1.2199 +        attrs |= JSPROP_PERMANENT;
  1.2200 +    if (JSOp(*pc) == JSOP_DEFCONST)
  1.2201 +        attrs |= JSPROP_READONLY;
  1.2202 +    JS_ASSERT(attrs <= UINT32_MAX);
  1.2203 +
  1.2204 +    masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  1.2205 +
  1.2206 +    prepareVMCall();
  1.2207 +
  1.2208 +    pushArg(R0.scratchReg());
  1.2209 +    pushArg(Imm32(attrs));
  1.2210 +    pushArg(ImmGCPtr(script->getName(pc)));
  1.2211 +
  1.2212 +    return callVM(DefVarOrConstInfo);
  1.2213 +}
  1.2214 +
  1.2215 +bool
  1.2216 +BaselineCompiler::emit_JSOP_DEFCONST()
  1.2217 +{
  1.2218 +    return emit_JSOP_DEFVAR();
  1.2219 +}
  1.2220 +
  1.2221 +typedef bool (*SetConstFn)(JSContext *, HandlePropertyName, HandleObject, HandleValue);
  1.2222 +static const VMFunction SetConstInfo = FunctionInfo<SetConstFn>(SetConst);
  1.2223 +
  1.2224 +bool
  1.2225 +BaselineCompiler::emit_JSOP_SETCONST()
  1.2226 +{
  1.2227 +    frame.popRegsAndSync(1);
  1.2228 +    frame.push(R0);
  1.2229 +    frame.syncStack(0);
  1.2230 +
  1.2231 +    masm.loadPtr(frame.addressOfScopeChain(), R1.scratchReg());
  1.2232 +
  1.2233 +    prepareVMCall();
  1.2234 +
  1.2235 +    pushArg(R0);
  1.2236 +    pushArg(R1.scratchReg());
  1.2237 +    pushArg(ImmGCPtr(script->getName(pc)));
  1.2238 +
  1.2239 +    return callVM(SetConstInfo);
  1.2240 +}
  1.2241 +
  1.2242 +typedef bool (*DefFunOperationFn)(JSContext *, HandleScript, HandleObject, HandleFunction);
  1.2243 +static const VMFunction DefFunOperationInfo = FunctionInfo<DefFunOperationFn>(DefFunOperation);
  1.2244 +
  1.2245 +bool
  1.2246 +BaselineCompiler::emit_JSOP_DEFFUN()
  1.2247 +{
  1.2248 +    RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc)));
  1.2249 +
  1.2250 +    frame.syncStack(0);
  1.2251 +    masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  1.2252 +
  1.2253 +    prepareVMCall();
  1.2254 +
  1.2255 +    pushArg(ImmGCPtr(fun));
  1.2256 +    pushArg(R0.scratchReg());
  1.2257 +    pushArg(ImmGCPtr(script));
  1.2258 +
  1.2259 +    return callVM(DefFunOperationInfo);
  1.2260 +}
  1.2261 +
  1.2262 +typedef bool (*InitPropGetterSetterFn)(JSContext *, jsbytecode *, HandleObject, HandlePropertyName,
  1.2263 +                                       HandleObject);
  1.2264 +static const VMFunction InitPropGetterSetterInfo =
  1.2265 +    FunctionInfo<InitPropGetterSetterFn>(InitGetterSetterOperation);
  1.2266 +
  1.2267 +bool
  1.2268 +BaselineCompiler::emitInitPropGetterSetter()
  1.2269 +{
  1.2270 +    JS_ASSERT(JSOp(*pc) == JSOP_INITPROP_GETTER ||
  1.2271 +              JSOp(*pc) == JSOP_INITPROP_SETTER);
  1.2272 +
  1.2273 +    // Keep values on the stack for the decompiler.
  1.2274 +    frame.syncStack(0);
  1.2275 +
  1.2276 +    prepareVMCall();
  1.2277 +
  1.2278 +    masm.extractObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
  1.2279 +    masm.extractObject(frame.addressOfStackValue(frame.peek(-2)), R1.scratchReg());
  1.2280 +
  1.2281 +    pushArg(R0.scratchReg());
  1.2282 +    pushArg(ImmGCPtr(script->getName(pc)));
  1.2283 +    pushArg(R1.scratchReg());
  1.2284 +    pushArg(ImmPtr(pc));
  1.2285 +
  1.2286 +    if (!callVM(InitPropGetterSetterInfo))
  1.2287 +        return false;
  1.2288 +
  1.2289 +    frame.pop();
  1.2290 +    return true;
  1.2291 +}
  1.2292 +
  1.2293 +bool
  1.2294 +BaselineCompiler::emit_JSOP_INITPROP_GETTER()
  1.2295 +{
  1.2296 +    return emitInitPropGetterSetter();
  1.2297 +}
  1.2298 +
  1.2299 +bool
  1.2300 +BaselineCompiler::emit_JSOP_INITPROP_SETTER()
  1.2301 +{
  1.2302 +    return emitInitPropGetterSetter();
  1.2303 +}
  1.2304 +
  1.2305 +typedef bool (*InitElemGetterSetterFn)(JSContext *, jsbytecode *, HandleObject, HandleValue,
  1.2306 +                                       HandleObject);
  1.2307 +static const VMFunction InitElemGetterSetterInfo =
  1.2308 +    FunctionInfo<InitElemGetterSetterFn>(InitGetterSetterOperation);
  1.2309 +
  1.2310 +bool
  1.2311 +BaselineCompiler::emitInitElemGetterSetter()
  1.2312 +{
  1.2313 +    JS_ASSERT(JSOp(*pc) == JSOP_INITELEM_GETTER ||
  1.2314 +              JSOp(*pc) == JSOP_INITELEM_SETTER);
  1.2315 +
  1.2316 +    // Load index and value in R0 and R1, but keep values on the stack for the
  1.2317 +    // decompiler.
  1.2318 +    frame.syncStack(0);
  1.2319 +    masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
  1.2320 +    masm.extractObject(frame.addressOfStackValue(frame.peek(-1)), R1.scratchReg());
  1.2321 +
  1.2322 +    prepareVMCall();
  1.2323 +
  1.2324 +    pushArg(R1.scratchReg());
  1.2325 +    pushArg(R0);
  1.2326 +    masm.extractObject(frame.addressOfStackValue(frame.peek(-3)), R0.scratchReg());
  1.2327 +    pushArg(R0.scratchReg());
  1.2328 +    pushArg(ImmPtr(pc));
  1.2329 +
  1.2330 +    if (!callVM(InitElemGetterSetterInfo))
  1.2331 +        return false;
  1.2332 +
  1.2333 +    frame.popn(2);
  1.2334 +    return true;
  1.2335 +}
  1.2336 +
  1.2337 +bool
  1.2338 +BaselineCompiler::emit_JSOP_INITELEM_GETTER()
  1.2339 +{
  1.2340 +    return emitInitElemGetterSetter();
  1.2341 +}
  1.2342 +
  1.2343 +bool
  1.2344 +BaselineCompiler::emit_JSOP_INITELEM_SETTER()
  1.2345 +{
  1.2346 +    return emitInitElemGetterSetter();
  1.2347 +}
  1.2348 +
  1.2349 +bool
  1.2350 +BaselineCompiler::emit_JSOP_GETLOCAL()
  1.2351 +{
  1.2352 +    frame.pushLocal(GET_LOCALNO(pc));
  1.2353 +    return true;
  1.2354 +}
  1.2355 +
  1.2356 +bool
  1.2357 +BaselineCompiler::emit_JSOP_SETLOCAL()
  1.2358 +{
  1.2359 +    // Ensure no other StackValue refers to the old value, for instance i + (i = 3).
  1.2360 +    // This also allows us to use R0 as scratch below.
  1.2361 +    frame.syncStack(1);
  1.2362 +
  1.2363 +    uint32_t local = GET_LOCALNO(pc);
  1.2364 +    storeValue(frame.peek(-1), frame.addressOfLocal(local), R0);
  1.2365 +    return true;
  1.2366 +}
  1.2367 +
  1.2368 +bool
  1.2369 +BaselineCompiler::emitFormalArgAccess(uint32_t arg, bool get)
  1.2370 +{
  1.2371 +    // Fast path: the script does not use |arguments|, or is strict. In strict
  1.2372 +    // mode, formals do not alias the arguments object.
  1.2373 +    if (!script->argumentsHasVarBinding() || script->strict()) {
  1.2374 +        if (get) {
  1.2375 +            frame.pushArg(arg);
  1.2376 +        } else {
  1.2377 +            // See the comment in emit_JSOP_SETLOCAL.
  1.2378 +            frame.syncStack(1);
  1.2379 +            storeValue(frame.peek(-1), frame.addressOfArg(arg), R0);
  1.2380 +        }
  1.2381 +
  1.2382 +        return true;
  1.2383 +    }
  1.2384 +
  1.2385 +    // Sync so that we can use R0.
  1.2386 +    frame.syncStack(0);
  1.2387 +
  1.2388 +    // If the script is known to have an arguments object, we can just use it.
  1.2389 +    // Else, we *may* have an arguments object (because we can't invalidate
  1.2390 +    // when needsArgsObj becomes |true|), so we have to test HAS_ARGS_OBJ.
  1.2391 +    Label done;
  1.2392 +    if (!script->needsArgsObj()) {
  1.2393 +        Label hasArgsObj;
  1.2394 +        masm.branchTest32(Assembler::NonZero, frame.addressOfFlags(),
  1.2395 +                          Imm32(BaselineFrame::HAS_ARGS_OBJ), &hasArgsObj);
  1.2396 +        if (get)
  1.2397 +            masm.loadValue(frame.addressOfArg(arg), R0);
  1.2398 +        else
  1.2399 +            storeValue(frame.peek(-1), frame.addressOfArg(arg), R0);
  1.2400 +        masm.jump(&done);
  1.2401 +        masm.bind(&hasArgsObj);
  1.2402 +    }
  1.2403 +
  1.2404 +    // Load the arguments object data vector.
  1.2405 +    Register reg = R2.scratchReg();
  1.2406 +    masm.loadPtr(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfArgsObj()), reg);
  1.2407 +    masm.loadPrivate(Address(reg, ArgumentsObject::getDataSlotOffset()), reg);
  1.2408 +
  1.2409 +    // Load/store the argument.
  1.2410 +    Address argAddr(reg, ArgumentsData::offsetOfArgs() + arg * sizeof(Value));
  1.2411 +    if (get) {
  1.2412 +        masm.loadValue(argAddr, R0);
  1.2413 +        frame.push(R0);
  1.2414 +    } else {
  1.2415 +        masm.patchableCallPreBarrier(argAddr, MIRType_Value);
  1.2416 +        storeValue(frame.peek(-1), argAddr, R0);
  1.2417 +
  1.2418 +#ifdef JSGC_GENERATIONAL
  1.2419 +        // Fully sync the stack if post-barrier is needed.
  1.2420 +        frame.syncStack(0);
  1.2421 +        Register temp = R1.scratchReg();
  1.2422 +
  1.2423 +        // Reload the arguments object
  1.2424 +        Register reg = R2.scratchReg();
  1.2425 +        masm.loadPtr(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfArgsObj()), reg);
  1.2426 +
  1.2427 +        Label skipBarrier;
  1.2428 +        masm.branchPtrInNurseryRange(reg, temp, &skipBarrier);
  1.2429 +
  1.2430 +        masm.call(&postBarrierSlot_);
  1.2431 +
  1.2432 +        masm.bind(&skipBarrier);
  1.2433 +#endif
  1.2434 +    }
  1.2435 +
  1.2436 +    masm.bind(&done);
  1.2437 +    return true;
  1.2438 +}
  1.2439 +
  1.2440 +bool
  1.2441 +BaselineCompiler::emit_JSOP_GETARG()
  1.2442 +{
  1.2443 +    uint32_t arg = GET_ARGNO(pc);
  1.2444 +    return emitFormalArgAccess(arg, /* get = */ true);
  1.2445 +}
  1.2446 +
  1.2447 +bool
  1.2448 +BaselineCompiler::emit_JSOP_SETARG()
  1.2449 +{
  1.2450 +    // Ionmonkey can't inline functions with SETARG with magic arguments.
  1.2451 +    if (!script->argsObjAliasesFormals() && script->argumentsAliasesFormals())
  1.2452 +        script->setUninlineable();
  1.2453 +
  1.2454 +    modifiesArguments_ = true;
  1.2455 +
  1.2456 +    uint32_t arg = GET_ARGNO(pc);
  1.2457 +    return emitFormalArgAccess(arg, /* get = */ false);
  1.2458 +}
  1.2459 +
  1.2460 +bool
  1.2461 +BaselineCompiler::emitCall()
  1.2462 +{
  1.2463 +    JS_ASSERT(IsCallPC(pc));
  1.2464 +
  1.2465 +    uint32_t argc = GET_ARGC(pc);
  1.2466 +
  1.2467 +    frame.syncStack(0);
  1.2468 +    masm.mov(ImmWord(argc), R0.scratchReg());
  1.2469 +
  1.2470 +    // Call IC
  1.2471 +    ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ JSOp(*pc) == JSOP_NEW);
  1.2472 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.2473 +        return false;
  1.2474 +
  1.2475 +    // Update FrameInfo.
  1.2476 +    frame.popn(argc + 2);
  1.2477 +    frame.push(R0);
  1.2478 +    return true;
  1.2479 +}
  1.2480 +
  1.2481 +bool
  1.2482 +BaselineCompiler::emit_JSOP_CALL()
  1.2483 +{
  1.2484 +    return emitCall();
  1.2485 +}
  1.2486 +
  1.2487 +bool
  1.2488 +BaselineCompiler::emit_JSOP_NEW()
  1.2489 +{
  1.2490 +    return emitCall();
  1.2491 +}
  1.2492 +
  1.2493 +bool
  1.2494 +BaselineCompiler::emit_JSOP_FUNCALL()
  1.2495 +{
  1.2496 +    return emitCall();
  1.2497 +}
  1.2498 +
  1.2499 +bool
  1.2500 +BaselineCompiler::emit_JSOP_FUNAPPLY()
  1.2501 +{
  1.2502 +    return emitCall();
  1.2503 +}
  1.2504 +
  1.2505 +bool
  1.2506 +BaselineCompiler::emit_JSOP_EVAL()
  1.2507 +{
  1.2508 +    return emitCall();
  1.2509 +}
  1.2510 +
  1.2511 +typedef bool (*ImplicitThisFn)(JSContext *, HandleObject, HandlePropertyName,
  1.2512 +                               MutableHandleValue);
  1.2513 +static const VMFunction ImplicitThisInfo = FunctionInfo<ImplicitThisFn>(ImplicitThisOperation);
  1.2514 +
  1.2515 +bool
  1.2516 +BaselineCompiler::emit_JSOP_IMPLICITTHIS()
  1.2517 +{
  1.2518 +    frame.syncStack(0);
  1.2519 +    masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
  1.2520 +
  1.2521 +    prepareVMCall();
  1.2522 +
  1.2523 +    pushArg(ImmGCPtr(script->getName(pc)));
  1.2524 +    pushArg(R0.scratchReg());
  1.2525 +
  1.2526 +    if (!callVM(ImplicitThisInfo))
  1.2527 +        return false;
  1.2528 +
  1.2529 +    frame.push(R0);
  1.2530 +    return true;
  1.2531 +}
  1.2532 +
  1.2533 +bool
  1.2534 +BaselineCompiler::emit_JSOP_INSTANCEOF()
  1.2535 +{
  1.2536 +    frame.popRegsAndSync(2);
  1.2537 +
  1.2538 +    ICInstanceOf_Fallback::Compiler stubCompiler(cx);
  1.2539 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.2540 +        return false;
  1.2541 +
  1.2542 +    frame.push(R0);
  1.2543 +    return true;
  1.2544 +}
  1.2545 +
  1.2546 +bool
  1.2547 +BaselineCompiler::emit_JSOP_TYPEOF()
  1.2548 +{
  1.2549 +    frame.popRegsAndSync(1);
  1.2550 +
  1.2551 +    ICTypeOf_Fallback::Compiler stubCompiler(cx);
  1.2552 +    if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
  1.2553 +        return false;
  1.2554 +
  1.2555 +    frame.push(R0);
  1.2556 +    return true;
  1.2557 +}
  1.2558 +
  1.2559 +bool
  1.2560 +BaselineCompiler::emit_JSOP_TYPEOFEXPR()
  1.2561 +{
  1.2562 +    return emit_JSOP_TYPEOF();
  1.2563 +}
  1.2564 +
  1.2565 +typedef bool (*SetCallFn)(JSContext *);
  1.2566 +static const VMFunction SetCallInfo = FunctionInfo<SetCallFn>(js::SetCallOperation);
  1.2567 +
  1.2568 +bool
  1.2569 +BaselineCompiler::emit_JSOP_SETCALL()
  1.2570 +{
  1.2571 +    prepareVMCall();
  1.2572 +    return callVM(SetCallInfo);
  1.2573 +}
  1.2574 +
  1.2575 +typedef bool (*ThrowFn)(JSContext *, HandleValue);
  1.2576 +static const VMFunction ThrowInfo = FunctionInfo<ThrowFn>(js::Throw);
  1.2577 +
  1.2578 +bool
  1.2579 +BaselineCompiler::emit_JSOP_THROW()
  1.2580 +{
  1.2581 +    // Keep value to throw in R0.
  1.2582 +    frame.popRegsAndSync(1);
  1.2583 +
  1.2584 +    prepareVMCall();
  1.2585 +    pushArg(R0);
  1.2586 +
  1.2587 +    return callVM(ThrowInfo);
  1.2588 +}
  1.2589 +
  1.2590 +bool
  1.2591 +BaselineCompiler::emit_JSOP_TRY()
  1.2592 +{
  1.2593 +    // Ionmonkey can't inline function with JSOP_TRY.
  1.2594 +    script->setUninlineable();
  1.2595 +    return true;
  1.2596 +}
  1.2597 +
  1.2598 +bool
  1.2599 +BaselineCompiler::emit_JSOP_FINALLY()
  1.2600 +{
  1.2601 +    // JSOP_FINALLY has a def count of 2, but these values are already on the
  1.2602 +    // stack (they're pushed by JSOP_GOSUB). Update the compiler's stack state.
  1.2603 +    frame.setStackDepth(frame.stackDepth() + 2);
  1.2604 +
  1.2605 +    // To match the interpreter, emit an interrupt check at the start of the
  1.2606 +    // finally block.
  1.2607 +    return emitInterruptCheck();
  1.2608 +}
  1.2609 +
  1.2610 +bool
  1.2611 +BaselineCompiler::emit_JSOP_GOSUB()
  1.2612 +{
  1.2613 +    // Push |false| so that RETSUB knows the value on top of the
  1.2614 +    // stack is not an exception but the offset to the op following
  1.2615 +    // this GOSUB.
  1.2616 +    frame.push(BooleanValue(false));
  1.2617 +
  1.2618 +    int32_t nextOffset = script->pcToOffset(GetNextPc(pc));
  1.2619 +    frame.push(Int32Value(nextOffset));
  1.2620 +
  1.2621 +    // Jump to the finally block.
  1.2622 +    frame.syncStack(0);
  1.2623 +    jsbytecode *target = pc + GET_JUMP_OFFSET(pc);
  1.2624 +    masm.jump(labelOf(target));
  1.2625 +    return true;
  1.2626 +}
  1.2627 +
  1.2628 +bool
  1.2629 +BaselineCompiler::emit_JSOP_RETSUB()
  1.2630 +{
  1.2631 +    frame.popRegsAndSync(2);
  1.2632 +
  1.2633 +    ICRetSub_Fallback::Compiler stubCompiler(cx);
  1.2634 +    return emitOpIC(stubCompiler.getStub(&stubSpace_));
  1.2635 +}
  1.2636 +
  1.2637 +typedef bool (*PushBlockScopeFn)(JSContext *, BaselineFrame *, Handle<StaticBlockObject *>);
  1.2638 +static const VMFunction PushBlockScopeInfo = FunctionInfo<PushBlockScopeFn>(jit::PushBlockScope);
  1.2639 +
  1.2640 +bool
  1.2641 +BaselineCompiler::emit_JSOP_PUSHBLOCKSCOPE()
  1.2642 +{
  1.2643 +    StaticBlockObject &blockObj = script->getObject(pc)->as<StaticBlockObject>();
  1.2644 +
  1.2645 +    // Call a stub to push the block on the block chain.
  1.2646 +    prepareVMCall();
  1.2647 +    masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  1.2648 +
  1.2649 +    pushArg(ImmGCPtr(&blockObj));
  1.2650 +    pushArg(R0.scratchReg());
  1.2651 +
  1.2652 +    return callVM(PushBlockScopeInfo);
  1.2653 +}
  1.2654 +
  1.2655 +typedef bool (*PopBlockScopeFn)(JSContext *, BaselineFrame *);
  1.2656 +static const VMFunction PopBlockScopeInfo = FunctionInfo<PopBlockScopeFn>(jit::PopBlockScope);
  1.2657 +
  1.2658 +bool
  1.2659 +BaselineCompiler::emit_JSOP_POPBLOCKSCOPE()
  1.2660 +{
  1.2661 +    // Call a stub to pop the block from the block chain.
  1.2662 +    prepareVMCall();
  1.2663 +
  1.2664 +    masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  1.2665 +    pushArg(R0.scratchReg());
  1.2666 +
  1.2667 +    return callVM(PopBlockScopeInfo);
  1.2668 +}
  1.2669 +
  1.2670 +typedef bool (*DebugLeaveBlockFn)(JSContext *, BaselineFrame *, jsbytecode *);
  1.2671 +static const VMFunction DebugLeaveBlockInfo = FunctionInfo<DebugLeaveBlockFn>(jit::DebugLeaveBlock);
  1.2672 +
  1.2673 +bool
  1.2674 +BaselineCompiler::emit_JSOP_DEBUGLEAVEBLOCK()
  1.2675 +{
  1.2676 +    if (!debugMode_)
  1.2677 +        return true;
  1.2678 +
  1.2679 +    prepareVMCall();
  1.2680 +    masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  1.2681 +    pushArg(ImmPtr(pc));
  1.2682 +    pushArg(R0.scratchReg());
  1.2683 +
  1.2684 +    return callVM(DebugLeaveBlockInfo);
  1.2685 +}
  1.2686 +
  1.2687 +typedef bool (*EnterWithFn)(JSContext *, BaselineFrame *, HandleValue, Handle<StaticWithObject *>);
  1.2688 +static const VMFunction EnterWithInfo = FunctionInfo<EnterWithFn>(jit::EnterWith);
  1.2689 +
  1.2690 +bool
  1.2691 +BaselineCompiler::emit_JSOP_ENTERWITH()
  1.2692 +{
  1.2693 +    StaticWithObject &withObj = script->getObject(pc)->as<StaticWithObject>();
  1.2694 +
  1.2695 +    // Pop "with" object to R0.
  1.2696 +    frame.popRegsAndSync(1);
  1.2697 +
  1.2698 +    // Call a stub to push the object onto the scope chain.
  1.2699 +    prepareVMCall();
  1.2700 +    masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
  1.2701 +
  1.2702 +    pushArg(ImmGCPtr(&withObj));
  1.2703 +    pushArg(R0);
  1.2704 +    pushArg(R1.scratchReg());
  1.2705 +
  1.2706 +    return callVM(EnterWithInfo);
  1.2707 +}
  1.2708 +
  1.2709 +typedef bool (*LeaveWithFn)(JSContext *, BaselineFrame *);
  1.2710 +static const VMFunction LeaveWithInfo = FunctionInfo<LeaveWithFn>(jit::LeaveWith);
  1.2711 +
  1.2712 +bool
  1.2713 +BaselineCompiler::emit_JSOP_LEAVEWITH()
  1.2714 +{
  1.2715 +    // Call a stub to pop the with object from the scope chain.
  1.2716 +    prepareVMCall();
  1.2717 +
  1.2718 +    masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  1.2719 +    pushArg(R0.scratchReg());
  1.2720 +
  1.2721 +    return callVM(LeaveWithInfo);
  1.2722 +}
  1.2723 +
  1.2724 +typedef bool (*GetAndClearExceptionFn)(JSContext *, MutableHandleValue);
  1.2725 +static const VMFunction GetAndClearExceptionInfo =
  1.2726 +    FunctionInfo<GetAndClearExceptionFn>(GetAndClearException);
  1.2727 +
  1.2728 +bool
  1.2729 +BaselineCompiler::emit_JSOP_EXCEPTION()
  1.2730 +{
  1.2731 +    prepareVMCall();
  1.2732 +
  1.2733 +    if (!callVM(GetAndClearExceptionInfo))
  1.2734 +        return false;
  1.2735 +
  1.2736 +    frame.push(R0);
  1.2737 +    return true;
  1.2738 +}
  1.2739 +
  1.2740 +typedef bool (*OnDebuggerStatementFn)(JSContext *, BaselineFrame *, jsbytecode *pc, bool *);
  1.2741 +static const VMFunction OnDebuggerStatementInfo =
  1.2742 +    FunctionInfo<OnDebuggerStatementFn>(jit::OnDebuggerStatement);
  1.2743 +
  1.2744 +bool
  1.2745 +BaselineCompiler::emit_JSOP_DEBUGGER()
  1.2746 +{
  1.2747 +    if (!debugMode_)
  1.2748 +        return true;
  1.2749 +
  1.2750 +    prepareVMCall();
  1.2751 +    pushArg(ImmPtr(pc));
  1.2752 +
  1.2753 +    masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  1.2754 +    pushArg(R0.scratchReg());
  1.2755 +
  1.2756 +    if (!callVM(OnDebuggerStatementInfo))
  1.2757 +        return false;
  1.2758 +
  1.2759 +    // If the stub returns |true|, return the frame's return value.
  1.2760 +    Label done;
  1.2761 +    masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &done);
  1.2762 +    {
  1.2763 +        masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
  1.2764 +        masm.jump(&return_);
  1.2765 +    }
  1.2766 +    masm.bind(&done);
  1.2767 +    return true;
  1.2768 +}
  1.2769 +
  1.2770 +typedef bool (*DebugEpilogueFn)(JSContext *, BaselineFrame *, jsbytecode *, bool);
  1.2771 +static const VMFunction DebugEpilogueInfo = FunctionInfo<DebugEpilogueFn>(jit::DebugEpilogue);
  1.2772 +
  1.2773 +bool
  1.2774 +BaselineCompiler::emitReturn()
  1.2775 +{
  1.2776 +    if (debugMode_) {
  1.2777 +        // Move return value into the frame's rval slot.
  1.2778 +        masm.storeValue(JSReturnOperand, frame.addressOfReturnValue());
  1.2779 +        masm.or32(Imm32(BaselineFrame::HAS_RVAL), frame.addressOfFlags());
  1.2780 +
  1.2781 +        // Load BaselineFrame pointer in R0.
  1.2782 +        frame.syncStack(0);
  1.2783 +        masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  1.2784 +
  1.2785 +        prepareVMCall();
  1.2786 +        pushArg(Imm32(1));
  1.2787 +        pushArg(ImmPtr(pc));
  1.2788 +        pushArg(R0.scratchReg());
  1.2789 +        if (!callVM(DebugEpilogueInfo))
  1.2790 +            return false;
  1.2791 +
  1.2792 +        // Fix up the fake ICEntry appended by callVM for on-stack recompilation.
  1.2793 +        icEntries_.back().setForDebugEpilogue();
  1.2794 +
  1.2795 +        masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
  1.2796 +    }
  1.2797 +
  1.2798 +    // Only emit the jump if this JSOP_RETRVAL is not the last instruction.
  1.2799 +    // Not needed for last instruction, because last instruction flows
  1.2800 +    // into return label.
  1.2801 +    if (pc + GetBytecodeLength(pc) < script->codeEnd())
  1.2802 +        masm.jump(&return_);
  1.2803 +
  1.2804 +    return true;
  1.2805 +}
  1.2806 +
  1.2807 +bool
  1.2808 +BaselineCompiler::emit_JSOP_RETURN()
  1.2809 +{
  1.2810 +    JS_ASSERT(frame.stackDepth() == 1);
  1.2811 +
  1.2812 +    frame.popValue(JSReturnOperand);
  1.2813 +    return emitReturn();
  1.2814 +}
  1.2815 +
  1.2816 +bool
  1.2817 +BaselineCompiler::emit_JSOP_RETRVAL()
  1.2818 +{
  1.2819 +    JS_ASSERT(frame.stackDepth() == 0);
  1.2820 +
  1.2821 +    masm.moveValue(UndefinedValue(), JSReturnOperand);
  1.2822 +
  1.2823 +    if (!script->noScriptRval()) {
  1.2824 +        // Return the value in the return value slot, if any.
  1.2825 +        Label done;
  1.2826 +        Address flags = frame.addressOfFlags();
  1.2827 +        masm.branchTest32(Assembler::Zero, flags, Imm32(BaselineFrame::HAS_RVAL), &done);
  1.2828 +        masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
  1.2829 +        masm.bind(&done);
  1.2830 +    }
  1.2831 +
  1.2832 +    return emitReturn();
  1.2833 +}
  1.2834 +
  1.2835 +typedef bool (*ToIdFn)(JSContext *, HandleScript, jsbytecode *, HandleValue, HandleValue,
  1.2836 +                       MutableHandleValue);
  1.2837 +static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(js::ToIdOperation);
  1.2838 +
  1.2839 +bool
  1.2840 +BaselineCompiler::emit_JSOP_TOID()
  1.2841 +{
  1.2842 +    // Load index in R0, but keep values on the stack for the decompiler.
  1.2843 +    frame.syncStack(0);
  1.2844 +    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
  1.2845 +
  1.2846 +    // No-op if index is int32.
  1.2847 +    Label done;
  1.2848 +    masm.branchTestInt32(Assembler::Equal, R0, &done);
  1.2849 +
  1.2850 +    prepareVMCall();
  1.2851 +
  1.2852 +    masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R1);
  1.2853 +
  1.2854 +    pushArg(R0);
  1.2855 +    pushArg(R1);
  1.2856 +    pushArg(ImmPtr(pc));
  1.2857 +    pushArg(ImmGCPtr(script));
  1.2858 +
  1.2859 +    if (!callVM(ToIdInfo))
  1.2860 +        return false;
  1.2861 +
  1.2862 +    masm.bind(&done);
  1.2863 +    frame.pop(); // Pop index.
  1.2864 +    frame.push(R0);
  1.2865 +    return true;
  1.2866 +}
  1.2867 +
  1.2868 +bool
  1.2869 +BaselineCompiler::emit_JSOP_TABLESWITCH()
  1.2870 +{
  1.2871 +    frame.popRegsAndSync(1);
  1.2872 +
  1.2873 +    // Call IC.
  1.2874 +    ICTableSwitch::Compiler compiler(cx, pc);
  1.2875 +    return emitOpIC(compiler.getStub(&stubSpace_));
  1.2876 +}
  1.2877 +
  1.2878 +bool
  1.2879 +BaselineCompiler::emit_JSOP_ITER()
  1.2880 +{
  1.2881 +    frame.popRegsAndSync(1);
  1.2882 +
  1.2883 +    ICIteratorNew_Fallback::Compiler compiler(cx);
  1.2884 +    if (!emitOpIC(compiler.getStub(&stubSpace_)))
  1.2885 +        return false;
  1.2886 +
  1.2887 +    frame.push(R0);
  1.2888 +    return true;
  1.2889 +}
  1.2890 +
  1.2891 +bool
  1.2892 +BaselineCompiler::emit_JSOP_MOREITER()
  1.2893 +{
  1.2894 +    frame.syncStack(0);
  1.2895 +    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
  1.2896 +
  1.2897 +    ICIteratorMore_Fallback::Compiler compiler(cx);
  1.2898 +    if (!emitOpIC(compiler.getStub(&stubSpace_)))
  1.2899 +        return false;
  1.2900 +
  1.2901 +    frame.push(R0);
  1.2902 +    return true;
  1.2903 +}
  1.2904 +
  1.2905 +bool
  1.2906 +BaselineCompiler::emit_JSOP_ITERNEXT()
  1.2907 +{
  1.2908 +    frame.syncStack(0);
  1.2909 +    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
  1.2910 +
  1.2911 +    ICIteratorNext_Fallback::Compiler compiler(cx);
  1.2912 +    if (!emitOpIC(compiler.getStub(&stubSpace_)))
  1.2913 +        return false;
  1.2914 +
  1.2915 +    frame.push(R0);
  1.2916 +    return true;
  1.2917 +}
  1.2918 +
  1.2919 +bool
  1.2920 +BaselineCompiler::emit_JSOP_ENDITER()
  1.2921 +{
  1.2922 +    frame.popRegsAndSync(1);
  1.2923 +
  1.2924 +    ICIteratorClose_Fallback::Compiler compiler(cx);
  1.2925 +    return emitOpIC(compiler.getStub(&stubSpace_));
  1.2926 +}
  1.2927 +
  1.2928 +bool
  1.2929 +BaselineCompiler::emit_JSOP_SETRVAL()
  1.2930 +{
  1.2931 +    // Store to the frame's return value slot.
  1.2932 +    storeValue(frame.peek(-1), frame.addressOfReturnValue(), R2);
  1.2933 +    masm.or32(Imm32(BaselineFrame::HAS_RVAL), frame.addressOfFlags());
  1.2934 +    frame.pop();
  1.2935 +    return true;
  1.2936 +}
  1.2937 +
  1.2938 +bool
  1.2939 +BaselineCompiler::emit_JSOP_CALLEE()
  1.2940 +{
  1.2941 +    JS_ASSERT(function());
  1.2942 +    frame.syncStack(0);
  1.2943 +    masm.loadPtr(frame.addressOfCallee(), R0.scratchReg());
  1.2944 +    masm.tagValue(JSVAL_TYPE_OBJECT, R0.scratchReg(), R0);
  1.2945 +    frame.push(R0);
  1.2946 +    return true;
  1.2947 +}
  1.2948 +
  1.2949 +typedef bool (*NewArgumentsObjectFn)(JSContext *, BaselineFrame *, MutableHandleValue);
  1.2950 +static const VMFunction NewArgumentsObjectInfo =
  1.2951 +    FunctionInfo<NewArgumentsObjectFn>(jit::NewArgumentsObject);
  1.2952 +
  1.2953 +bool
  1.2954 +BaselineCompiler::emit_JSOP_ARGUMENTS()
  1.2955 +{
  1.2956 +    frame.syncStack(0);
  1.2957 +
  1.2958 +    Label done;
  1.2959 +    if (!script->argumentsHasVarBinding() || !script->needsArgsObj()) {
  1.2960 +        // We assume the script does not need an arguments object. However, this
  1.2961 +        // assumption can be invalidated later, see argumentsOptimizationFailed
  1.2962 +        // in JSScript. Because we can't invalidate baseline JIT code, we set a
  1.2963 +        // flag on BaselineScript when that happens and guard on it here.
  1.2964 +        masm.moveValue(MagicValue(JS_OPTIMIZED_ARGUMENTS), R0);
  1.2965 +
  1.2966 +        // Load script->baseline.
  1.2967 +        Register scratch = R1.scratchReg();
  1.2968 +        masm.movePtr(ImmGCPtr(script), scratch);
  1.2969 +        masm.loadPtr(Address(scratch, JSScript::offsetOfBaselineScript()), scratch);
  1.2970 +
  1.2971 +        // If we don't need an arguments object, skip the VM call.
  1.2972 +        masm.branchTest32(Assembler::Zero, Address(scratch, BaselineScript::offsetOfFlags()),
  1.2973 +                          Imm32(BaselineScript::NEEDS_ARGS_OBJ), &done);
  1.2974 +    }
  1.2975 +
  1.2976 +    prepareVMCall();
  1.2977 +
  1.2978 +    masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  1.2979 +    pushArg(R0.scratchReg());
  1.2980 +
  1.2981 +    if (!callVM(NewArgumentsObjectInfo))
  1.2982 +        return false;
  1.2983 +
  1.2984 +    masm.bind(&done);
  1.2985 +    frame.push(R0);
  1.2986 +    return true;
  1.2987 +}
  1.2988 +
  1.2989 +typedef bool (*RunOnceScriptPrologueFn)(JSContext *, HandleScript);
  1.2990 +static const VMFunction RunOnceScriptPrologueInfo =
  1.2991 +    FunctionInfo<RunOnceScriptPrologueFn>(js::RunOnceScriptPrologue);
  1.2992 +
  1.2993 +bool
  1.2994 +BaselineCompiler::emit_JSOP_RUNONCE()
  1.2995 +{
  1.2996 +    frame.syncStack(0);
  1.2997 +
  1.2998 +    prepareVMCall();
  1.2999 +
  1.3000 +    masm.movePtr(ImmGCPtr(script), R0.scratchReg());
  1.3001 +    pushArg(R0.scratchReg());
  1.3002 +
  1.3003 +    return callVM(RunOnceScriptPrologueInfo);
  1.3004 +}
  1.3005 +
  1.3006 +bool
  1.3007 +BaselineCompiler::emit_JSOP_REST()
  1.3008 +{
  1.3009 +    frame.syncStack(0);
  1.3010 +
  1.3011 +    JSObject *templateObject = NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject);
  1.3012 +    if (!templateObject)
  1.3013 +        return false;
  1.3014 +    types::FixRestArgumentsType(cx, templateObject);
  1.3015 +
  1.3016 +    // Call IC.
  1.3017 +    ICRest_Fallback::Compiler compiler(cx, templateObject);
  1.3018 +    if (!emitOpIC(compiler.getStub(&stubSpace_)))
  1.3019 +        return false;
  1.3020 +
  1.3021 +    // Mark R0 as pushed stack value.
  1.3022 +    frame.push(R0);
  1.3023 +    return true;
  1.3024 +}

mercurial