|
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 */ |