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