|
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 using namespace js; |
|
13 using namespace js::jit; |
|
14 |
|
15 BaselineCompilerShared::BaselineCompilerShared(JSContext *cx, TempAllocator &alloc, JSScript *script) |
|
16 : cx(cx), |
|
17 script(script), |
|
18 pc(script->code()), |
|
19 ionCompileable_(jit::IsIonEnabled(cx) && CanIonCompileScript(cx, script, false)), |
|
20 ionOSRCompileable_(jit::IsIonEnabled(cx) && CanIonCompileScript(cx, script, true)), |
|
21 debugMode_(cx->compartment()->debugMode()), |
|
22 alloc_(alloc), |
|
23 analysis_(alloc, script), |
|
24 frame(script, masm), |
|
25 stubSpace_(), |
|
26 icEntries_(), |
|
27 pcMappingEntries_(), |
|
28 icLoadLabels_(), |
|
29 pushedBeforeCall_(0), |
|
30 inCall_(false), |
|
31 spsPushToggleOffset_() |
|
32 { } |
|
33 |
|
34 bool |
|
35 BaselineCompilerShared::callVM(const VMFunction &fun, CallVMPhase phase) |
|
36 { |
|
37 JitCode *code = cx->runtime()->jitRuntime()->getVMWrapper(fun); |
|
38 if (!code) |
|
39 return false; |
|
40 |
|
41 #ifdef DEBUG |
|
42 // Assert prepareVMCall() has been called. |
|
43 JS_ASSERT(inCall_); |
|
44 inCall_ = false; |
|
45 #endif |
|
46 |
|
47 // Compute argument size. Note that this include the size of the frame pointer |
|
48 // pushed by prepareVMCall. |
|
49 uint32_t argSize = fun.explicitStackSlots() * sizeof(void *) + sizeof(void *); |
|
50 |
|
51 // Assert all arguments were pushed. |
|
52 JS_ASSERT(masm.framePushed() - pushedBeforeCall_ == argSize); |
|
53 |
|
54 Address frameSizeAddress(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()); |
|
55 uint32_t frameVals = frame.nlocals() + frame.stackDepth(); |
|
56 uint32_t frameBaseSize = BaselineFrame::FramePointerOffset + BaselineFrame::Size(); |
|
57 uint32_t frameFullSize = frameBaseSize + (frameVals * sizeof(Value)); |
|
58 if (phase == POST_INITIALIZE) { |
|
59 masm.store32(Imm32(frameFullSize), frameSizeAddress); |
|
60 uint32_t descriptor = MakeFrameDescriptor(frameFullSize + argSize, JitFrame_BaselineJS); |
|
61 masm.push(Imm32(descriptor)); |
|
62 |
|
63 } else if (phase == PRE_INITIALIZE) { |
|
64 masm.store32(Imm32(frameBaseSize), frameSizeAddress); |
|
65 uint32_t descriptor = MakeFrameDescriptor(frameBaseSize + argSize, JitFrame_BaselineJS); |
|
66 masm.push(Imm32(descriptor)); |
|
67 |
|
68 } else { |
|
69 JS_ASSERT(phase == CHECK_OVER_RECURSED); |
|
70 Label afterWrite; |
|
71 Label writePostInitialize; |
|
72 |
|
73 // If OVER_RECURSED is set, then frame locals haven't been pushed yet. |
|
74 masm.branchTest32(Assembler::Zero, |
|
75 frame.addressOfFlags(), |
|
76 Imm32(BaselineFrame::OVER_RECURSED), |
|
77 &writePostInitialize); |
|
78 |
|
79 masm.move32(Imm32(frameBaseSize), BaselineTailCallReg); |
|
80 masm.jump(&afterWrite); |
|
81 |
|
82 masm.bind(&writePostInitialize); |
|
83 masm.move32(Imm32(frameFullSize), BaselineTailCallReg); |
|
84 |
|
85 masm.bind(&afterWrite); |
|
86 masm.store32(BaselineTailCallReg, frameSizeAddress); |
|
87 masm.add32(Imm32(argSize), BaselineTailCallReg); |
|
88 masm.makeFrameDescriptor(BaselineTailCallReg, JitFrame_BaselineJS); |
|
89 masm.push(BaselineTailCallReg); |
|
90 } |
|
91 |
|
92 // Perform the call. |
|
93 masm.call(code); |
|
94 uint32_t callOffset = masm.currentOffset(); |
|
95 masm.pop(BaselineFrameReg); |
|
96 |
|
97 // Add a fake ICEntry (without stubs), so that the return offset to |
|
98 // pc mapping works. |
|
99 ICEntry entry(script->pcToOffset(pc), ICEntry::Kind_CallVM); |
|
100 entry.setReturnOffset(callOffset); |
|
101 |
|
102 return icEntries_.append(entry); |
|
103 } |