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 +}