1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/. */
7 #include "jit/BaselineFrameInfo.h"
11 #include "jit/BaselineIC.h"
13 # include "jit/BytecodeAnalysis.h"
16 #include "jit/BaselineFrameInfo-inl.h"
17 #include "jit/JitFrames.h"
18 #include "jit/MacroAssembler-inl.h"
21 using namespace js::jit
;
23 bool CompilerFrameInfo::init(TempAllocator
& alloc
) {
24 // An extra slot is needed for global scopes because INITGLEXICAL (stack
25 // depth 1) is compiled as a SETPROP (stack depth 2) on the global lexical
27 size_t extra
= script
->isGlobalCode() ? 1 : 0;
29 std::max(script
->nslots() - script
->nfixed(), size_t(MinJITStackSize
)) +
31 if (!stack
.init(alloc
, nstack
)) {
38 void CompilerFrameInfo::sync(StackValue
* val
) {
39 switch (val
->kind()) {
40 case StackValue::Stack
:
42 case StackValue::LocalSlot
:
43 masm
.pushValue(addressOfLocal(val
->localSlot()));
45 case StackValue::ArgSlot
:
46 masm
.pushValue(addressOfArg(val
->argSlot()));
48 case StackValue::ThisSlot
:
49 masm
.pushValue(addressOfThis());
51 case StackValue::Register
:
52 masm
.pushValue(val
->reg());
54 case StackValue::Constant
:
55 masm
.pushValue(val
->constant());
58 MOZ_CRASH("Invalid kind");
64 void CompilerFrameInfo::syncStack(uint32_t uses
) {
65 MOZ_ASSERT(uses
<= stackDepth());
67 uint32_t depth
= stackDepth() - uses
;
69 for (uint32_t i
= 0; i
< depth
; i
++) {
70 StackValue
* current
= &stack
[i
];
75 uint32_t CompilerFrameInfo::numUnsyncedSlots() {
76 // Start at the bottom, find the first value that's not synced.
78 for (; i
< stackDepth(); i
++) {
79 if (peek(-int32_t(i
+ 1))->kind() == StackValue::Stack
) {
86 void CompilerFrameInfo::popValue(ValueOperand dest
) {
87 StackValue
* val
= peek(-1);
89 switch (val
->kind()) {
90 case StackValue::Constant
:
91 masm
.moveValue(val
->constant(), dest
);
93 case StackValue::LocalSlot
:
94 masm
.loadValue(addressOfLocal(val
->localSlot()), dest
);
96 case StackValue::ArgSlot
:
97 masm
.loadValue(addressOfArg(val
->argSlot()), dest
);
99 case StackValue::ThisSlot
:
100 masm
.loadValue(addressOfThis(), dest
);
102 case StackValue::Stack
:
105 case StackValue::Register
:
106 masm
.moveValue(val
->reg(), dest
);
109 MOZ_CRASH("Invalid kind");
112 // masm.popValue already adjusted the stack pointer, don't do it twice.
113 pop(DontAdjustStack
);
116 void CompilerFrameInfo::popRegsAndSync(uint32_t uses
) {
117 // x86 has only 3 Value registers. Only support 2 regs here for now,
118 // so that there's always a scratch Value register for reg -> reg
120 MOZ_ASSERT(uses
> 0);
121 MOZ_ASSERT(uses
<= 2);
122 MOZ_ASSERT(uses
<= stackDepth());
131 // If the second value is in R1, move it to R2 so that it's not
132 // clobbered by the first popValue.
133 StackValue
* val
= peek(-2);
134 if (val
->kind() == StackValue::Register
&& val
->reg() == R1
) {
135 masm
.moveValue(R1
, ValueOperand(R2
));
136 val
->setRegister(R2
);
143 MOZ_CRASH("Invalid uses");
145 // On arm64, SP may be < PSP now (that's OK).
146 // eg testcase: tests/bug1580246.js
149 void InterpreterFrameInfo::popRegsAndSync(uint32_t uses
) {
160 MOZ_CRASH("Invalid uses");
162 // On arm64, SP may be < PSP now (that's OK).
163 // eg testcase: tests/backup-point-bug1315634.js
166 void InterpreterFrameInfo::bumpInterpreterICEntry() {
167 masm
.addPtr(Imm32(sizeof(ICEntry
)), addressOfInterpreterICEntry());
170 void CompilerFrameInfo::storeStackValue(int32_t depth
, const Address
& dest
,
171 const ValueOperand
& scratch
) {
172 const StackValue
* source
= peek(depth
);
173 switch (source
->kind()) {
174 case StackValue::Constant
:
175 masm
.storeValue(source
->constant(), dest
);
177 case StackValue::Register
:
178 masm
.storeValue(source
->reg(), dest
);
180 case StackValue::LocalSlot
:
181 masm
.loadValue(addressOfLocal(source
->localSlot()), scratch
);
182 masm
.storeValue(scratch
, dest
);
184 case StackValue::ArgSlot
:
185 masm
.loadValue(addressOfArg(source
->argSlot()), scratch
);
186 masm
.storeValue(scratch
, dest
);
188 case StackValue::ThisSlot
:
189 masm
.loadValue(addressOfThis(), scratch
);
190 masm
.storeValue(scratch
, dest
);
192 case StackValue::Stack
:
193 masm
.loadValue(addressOfStackValue(depth
), scratch
);
194 masm
.storeValue(scratch
, dest
);
197 MOZ_CRASH("Invalid kind");
202 void CompilerFrameInfo::assertValidState(const BytecodeInfo
& info
) {
203 // Check stack depth.
204 MOZ_ASSERT(stackDepth() == info
.stackDepth
);
206 // Start at the bottom, find the first value that's not synced.
208 for (; i
< stackDepth(); i
++) {
209 if (stack
[i
].kind() != StackValue::Stack
) {
214 // Assert all values on top of it are also not synced.
215 for (; i
< stackDepth(); i
++) {
216 MOZ_ASSERT(stack
[i
].kind() != StackValue::Stack
);
219 // Assert every Value register is used by at most one StackValue.
220 // R2 is used as scratch register by the compiler and FrameInfo,
221 // so it shouldn't be used for StackValues.
222 bool usedR0
= false, usedR1
= false;
224 for (i
= 0; i
< stackDepth(); i
++) {
225 if (stack
[i
].kind() == StackValue::Register
) {
226 ValueOperand reg
= stack
[i
].reg();
230 } else if (reg
== R1
) {
234 MOZ_CRASH("Invalid register");