bool
BaselineCompilerShared::callVM(const VMFunction &fun, bool preInitialize)
{
    IonCode *code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
    if (!code)
        return false;

#ifdef DEBUG
    // Assert prepareVMCall() has been called.
    JS_ASSERT(inCall_);
    inCall_ = false;
#endif

    // Compute argument size. Note that this include the size of the frame pointer
    // pushed by prepareVMCall.
    uint32_t argSize = fun.explicitStackSlots() * sizeof(void *) + sizeof(void *);

    // Assert all arguments were pushed.
    JS_ASSERT(masm.framePushed() - pushedBeforeCall_ == argSize);

    uint32_t frameVals = preInitialize ? 0 : frame.nlocals() + frame.stackDepth();
    uint32_t frameSize = BaselineFrame::FramePointerOffset + BaselineFrame::Size() +
                         (frameVals * sizeof(Value));

    masm.store32(Imm32(frameSize), Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));

    uint32_t descriptor = MakeFrameDescriptor(frameSize + argSize, IonFrame_BaselineJS);
    masm.push(Imm32(descriptor));

    // Perform the call.
    masm.call(code);
    uint32_t callOffset = masm.currentOffset();
    masm.pop(BaselineFrameReg);

    // Add a fake ICEntry (without stubs), so that the return offset to
    // pc mapping works.
    ICEntry entry(pc - script->code, false);
    entry.setReturnOffset(callOffset);

    return icEntries_.append(entry);
}
bool
BaselineCompilerShared::callVM(const VMFunction &fun, CallVMPhase phase)
{
    JitCode *code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
    if (!code)
        return false;

#ifdef DEBUG
    // Assert prepareVMCall() has been called.
    MOZ_ASSERT(inCall_);
    inCall_ = false;
#endif

    // Compute argument size. Note that this include the size of the frame pointer
    // pushed by prepareVMCall.
    uint32_t argSize = fun.explicitStackSlots() * sizeof(void *) + sizeof(void *);

    // Assert all arguments were pushed.
    MOZ_ASSERT(masm.framePushed() - pushedBeforeCall_ == argSize);

    Address frameSizeAddress(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize());
    uint32_t frameVals = frame.nlocals() + frame.stackDepth();
    uint32_t frameBaseSize = BaselineFrame::FramePointerOffset + BaselineFrame::Size();
    uint32_t frameFullSize = frameBaseSize + (frameVals * sizeof(Value));
    if (phase == POST_INITIALIZE) {
        masm.store32(Imm32(frameFullSize), frameSizeAddress);
        uint32_t descriptor = MakeFrameDescriptor(frameFullSize + argSize, JitFrame_BaselineJS);
        masm.push(Imm32(descriptor));

    } else if (phase == PRE_INITIALIZE) {
        masm.store32(Imm32(frameBaseSize), frameSizeAddress);
        uint32_t descriptor = MakeFrameDescriptor(frameBaseSize + argSize, JitFrame_BaselineJS);
        masm.push(Imm32(descriptor));

    } else {
        MOZ_ASSERT(phase == CHECK_OVER_RECURSED);
        Label afterWrite;
        Label writePostInitialize;

        // If OVER_RECURSED is set, then frame locals haven't been pushed yet.
        masm.branchTest32(Assembler::Zero,
                          frame.addressOfFlags(),
                          Imm32(BaselineFrame::OVER_RECURSED),
                          &writePostInitialize);

        masm.move32(Imm32(frameBaseSize), BaselineTailCallReg);
        masm.jump(&afterWrite);

        masm.bind(&writePostInitialize);
        masm.move32(Imm32(frameFullSize), BaselineTailCallReg);

        masm.bind(&afterWrite);
        masm.store32(BaselineTailCallReg, frameSizeAddress);
        masm.add32(Imm32(argSize), BaselineTailCallReg);
        masm.makeFrameDescriptor(BaselineTailCallReg, JitFrame_BaselineJS);
        masm.push(BaselineTailCallReg);
    }

    // Perform the call.
    masm.call(code);
    uint32_t callOffset = masm.currentOffset();
    masm.pop(BaselineFrameReg);

    // Add a fake ICEntry (without stubs), so that the return offset to
    // pc mapping works.
    ICEntry entry(script->pcToOffset(pc), ICEntry::Kind_CallVM);
    entry.setReturnOffset(CodeOffsetLabel(callOffset));

    return icEntries_.append(entry);
}
bool
BaselineCompilerShared::callVM(const VMFunction& fun, CallVMPhase phase)
{
    JitCode* code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
    if (!code)
        return false;

#ifdef DEBUG
    // Assert prepareVMCall() has been called.
    MOZ_ASSERT(inCall_);
    inCall_ = false;
#endif

#ifdef DEBUG
    // Assert the frame does not have an override pc when we're executing JIT code.
    {
        Label ok;
        masm.branchTest32(Assembler::Zero, frame.addressOfFlags(),
                          Imm32(BaselineFrame::HAS_OVERRIDE_PC), &ok);
        masm.assumeUnreachable("BaselineFrame shouldn't override pc when executing JIT code");
        masm.bind(&ok);
    }
#endif

    // Compute argument size. Note that this include the size of the frame pointer
    // pushed by prepareVMCall.
    uint32_t argSize = fun.explicitStackSlots() * sizeof(void*) + sizeof(void*);

    // Assert all arguments were pushed.
    MOZ_ASSERT(masm.framePushed() - pushedBeforeCall_ == argSize);

    Address frameSizeAddress(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize());
    uint32_t frameVals = frame.nlocals() + frame.stackDepth();
    uint32_t frameBaseSize = BaselineFrame::FramePointerOffset + BaselineFrame::Size();
    uint32_t frameFullSize = frameBaseSize + (frameVals * sizeof(Value));
    if (phase == POST_INITIALIZE) {
        masm.store32(Imm32(frameFullSize), frameSizeAddress);
        uint32_t descriptor = MakeFrameDescriptor(frameFullSize + argSize, JitFrame_BaselineJS,
                                                  ExitFrameLayout::Size());
        masm.push(Imm32(descriptor));

    } else if (phase == PRE_INITIALIZE) {
        masm.store32(Imm32(frameBaseSize), frameSizeAddress);
        uint32_t descriptor = MakeFrameDescriptor(frameBaseSize + argSize, JitFrame_BaselineJS,
                                                  ExitFrameLayout::Size());
        masm.push(Imm32(descriptor));

    } else {
        MOZ_ASSERT(phase == CHECK_OVER_RECURSED);
        Label afterWrite;
        Label writePostInitialize;

        // If OVER_RECURSED is set, then frame locals haven't been pushed yet.
        masm.branchTest32(Assembler::Zero,
                          frame.addressOfFlags(),
                          Imm32(BaselineFrame::OVER_RECURSED),
                          &writePostInitialize);

        masm.move32(Imm32(frameBaseSize), ICTailCallReg);
        masm.jump(&afterWrite);

        masm.bind(&writePostInitialize);
        masm.move32(Imm32(frameFullSize), ICTailCallReg);

        masm.bind(&afterWrite);
        masm.store32(ICTailCallReg, frameSizeAddress);
        masm.add32(Imm32(argSize), ICTailCallReg);
        masm.makeFrameDescriptor(ICTailCallReg, JitFrame_BaselineJS, ExitFrameLayout::Size());
        masm.push(ICTailCallReg);
    }
    MOZ_ASSERT(fun.expectTailCall == NonTailCall);
    // Perform the call.
    masm.call(code);
    uint32_t callOffset = masm.currentOffset();
    masm.pop(BaselineFrameReg);

#ifdef DEBUG
    // Assert the frame does not have an override pc when we're executing JIT code.
    {
        Label ok;
        masm.branchTest32(Assembler::Zero, frame.addressOfFlags(),
                          Imm32(BaselineFrame::HAS_OVERRIDE_PC), &ok);
        masm.assumeUnreachable("BaselineFrame shouldn't override pc after VM call");
        masm.bind(&ok);
    }
#endif

    // Add a fake ICEntry (without stubs), so that the return offset to
    // pc mapping works.
    return appendICEntry(ICEntry::Kind_CallVM, callOffset);
}