js/src/jit/BaselineFrameInfo.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:c16f287be047
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 #ifndef jit_BaselineFrameInfo_h
8 #define jit_BaselineFrameInfo_h
9
10 #ifdef JS_ION
11
12 #include "mozilla/Alignment.h"
13
14 #include "jit/BaselineFrame.h"
15 #include "jit/BaselineRegisters.h"
16 #include "jit/FixedList.h"
17 #include "jit/IonMacroAssembler.h"
18
19 namespace js {
20 namespace jit {
21
22 struct BytecodeInfo;
23
24 // FrameInfo overview.
25 //
26 // FrameInfo is used by the compiler to track values stored in the frame. This
27 // includes locals, arguments and stack values. Locals and arguments are always
28 // fully synced. Stack values can either be synced, stored as constant, stored in
29 // a Value register or refer to a local slot. Syncing a StackValue ensures it's
30 // stored on the stack, e.g. kind == Stack.
31 //
32 // To see how this works, consider the following statement:
33 //
34 // var y = x + 9;
35 //
36 // Here two values are pushed: StackValue(LocalSlot(0)) and StackValue(Int32Value(9)).
37 // Only when we reach the ADD op, code is generated to load the operands directly
38 // into the right operand registers and sync all other stack values.
39 //
40 // For stack values, the following invariants hold (and are checked between ops):
41 //
42 // (1) If a value is synced (kind == Stack), all values below it must also be synced.
43 // In other words, values with kind other than Stack can only appear on top of the
44 // abstract stack.
45 //
46 // (2) When we call a stub or IC, all values still on the stack must be synced.
47
48 // Represents a value pushed on the stack. Note that StackValue is not used for
49 // locals or arguments since these are always fully synced.
50 class StackValue
51 {
52 public:
53 enum Kind {
54 Constant,
55 Register,
56 Stack,
57 LocalSlot,
58 ArgSlot,
59 ThisSlot
60 #ifdef DEBUG
61 // In debug builds, assert Kind is initialized.
62 , Uninitialized
63 #endif
64 };
65
66 private:
67 Kind kind_;
68
69 union {
70 struct {
71 Value v;
72 } constant;
73 struct {
74 mozilla::AlignedStorage2<ValueOperand> reg;
75 } reg;
76 struct {
77 uint32_t slot;
78 } local;
79 struct {
80 uint32_t slot;
81 } arg;
82 } data;
83
84 JSValueType knownType_;
85
86 public:
87 StackValue() {
88 reset();
89 }
90
91 Kind kind() const {
92 return kind_;
93 }
94 bool hasKnownType() const {
95 return knownType_ != JSVAL_TYPE_UNKNOWN;
96 }
97 bool hasKnownType(JSValueType type) const {
98 JS_ASSERT(type != JSVAL_TYPE_UNKNOWN);
99 return knownType_ == type;
100 }
101 bool isKnownBoolean() const {
102 return hasKnownType(JSVAL_TYPE_BOOLEAN);
103 }
104 JSValueType knownType() const {
105 JS_ASSERT(hasKnownType());
106 return knownType_;
107 }
108 void reset() {
109 #ifdef DEBUG
110 kind_ = Uninitialized;
111 knownType_ = JSVAL_TYPE_UNKNOWN;
112 #endif
113 }
114 Value constant() const {
115 JS_ASSERT(kind_ == Constant);
116 return data.constant.v;
117 }
118 ValueOperand reg() const {
119 JS_ASSERT(kind_ == Register);
120 return *data.reg.reg.addr();
121 }
122 uint32_t localSlot() const {
123 JS_ASSERT(kind_ == LocalSlot);
124 return data.local.slot;
125 }
126 uint32_t argSlot() const {
127 JS_ASSERT(kind_ == ArgSlot);
128 return data.arg.slot;
129 }
130
131 void setConstant(const Value &v) {
132 kind_ = Constant;
133 data.constant.v = v;
134 knownType_ = v.isDouble() ? JSVAL_TYPE_DOUBLE : v.extractNonDoubleType();
135 }
136 void setRegister(const ValueOperand &val, JSValueType knownType = JSVAL_TYPE_UNKNOWN) {
137 kind_ = Register;
138 *data.reg.reg.addr() = val;
139 knownType_ = knownType;
140 }
141 void setLocalSlot(uint32_t slot) {
142 kind_ = LocalSlot;
143 data.local.slot = slot;
144 knownType_ = JSVAL_TYPE_UNKNOWN;
145 }
146 void setArgSlot(uint32_t slot) {
147 kind_ = ArgSlot;
148 data.arg.slot = slot;
149 knownType_ = JSVAL_TYPE_UNKNOWN;
150 }
151 void setThis() {
152 kind_ = ThisSlot;
153 knownType_ = JSVAL_TYPE_UNKNOWN;
154 }
155 void setStack() {
156 kind_ = Stack;
157 knownType_ = JSVAL_TYPE_UNKNOWN;
158 }
159 };
160
161 enum StackAdjustment { AdjustStack, DontAdjustStack };
162
163 class FrameInfo
164 {
165 JSScript *script;
166 MacroAssembler &masm;
167
168 FixedList<StackValue> stack;
169 size_t spIndex;
170
171 public:
172 FrameInfo(JSScript *script, MacroAssembler &masm)
173 : script(script),
174 masm(masm),
175 stack(),
176 spIndex(0)
177 { }
178
179 bool init(TempAllocator &alloc);
180
181 uint32_t nlocals() const {
182 return script->nfixed();
183 }
184 uint32_t nargs() const {
185 return script->functionNonDelazifying()->nargs();
186 }
187
188 private:
189 inline StackValue *rawPush() {
190 StackValue *val = &stack[spIndex++];
191 val->reset();
192 return val;
193 }
194
195 public:
196 inline size_t stackDepth() const {
197 return spIndex;
198 }
199 inline void setStackDepth(uint32_t newDepth) {
200 if (newDepth <= stackDepth()) {
201 spIndex = newDepth;
202 } else {
203 uint32_t diff = newDepth - stackDepth();
204 for (uint32_t i = 0; i < diff; i++) {
205 StackValue *val = rawPush();
206 val->setStack();
207 }
208
209 JS_ASSERT(spIndex == newDepth);
210 }
211 }
212 inline StackValue *peek(int32_t index) const {
213 JS_ASSERT(index < 0);
214 return const_cast<StackValue *>(&stack[spIndex + index]);
215 }
216
217 inline void pop(StackAdjustment adjust = AdjustStack) {
218 spIndex--;
219 StackValue *popped = &stack[spIndex];
220
221 if (adjust == AdjustStack && popped->kind() == StackValue::Stack)
222 masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg);
223
224 // Assert when anything uses this value.
225 popped->reset();
226 }
227 inline void popn(uint32_t n, StackAdjustment adjust = AdjustStack) {
228 uint32_t poppedStack = 0;
229 for (uint32_t i = 0; i < n; i++) {
230 if (peek(-1)->kind() == StackValue::Stack)
231 poppedStack++;
232 pop(DontAdjustStack);
233 }
234 if (adjust == AdjustStack && poppedStack > 0)
235 masm.addPtr(Imm32(sizeof(Value) * poppedStack), BaselineStackReg);
236 }
237 inline void push(const Value &val) {
238 StackValue *sv = rawPush();
239 sv->setConstant(val);
240 }
241 inline void push(const ValueOperand &val, JSValueType knownType=JSVAL_TYPE_UNKNOWN) {
242 StackValue *sv = rawPush();
243 sv->setRegister(val, knownType);
244 }
245 inline void pushLocal(uint32_t local) {
246 JS_ASSERT(local < nlocals());
247 StackValue *sv = rawPush();
248 sv->setLocalSlot(local);
249 }
250 inline void pushArg(uint32_t arg) {
251 StackValue *sv = rawPush();
252 sv->setArgSlot(arg);
253 }
254 inline void pushThis() {
255 StackValue *sv = rawPush();
256 sv->setThis();
257 }
258 inline void pushScratchValue() {
259 masm.pushValue(addressOfScratchValue());
260 StackValue *sv = rawPush();
261 sv->setStack();
262 }
263 inline Address addressOfLocal(size_t local) const {
264 JS_ASSERT(local < nlocals());
265 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfLocal(local));
266 }
267 Address addressOfArg(size_t arg) const {
268 JS_ASSERT(arg < nargs());
269 return Address(BaselineFrameReg, BaselineFrame::offsetOfArg(arg));
270 }
271 Address addressOfThis() const {
272 return Address(BaselineFrameReg, BaselineFrame::offsetOfThis());
273 }
274 Address addressOfCallee() const {
275 return Address(BaselineFrameReg, BaselineFrame::offsetOfCalleeToken());
276 }
277 Address addressOfScopeChain() const {
278 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfScopeChain());
279 }
280 Address addressOfFlags() const {
281 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags());
282 }
283 Address addressOfEvalScript() const {
284 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfEvalScript());
285 }
286 Address addressOfReturnValue() const {
287 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfReturnValue());
288 }
289 Address addressOfStackValue(const StackValue *value) const {
290 JS_ASSERT(value->kind() == StackValue::Stack);
291 size_t slot = value - &stack[0];
292 JS_ASSERT(slot < stackDepth());
293 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfLocal(nlocals() + slot));
294 }
295 Address addressOfScratchValue() const {
296 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfScratchValue());
297 }
298
299 void popValue(ValueOperand dest);
300
301 void sync(StackValue *val);
302 void syncStack(uint32_t uses);
303 uint32_t numUnsyncedSlots();
304 void popRegsAndSync(uint32_t uses);
305
306 inline void assertSyncedStack() const {
307 JS_ASSERT_IF(stackDepth() > 0, peek(-1)->kind() == StackValue::Stack);
308 }
309
310 #ifdef DEBUG
311 // Assert the state is valid before excuting "pc".
312 void assertValidState(const BytecodeInfo &info);
313 #else
314 inline void assertValidState(const BytecodeInfo &info) {}
315 #endif
316 };
317
318 } // namespace jit
319 } // namespace js
320
321 #endif // JS_ION
322
323 #endif /* jit_BaselineFrameInfo_h */

mercurial