michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "jit/shared/BaselineCompiler-shared.h" michael@0: michael@0: #include "jit/BaselineIC.h" michael@0: #include "jit/VMFunctions.h" michael@0: michael@0: using namespace js; michael@0: using namespace js::jit; michael@0: michael@0: BaselineCompilerShared::BaselineCompilerShared(JSContext *cx, TempAllocator &alloc, JSScript *script) michael@0: : cx(cx), michael@0: script(script), michael@0: pc(script->code()), michael@0: ionCompileable_(jit::IsIonEnabled(cx) && CanIonCompileScript(cx, script, false)), michael@0: ionOSRCompileable_(jit::IsIonEnabled(cx) && CanIonCompileScript(cx, script, true)), michael@0: debugMode_(cx->compartment()->debugMode()), michael@0: alloc_(alloc), michael@0: analysis_(alloc, script), michael@0: frame(script, masm), michael@0: stubSpace_(), michael@0: icEntries_(), michael@0: pcMappingEntries_(), michael@0: icLoadLabels_(), michael@0: pushedBeforeCall_(0), michael@0: inCall_(false), michael@0: spsPushToggleOffset_() michael@0: { } michael@0: michael@0: bool michael@0: BaselineCompilerShared::callVM(const VMFunction &fun, CallVMPhase phase) michael@0: { michael@0: JitCode *code = cx->runtime()->jitRuntime()->getVMWrapper(fun); michael@0: if (!code) michael@0: return false; michael@0: michael@0: #ifdef DEBUG michael@0: // Assert prepareVMCall() has been called. michael@0: JS_ASSERT(inCall_); michael@0: inCall_ = false; michael@0: #endif michael@0: michael@0: // Compute argument size. Note that this include the size of the frame pointer michael@0: // pushed by prepareVMCall. michael@0: uint32_t argSize = fun.explicitStackSlots() * sizeof(void *) + sizeof(void *); michael@0: michael@0: // Assert all arguments were pushed. michael@0: JS_ASSERT(masm.framePushed() - pushedBeforeCall_ == argSize); michael@0: michael@0: Address frameSizeAddress(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()); michael@0: uint32_t frameVals = frame.nlocals() + frame.stackDepth(); michael@0: uint32_t frameBaseSize = BaselineFrame::FramePointerOffset + BaselineFrame::Size(); michael@0: uint32_t frameFullSize = frameBaseSize + (frameVals * sizeof(Value)); michael@0: if (phase == POST_INITIALIZE) { michael@0: masm.store32(Imm32(frameFullSize), frameSizeAddress); michael@0: uint32_t descriptor = MakeFrameDescriptor(frameFullSize + argSize, JitFrame_BaselineJS); michael@0: masm.push(Imm32(descriptor)); michael@0: michael@0: } else if (phase == PRE_INITIALIZE) { michael@0: masm.store32(Imm32(frameBaseSize), frameSizeAddress); michael@0: uint32_t descriptor = MakeFrameDescriptor(frameBaseSize + argSize, JitFrame_BaselineJS); michael@0: masm.push(Imm32(descriptor)); michael@0: michael@0: } else { michael@0: JS_ASSERT(phase == CHECK_OVER_RECURSED); michael@0: Label afterWrite; michael@0: Label writePostInitialize; michael@0: michael@0: // If OVER_RECURSED is set, then frame locals haven't been pushed yet. michael@0: masm.branchTest32(Assembler::Zero, michael@0: frame.addressOfFlags(), michael@0: Imm32(BaselineFrame::OVER_RECURSED), michael@0: &writePostInitialize); michael@0: michael@0: masm.move32(Imm32(frameBaseSize), BaselineTailCallReg); michael@0: masm.jump(&afterWrite); michael@0: michael@0: masm.bind(&writePostInitialize); michael@0: masm.move32(Imm32(frameFullSize), BaselineTailCallReg); michael@0: michael@0: masm.bind(&afterWrite); michael@0: masm.store32(BaselineTailCallReg, frameSizeAddress); michael@0: masm.add32(Imm32(argSize), BaselineTailCallReg); michael@0: masm.makeFrameDescriptor(BaselineTailCallReg, JitFrame_BaselineJS); michael@0: masm.push(BaselineTailCallReg); michael@0: } michael@0: michael@0: // Perform the call. michael@0: masm.call(code); michael@0: uint32_t callOffset = masm.currentOffset(); michael@0: masm.pop(BaselineFrameReg); michael@0: michael@0: // Add a fake ICEntry (without stubs), so that the return offset to michael@0: // pc mapping works. michael@0: ICEntry entry(script->pcToOffset(pc), ICEntry::Kind_CallVM); michael@0: entry.setReturnOffset(callOffset); michael@0: michael@0: return icEntries_.append(entry); michael@0: }