js/src/jit/BaselineFrame.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:b080b03dc924
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_BaselineFrame_h
8 #define jit_BaselineFrame_h
9
10 #ifdef JS_ION
11
12 #include "jit/IonFrames.h"
13 #include "vm/Stack.h"
14
15 namespace js {
16 namespace jit {
17
18 struct BaselineDebugModeOSRInfo;
19
20 // The stack looks like this, fp is the frame pointer:
21 //
22 // fp+y arguments
23 // fp+x IonJSFrameLayout (frame header)
24 // fp => saved frame pointer
25 // fp-x BaselineFrame
26 // locals
27 // stack values
28
29 // Eval frames
30 //
31 // Like js::InterpreterFrame, every BaselineFrame is either a global frame
32 // or a function frame. Both global and function frames can optionally
33 // be "eval frames". The callee token for eval function frames is the
34 // enclosing function. BaselineFrame::evalScript_ stores the eval script
35 // itself.
36 class BaselineFrame
37 {
38 public:
39 enum Flags {
40 // The frame has a valid return value. See also InterpreterFrame::HAS_RVAL.
41 HAS_RVAL = 1 << 0,
42
43 // A call object has been pushed on the scope chain.
44 HAS_CALL_OBJ = 1 << 2,
45
46 // Frame has an arguments object, argsObj_.
47 HAS_ARGS_OBJ = 1 << 4,
48
49 // See InterpreterFrame::PREV_UP_TO_DATE.
50 PREV_UP_TO_DATE = 1 << 5,
51
52 // Eval frame, see the "eval frames" comment.
53 EVAL = 1 << 6,
54
55 // Frame has hookData_ set.
56 HAS_HOOK_DATA = 1 << 7,
57
58 // Frame has profiler entry pushed.
59 HAS_PUSHED_SPS_FRAME = 1 << 8,
60
61 // Frame has over-recursed on an early check.
62 OVER_RECURSED = 1 << 9,
63
64 // Frame has a BaselineRecompileInfo stashed in the scratch value
65 // slot. See PatchBaselineFramesForDebugMOde.
66 HAS_DEBUG_MODE_OSR_INFO = 1 << 10
67 };
68
69 protected: // Silence Clang warning about unused private fields.
70 // We need to split the Value into 2 fields of 32 bits, otherwise the C++
71 // compiler may add some padding between the fields.
72 uint32_t loScratchValue_;
73 uint32_t hiScratchValue_;
74 uint32_t loReturnValue_; // If HAS_RVAL, the frame's return value.
75 uint32_t hiReturnValue_;
76 uint32_t frameSize_;
77 JSObject *scopeChain_; // Scope chain (always initialized).
78 JSScript *evalScript_; // If isEvalFrame(), the current eval script.
79 ArgumentsObject *argsObj_; // If HAS_ARGS_OBJ, the arguments object.
80 void *hookData_; // If HAS_HOOK_DATA, debugger call hook data.
81 uint32_t flags_;
82 #if JS_BITS_PER_WORD == 32
83 uint32_t padding_; // Pad to 8-byte alignment.
84 #endif
85
86 public:
87 // Distance between the frame pointer and the frame header (return address).
88 // This is the old frame pointer saved in the prologue.
89 static const uint32_t FramePointerOffset = sizeof(void *);
90
91 bool initForOsr(InterpreterFrame *fp, uint32_t numStackValues);
92
93 uint32_t frameSize() const {
94 return frameSize_;
95 }
96 void setFrameSize(uint32_t frameSize) {
97 frameSize_ = frameSize;
98 }
99 inline uint32_t *addressOfFrameSize() {
100 return &frameSize_;
101 }
102 JSObject *scopeChain() const {
103 return scopeChain_;
104 }
105 void setScopeChain(JSObject *scopeChain) {
106 scopeChain_ = scopeChain;
107 }
108 inline JSObject **addressOfScopeChain() {
109 return &scopeChain_;
110 }
111
112 inline Value *addressOfScratchValue() {
113 return reinterpret_cast<Value *>(&loScratchValue_);
114 }
115
116 inline void pushOnScopeChain(ScopeObject &scope);
117 inline void popOffScopeChain();
118
119 inline void popWith(JSContext *cx);
120
121 CalleeToken calleeToken() const {
122 uint8_t *pointer = (uint8_t *)this + Size() + offsetOfCalleeToken();
123 return *(CalleeToken *)pointer;
124 }
125 void replaceCalleeToken(CalleeToken token) {
126 uint8_t *pointer = (uint8_t *)this + Size() + offsetOfCalleeToken();
127 *(CalleeToken *)pointer = token;
128 }
129 JSScript *script() const {
130 if (isEvalFrame())
131 return evalScript();
132 return ScriptFromCalleeToken(calleeToken());
133 }
134 JSFunction *fun() const {
135 return CalleeTokenToFunction(calleeToken());
136 }
137 JSFunction *maybeFun() const {
138 return isFunctionFrame() ? fun() : nullptr;
139 }
140 JSFunction *callee() const {
141 return CalleeTokenToFunction(calleeToken());
142 }
143 Value calleev() const {
144 return ObjectValue(*callee());
145 }
146 size_t numValueSlots() const {
147 size_t size = frameSize();
148
149 JS_ASSERT(size >= BaselineFrame::FramePointerOffset + BaselineFrame::Size());
150 size -= BaselineFrame::FramePointerOffset + BaselineFrame::Size();
151
152 JS_ASSERT((size % sizeof(Value)) == 0);
153 return size / sizeof(Value);
154 }
155 Value *valueSlot(size_t slot) const {
156 JS_ASSERT(slot < numValueSlots());
157 return (Value *)this - (slot + 1);
158 }
159
160 Value &unaliasedVar(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
161 JS_ASSERT(i < script()->nfixedvars());
162 JS_ASSERT_IF(checkAliasing, !script()->varIsAliased(i));
163 return *valueSlot(i);
164 }
165
166 Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
167 JS_ASSERT(i < numFormalArgs());
168 JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals() &&
169 !script()->formalIsAliased(i));
170 return argv()[i];
171 }
172
173 Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
174 JS_ASSERT(i < numActualArgs());
175 JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
176 JS_ASSERT_IF(checkAliasing && i < numFormalArgs(), !script()->formalIsAliased(i));
177 return argv()[i];
178 }
179
180 Value &unaliasedLocal(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
181 JS_ASSERT(i < script()->nfixed());
182 #ifdef DEBUG
183 CheckLocalUnaliased(checkAliasing, script(), i);
184 #endif
185 return *valueSlot(i);
186 }
187
188 unsigned numActualArgs() const {
189 return *(size_t *)(reinterpret_cast<const uint8_t *>(this) +
190 BaselineFrame::Size() +
191 offsetOfNumActualArgs());
192 }
193 unsigned numFormalArgs() const {
194 return script()->functionNonDelazifying()->nargs();
195 }
196 Value &thisValue() const {
197 return *(Value *)(reinterpret_cast<const uint8_t *>(this) +
198 BaselineFrame::Size() +
199 offsetOfThis());
200 }
201 Value *argv() const {
202 return (Value *)(reinterpret_cast<const uint8_t *>(this) +
203 BaselineFrame::Size() +
204 offsetOfArg(0));
205 }
206
207 bool copyRawFrameSlots(AutoValueVector *vec) const;
208
209 bool hasReturnValue() const {
210 return flags_ & HAS_RVAL;
211 }
212 MutableHandleValue returnValue() {
213 return MutableHandleValue::fromMarkedLocation(reinterpret_cast<Value *>(&loReturnValue_));
214 }
215 void setReturnValue(const Value &v) {
216 flags_ |= HAS_RVAL;
217 returnValue().set(v);
218 }
219 inline Value *addressOfReturnValue() {
220 return reinterpret_cast<Value *>(&loReturnValue_);
221 }
222
223 bool hasCallObj() const {
224 return flags_ & HAS_CALL_OBJ;
225 }
226
227 inline CallObject &callObj() const;
228
229 void setFlags(uint32_t flags) {
230 flags_ = flags;
231 }
232 uint32_t *addressOfFlags() {
233 return &flags_;
234 }
235
236 inline bool pushBlock(JSContext *cx, Handle<StaticBlockObject *> block);
237 inline void popBlock(JSContext *cx);
238
239 bool strictEvalPrologue(JSContext *cx);
240 bool heavyweightFunPrologue(JSContext *cx);
241 bool initFunctionScopeObjects(JSContext *cx);
242
243 void initArgsObjUnchecked(ArgumentsObject &argsobj) {
244 flags_ |= HAS_ARGS_OBJ;
245 argsObj_ = &argsobj;
246 }
247 void initArgsObj(ArgumentsObject &argsobj) {
248 JS_ASSERT(script()->needsArgsObj());
249 initArgsObjUnchecked(argsobj);
250 }
251 bool hasArgsObj() const {
252 return flags_ & HAS_ARGS_OBJ;
253 }
254 ArgumentsObject &argsObj() const {
255 JS_ASSERT(hasArgsObj());
256 JS_ASSERT(script()->needsArgsObj());
257 return *argsObj_;
258 }
259
260 bool prevUpToDate() const {
261 return flags_ & PREV_UP_TO_DATE;
262 }
263 void setPrevUpToDate() {
264 flags_ |= PREV_UP_TO_DATE;
265 }
266
267 JSScript *evalScript() const {
268 JS_ASSERT(isEvalFrame());
269 return evalScript_;
270 }
271
272 bool hasHookData() const {
273 return flags_ & HAS_HOOK_DATA;
274 }
275
276 void *maybeHookData() const {
277 return hasHookData() ? hookData_ : nullptr;
278 }
279
280 void setHookData(void *v) {
281 hookData_ = v;
282 flags_ |= HAS_HOOK_DATA;
283 }
284
285 bool hasPushedSPSFrame() const {
286 return flags_ & HAS_PUSHED_SPS_FRAME;
287 }
288
289 void setPushedSPSFrame() {
290 flags_ |= HAS_PUSHED_SPS_FRAME;
291 }
292
293 void unsetPushedSPSFrame() {
294 flags_ &= ~HAS_PUSHED_SPS_FRAME;
295 }
296
297 bool overRecursed() const {
298 return flags_ & OVER_RECURSED;
299 }
300
301 void setOverRecursed() {
302 flags_ |= OVER_RECURSED;
303 }
304
305 BaselineDebugModeOSRInfo *debugModeOSRInfo() {
306 MOZ_ASSERT(flags_ & HAS_DEBUG_MODE_OSR_INFO);
307 return *reinterpret_cast<BaselineDebugModeOSRInfo **>(&loScratchValue_);
308 }
309
310 BaselineDebugModeOSRInfo *getDebugModeOSRInfo() {
311 if (flags_ & HAS_DEBUG_MODE_OSR_INFO)
312 return debugModeOSRInfo();
313 return nullptr;
314 }
315
316 void setDebugModeOSRInfo(BaselineDebugModeOSRInfo *info) {
317 flags_ |= HAS_DEBUG_MODE_OSR_INFO;
318 *reinterpret_cast<BaselineDebugModeOSRInfo **>(&loScratchValue_) = info;
319 }
320
321 void deleteDebugModeOSRInfo();
322
323 void trace(JSTracer *trc, JitFrameIterator &frame);
324
325 bool isFunctionFrame() const {
326 return CalleeTokenIsFunction(calleeToken());
327 }
328 bool isGlobalFrame() const {
329 return !CalleeTokenIsFunction(calleeToken());
330 }
331 bool isEvalFrame() const {
332 return flags_ & EVAL;
333 }
334 bool isStrictEvalFrame() const {
335 return isEvalFrame() && script()->strict();
336 }
337 bool isNonStrictEvalFrame() const {
338 return isEvalFrame() && !script()->strict();
339 }
340 bool isDirectEvalFrame() const {
341 return isEvalFrame() && script()->staticLevel() > 0;
342 }
343 bool isNonStrictDirectEvalFrame() const {
344 return isNonStrictEvalFrame() && isDirectEvalFrame();
345 }
346 bool isNonEvalFunctionFrame() const {
347 return isFunctionFrame() && !isEvalFrame();
348 }
349 bool isDebuggerFrame() const {
350 return false;
351 }
352 bool isGeneratorFrame() const {
353 return false;
354 }
355
356 IonJSFrameLayout *framePrefix() const {
357 uint8_t *fp = (uint8_t *)this + Size() + FramePointerOffset;
358 return (IonJSFrameLayout *)fp;
359 }
360
361 // Methods below are used by the compiler.
362 static size_t offsetOfCalleeToken() {
363 return FramePointerOffset + js::jit::IonJSFrameLayout::offsetOfCalleeToken();
364 }
365 static size_t offsetOfThis() {
366 return FramePointerOffset + js::jit::IonJSFrameLayout::offsetOfThis();
367 }
368 static size_t offsetOfArg(size_t index) {
369 return FramePointerOffset + js::jit::IonJSFrameLayout::offsetOfActualArg(index);
370 }
371 static size_t offsetOfNumActualArgs() {
372 return FramePointerOffset + js::jit::IonJSFrameLayout::offsetOfNumActualArgs();
373 }
374 static size_t Size() {
375 return sizeof(BaselineFrame);
376 }
377
378 // The reverseOffsetOf methods below compute the offset relative to the
379 // frame's base pointer. Since the stack grows down, these offsets are
380 // negative.
381 static int reverseOffsetOfFrameSize() {
382 return -int(Size()) + offsetof(BaselineFrame, frameSize_);
383 }
384 static int reverseOffsetOfScratchValue() {
385 return -int(Size()) + offsetof(BaselineFrame, loScratchValue_);
386 }
387 static int reverseOffsetOfScopeChain() {
388 return -int(Size()) + offsetof(BaselineFrame, scopeChain_);
389 }
390 static int reverseOffsetOfArgsObj() {
391 return -int(Size()) + offsetof(BaselineFrame, argsObj_);
392 }
393 static int reverseOffsetOfFlags() {
394 return -int(Size()) + offsetof(BaselineFrame, flags_);
395 }
396 static int reverseOffsetOfEvalScript() {
397 return -int(Size()) + offsetof(BaselineFrame, evalScript_);
398 }
399 static int reverseOffsetOfReturnValue() {
400 return -int(Size()) + offsetof(BaselineFrame, loReturnValue_);
401 }
402 static int reverseOffsetOfLocal(size_t index) {
403 return -int(Size()) - (index + 1) * sizeof(Value);
404 }
405 };
406
407 // Ensure the frame is 8-byte aligned (required on ARM).
408 JS_STATIC_ASSERT(((sizeof(BaselineFrame) + BaselineFrame::FramePointerOffset) % 8) == 0);
409
410 } // namespace jit
411 } // namespace js
412
413 #endif // JS_ION
414
415 #endif /* jit_BaselineFrame_h */

mercurial