Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "jit/shared/BaselineCompiler-shared.h"
8 :
9 : #include "jit/BaselineIC.h"
10 : #include "jit/VMFunctions.h"
11 :
12 : #include "jsscriptinlines.h"
13 : #include "jit/MacroAssembler-inl.h"
14 :
15 : using namespace js;
16 : using namespace js::jit;
17 :
18 628 : BaselineCompilerShared::BaselineCompilerShared(JSContext* cx, TempAllocator& alloc, JSScript* script)
19 : : cx(cx),
20 : script(script),
21 628 : pc(script->code()),
22 628 : ionCompileable_(jit::IsIonEnabled(cx) && CanIonCompileScript(cx, script, false)),
23 628 : ionOSRCompileable_(jit::IsIonEnabled(cx) && CanIonCompileScript(cx, script, true)),
24 628 : compileDebugInstrumentation_(script->isDebuggee()),
25 : alloc_(alloc),
26 : analysis_(alloc, script),
27 : frame(script, masm),
28 : stubSpace_(),
29 : icEntries_(),
30 : pcMappingEntries_(),
31 : icLoadLabels_(),
32 : pushedBeforeCall_(0),
33 : #ifdef DEBUG
34 : inCall_(false),
35 : #endif
36 : profilerPushToggleOffset_(),
37 : profilerEnterFrameToggleOffset_(),
38 : profilerExitFrameToggleOffset_(),
39 : traceLoggerToggleOffsets_(cx),
40 3140 : traceLoggerScriptTextIdOffset_()
41 628 : { }
42 :
43 : void
44 3436 : BaselineCompilerShared::prepareVMCall()
45 : {
46 3436 : pushedBeforeCall_ = masm.framePushed();
47 : #ifdef DEBUG
48 3436 : inCall_ = true;
49 : #endif
50 :
51 : // Ensure everything is synced.
52 3436 : frame.syncStack(0);
53 :
54 : // Save the frame pointer.
55 3436 : masm.Push(BaselineFrameReg);
56 3436 : }
57 :
58 : bool
59 3436 : BaselineCompilerShared::callVM(const VMFunction& fun, CallVMPhase phase)
60 : {
61 3436 : JitCode* code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
62 3436 : if (!code)
63 0 : return false;
64 :
65 : #ifdef DEBUG
66 : // Assert prepareVMCall() has been called.
67 3436 : MOZ_ASSERT(inCall_);
68 3436 : inCall_ = false;
69 :
70 : // Assert the frame does not have an override pc when we're executing JIT code.
71 : {
72 6872 : Label ok;
73 6872 : masm.branchTest32(Assembler::Zero, frame.addressOfFlags(),
74 3436 : Imm32(BaselineFrame::HAS_OVERRIDE_PC), &ok);
75 3436 : masm.assumeUnreachable("BaselineFrame shouldn't override pc when executing JIT code");
76 3436 : masm.bind(&ok);
77 : }
78 : #endif
79 :
80 : // Compute argument size. Note that this include the size of the frame pointer
81 : // pushed by prepareVMCall.
82 3436 : uint32_t argSize = fun.explicitStackSlots() * sizeof(void*) + sizeof(void*);
83 :
84 : // Assert all arguments were pushed.
85 3436 : MOZ_ASSERT(masm.framePushed() - pushedBeforeCall_ == argSize);
86 :
87 3436 : Address frameSizeAddress(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize());
88 3436 : uint32_t frameVals = frame.nlocals() + frame.stackDepth();
89 3436 : uint32_t frameBaseSize = BaselineFrame::FramePointerOffset + BaselineFrame::Size();
90 3436 : uint32_t frameFullSize = frameBaseSize + (frameVals * sizeof(Value));
91 3436 : if (phase == POST_INITIALIZE) {
92 3436 : masm.store32(Imm32(frameFullSize), frameSizeAddress);
93 3436 : uint32_t descriptor = MakeFrameDescriptor(frameFullSize + argSize, JitFrame_BaselineJS,
94 6872 : ExitFrameLayout::Size());
95 3436 : masm.push(Imm32(descriptor));
96 :
97 0 : } else if (phase == PRE_INITIALIZE) {
98 0 : masm.store32(Imm32(frameBaseSize), frameSizeAddress);
99 0 : uint32_t descriptor = MakeFrameDescriptor(frameBaseSize + argSize, JitFrame_BaselineJS,
100 0 : ExitFrameLayout::Size());
101 0 : masm.push(Imm32(descriptor));
102 :
103 : } else {
104 0 : MOZ_ASSERT(phase == CHECK_OVER_RECURSED);
105 0 : Label afterWrite;
106 0 : Label writePostInitialize;
107 :
108 : // If OVER_RECURSED is set, then frame locals haven't been pushed yet.
109 0 : masm.branchTest32(Assembler::Zero,
110 0 : frame.addressOfFlags(),
111 : Imm32(BaselineFrame::OVER_RECURSED),
112 0 : &writePostInitialize);
113 :
114 0 : masm.move32(Imm32(frameBaseSize), ICTailCallReg);
115 0 : masm.jump(&afterWrite);
116 :
117 0 : masm.bind(&writePostInitialize);
118 0 : masm.move32(Imm32(frameFullSize), ICTailCallReg);
119 :
120 0 : masm.bind(&afterWrite);
121 0 : masm.store32(ICTailCallReg, frameSizeAddress);
122 0 : masm.add32(Imm32(argSize), ICTailCallReg);
123 0 : masm.makeFrameDescriptor(ICTailCallReg, JitFrame_BaselineJS, ExitFrameLayout::Size());
124 0 : masm.push(ICTailCallReg);
125 : }
126 3436 : MOZ_ASSERT(fun.expectTailCall == NonTailCall);
127 : // Perform the call.
128 3436 : masm.call(code);
129 3436 : uint32_t callOffset = masm.currentOffset();
130 3436 : masm.pop(BaselineFrameReg);
131 :
132 : #ifdef DEBUG
133 : // Assert the frame does not have an override pc when we're executing JIT code.
134 : {
135 6872 : Label ok;
136 6872 : masm.branchTest32(Assembler::Zero, frame.addressOfFlags(),
137 3436 : Imm32(BaselineFrame::HAS_OVERRIDE_PC), &ok);
138 3436 : masm.assumeUnreachable("BaselineFrame shouldn't override pc after VM call");
139 3436 : masm.bind(&ok);
140 : }
141 : #endif
142 :
143 : // Add a fake ICEntry (without stubs), so that the return offset to
144 : // pc mapping works.
145 3436 : return appendICEntry(ICEntry::Kind_CallVM, callOffset);
146 : }
|