|
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_JitFrameIterator_h |
|
8 #define jit_JitFrameIterator_h |
|
9 |
|
10 #ifdef JS_ION |
|
11 |
|
12 #include "jsfun.h" |
|
13 #include "jsscript.h" |
|
14 #include "jstypes.h" |
|
15 |
|
16 #include "jit/IonCode.h" |
|
17 #include "jit/Snapshots.h" |
|
18 |
|
19 namespace js { |
|
20 class ActivationIterator; |
|
21 }; |
|
22 |
|
23 namespace js { |
|
24 namespace jit { |
|
25 |
|
26 enum FrameType |
|
27 { |
|
28 // A JS frame is analagous to a js::InterpreterFrame, representing one scripted |
|
29 // functon activation. IonJS frames are used by the optimizing compiler. |
|
30 JitFrame_IonJS, |
|
31 |
|
32 // JS frame used by the baseline JIT. |
|
33 JitFrame_BaselineJS, |
|
34 |
|
35 // Frame pushed for baseline JIT stubs that make non-tail calls, so that the |
|
36 // return address -> ICEntry mapping works. |
|
37 JitFrame_BaselineStub, |
|
38 |
|
39 // The entry frame is the initial prologue block transitioning from the VM |
|
40 // into the Ion world. |
|
41 JitFrame_Entry, |
|
42 |
|
43 // A rectifier frame sits in between two JS frames, adapting argc != nargs |
|
44 // mismatches in calls. |
|
45 JitFrame_Rectifier, |
|
46 |
|
47 // An unwound JS frame is a JS frame signalling that its callee frame has been |
|
48 // turned into an exit frame (see EnsureExitFrame). Used by Ion bailouts and |
|
49 // Baseline exception unwinding. |
|
50 JitFrame_Unwound_IonJS, |
|
51 |
|
52 // Like Unwound_IonJS, but the caller is a baseline stub frame. |
|
53 JitFrame_Unwound_BaselineStub, |
|
54 |
|
55 // An unwound rectifier frame is a rectifier frame signalling that its callee |
|
56 // frame has been turned into an exit frame (see EnsureExitFrame). |
|
57 JitFrame_Unwound_Rectifier, |
|
58 |
|
59 // An exit frame is necessary for transitioning from a JS frame into C++. |
|
60 // From within C++, an exit frame is always the last frame in any |
|
61 // JitActivation. |
|
62 JitFrame_Exit |
|
63 }; |
|
64 |
|
65 enum ReadFrameArgsBehavior { |
|
66 // Only read formals (i.e. [0 ... callee()->nargs] |
|
67 ReadFrame_Formals, |
|
68 |
|
69 // Only read overflown args (i.e. [callee()->nargs ... numActuals()] |
|
70 ReadFrame_Overflown, |
|
71 |
|
72 // Read all args (i.e. [0 ... numActuals()]) |
|
73 ReadFrame_Actuals |
|
74 }; |
|
75 |
|
76 class IonCommonFrameLayout; |
|
77 class IonJSFrameLayout; |
|
78 class IonExitFrameLayout; |
|
79 |
|
80 class BaselineFrame; |
|
81 |
|
82 class JitActivation; |
|
83 |
|
84 class JitFrameIterator |
|
85 { |
|
86 protected: |
|
87 uint8_t *current_; |
|
88 FrameType type_; |
|
89 uint8_t *returnAddressToFp_; |
|
90 size_t frameSize_; |
|
91 |
|
92 private: |
|
93 mutable const SafepointIndex *cachedSafepointIndex_; |
|
94 const JitActivation *activation_; |
|
95 ExecutionMode mode_; |
|
96 |
|
97 void dumpBaseline() const; |
|
98 |
|
99 public: |
|
100 explicit JitFrameIterator(uint8_t *top, ExecutionMode mode) |
|
101 : current_(top), |
|
102 type_(JitFrame_Exit), |
|
103 returnAddressToFp_(nullptr), |
|
104 frameSize_(0), |
|
105 cachedSafepointIndex_(nullptr), |
|
106 activation_(nullptr), |
|
107 mode_(mode) |
|
108 { } |
|
109 |
|
110 explicit JitFrameIterator(JSContext *cx); |
|
111 explicit JitFrameIterator(const ActivationIterator &activations); |
|
112 explicit JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode); |
|
113 |
|
114 // Current frame information. |
|
115 FrameType type() const { |
|
116 return type_; |
|
117 } |
|
118 uint8_t *fp() const { |
|
119 return current_; |
|
120 } |
|
121 const JitActivation *activation() const { |
|
122 return activation_; |
|
123 } |
|
124 |
|
125 IonCommonFrameLayout *current() const { |
|
126 return (IonCommonFrameLayout *)current_; |
|
127 } |
|
128 |
|
129 inline uint8_t *returnAddress() const; |
|
130 |
|
131 IonJSFrameLayout *jsFrame() const { |
|
132 JS_ASSERT(isScripted()); |
|
133 return (IonJSFrameLayout *) fp(); |
|
134 } |
|
135 |
|
136 // Returns true iff this exit frame was created using EnsureExitFrame. |
|
137 inline bool isFakeExitFrame() const; |
|
138 |
|
139 inline IonExitFrameLayout *exitFrame() const; |
|
140 |
|
141 // Returns whether the JS frame has been invalidated and, if so, |
|
142 // places the invalidated Ion script in |ionScript|. |
|
143 bool checkInvalidation(IonScript **ionScript) const; |
|
144 bool checkInvalidation() const; |
|
145 |
|
146 bool isScripted() const { |
|
147 return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS; |
|
148 } |
|
149 bool isBaselineJS() const { |
|
150 return type_ == JitFrame_BaselineJS; |
|
151 } |
|
152 bool isIonJS() const { |
|
153 return type_ == JitFrame_IonJS; |
|
154 } |
|
155 bool isBaselineStub() const { |
|
156 return type_ == JitFrame_BaselineStub; |
|
157 } |
|
158 bool isNative() const; |
|
159 bool isOOLNative() const; |
|
160 bool isOOLPropertyOp() const; |
|
161 bool isOOLProxy() const; |
|
162 bool isDOMExit() const; |
|
163 bool isEntry() const { |
|
164 return type_ == JitFrame_Entry; |
|
165 } |
|
166 bool isFunctionFrame() const; |
|
167 |
|
168 bool isConstructing() const; |
|
169 |
|
170 void *calleeToken() const; |
|
171 JSFunction *callee() const; |
|
172 JSFunction *maybeCallee() const; |
|
173 unsigned numActualArgs() const; |
|
174 JSScript *script() const; |
|
175 void baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) const; |
|
176 Value *actualArgs() const; |
|
177 |
|
178 // Returns the return address of the frame above this one (that is, the |
|
179 // return address that returns back to the current frame). |
|
180 uint8_t *returnAddressToFp() const { |
|
181 return returnAddressToFp_; |
|
182 } |
|
183 |
|
184 // Previous frame information extracted from the current frame. |
|
185 inline size_t prevFrameLocalSize() const; |
|
186 inline FrameType prevType() const; |
|
187 uint8_t *prevFp() const; |
|
188 |
|
189 // Returns the stack space used by the current frame, in bytes. This does |
|
190 // not include the size of its fixed header. |
|
191 size_t frameSize() const { |
|
192 JS_ASSERT(type_ != JitFrame_Exit); |
|
193 return frameSize_; |
|
194 } |
|
195 |
|
196 // Functions used to iterate on frames. When prevType is JitFrame_Entry, |
|
197 // the current frame is the last frame. |
|
198 inline bool done() const { |
|
199 return type_ == JitFrame_Entry; |
|
200 } |
|
201 JitFrameIterator &operator++(); |
|
202 |
|
203 // Returns the IonScript associated with this JS frame. |
|
204 IonScript *ionScript() const; |
|
205 |
|
206 // Returns the Safepoint associated with this JS frame. Incurs a lookup |
|
207 // overhead. |
|
208 const SafepointIndex *safepoint() const; |
|
209 |
|
210 // Returns the OSI index associated with this JS frame. Incurs a lookup |
|
211 // overhead. |
|
212 const OsiIndex *osiIndex() const; |
|
213 |
|
214 uintptr_t *spillBase() const; |
|
215 MachineState machineState() const; |
|
216 |
|
217 template <class Op> |
|
218 void unaliasedForEachActual(Op op, ReadFrameArgsBehavior behavior) const { |
|
219 JS_ASSERT(isBaselineJS()); |
|
220 |
|
221 unsigned nactual = numActualArgs(); |
|
222 unsigned start, end; |
|
223 switch (behavior) { |
|
224 case ReadFrame_Formals: |
|
225 start = 0; |
|
226 end = callee()->nargs(); |
|
227 break; |
|
228 case ReadFrame_Overflown: |
|
229 start = callee()->nargs(); |
|
230 end = nactual; |
|
231 break; |
|
232 case ReadFrame_Actuals: |
|
233 start = 0; |
|
234 end = nactual; |
|
235 } |
|
236 |
|
237 Value *argv = actualArgs(); |
|
238 for (unsigned i = start; i < end; i++) |
|
239 op(argv[i]); |
|
240 } |
|
241 |
|
242 void dump() const; |
|
243 |
|
244 inline BaselineFrame *baselineFrame() const; |
|
245 }; |
|
246 |
|
247 class IonJSFrameLayout; |
|
248 class IonBailoutIterator; |
|
249 |
|
250 class RResumePoint; |
|
251 |
|
252 // Reads frame information in snapshot-encoding order (that is, outermost frame |
|
253 // to innermost frame). |
|
254 class SnapshotIterator |
|
255 { |
|
256 SnapshotReader snapshot_; |
|
257 RecoverReader recover_; |
|
258 IonJSFrameLayout *fp_; |
|
259 MachineState machine_; |
|
260 IonScript *ionScript_; |
|
261 |
|
262 private: |
|
263 // Read a spilled register from the machine state. |
|
264 bool hasRegister(Register reg) const { |
|
265 return machine_.has(reg); |
|
266 } |
|
267 uintptr_t fromRegister(Register reg) const { |
|
268 return machine_.read(reg); |
|
269 } |
|
270 |
|
271 bool hasRegister(FloatRegister reg) const { |
|
272 return machine_.has(reg); |
|
273 } |
|
274 double fromRegister(FloatRegister reg) const { |
|
275 return machine_.read(reg); |
|
276 } |
|
277 |
|
278 // Read an uintptr_t from the stack. |
|
279 bool hasStack(int32_t offset) const { |
|
280 return true; |
|
281 } |
|
282 uintptr_t fromStack(int32_t offset) const; |
|
283 |
|
284 Value allocationValue(const RValueAllocation &a); |
|
285 bool allocationReadable(const RValueAllocation &a); |
|
286 void warnUnreadableAllocation(); |
|
287 |
|
288 public: |
|
289 // Handle iterating over RValueAllocations of the snapshots. |
|
290 inline RValueAllocation readAllocation() { |
|
291 MOZ_ASSERT(moreAllocations()); |
|
292 return snapshot_.readAllocation(); |
|
293 } |
|
294 Value skip() { |
|
295 snapshot_.skipAllocation(); |
|
296 return UndefinedValue(); |
|
297 } |
|
298 |
|
299 const RResumePoint *resumePoint() const; |
|
300 const RInstruction *instruction() const { |
|
301 return recover_.instruction(); |
|
302 } |
|
303 |
|
304 uint32_t numAllocations() const; |
|
305 inline bool moreAllocations() const { |
|
306 return snapshot_.numAllocationsRead() < numAllocations(); |
|
307 } |
|
308 |
|
309 public: |
|
310 // Exhibits frame properties contained in the snapshot. |
|
311 uint32_t pcOffset() const; |
|
312 inline bool resumeAfter() const { |
|
313 // Inline frames are inlined on calls, which are considered as being |
|
314 // resumed on the Call as baseline will push the pc once we return from |
|
315 // the call. |
|
316 if (moreFrames()) |
|
317 return false; |
|
318 return recover_.resumeAfter(); |
|
319 } |
|
320 inline BailoutKind bailoutKind() const { |
|
321 return snapshot_.bailoutKind(); |
|
322 } |
|
323 |
|
324 public: |
|
325 // Read the next instruction available and get ready to either skip it or |
|
326 // evaluate it. |
|
327 inline void nextInstruction() { |
|
328 MOZ_ASSERT(snapshot_.numAllocationsRead() == numAllocations()); |
|
329 recover_.nextInstruction(); |
|
330 snapshot_.resetNumAllocationsRead(); |
|
331 } |
|
332 |
|
333 // Skip an Instruction by walking to the next instruction and by skipping |
|
334 // all the allocations corresponding to this instruction. |
|
335 void skipInstruction(); |
|
336 |
|
337 inline bool moreInstructions() const { |
|
338 return recover_.moreInstructions(); |
|
339 } |
|
340 |
|
341 public: |
|
342 // Handle iterating over frames of the snapshots. |
|
343 void nextFrame(); |
|
344 |
|
345 inline bool moreFrames() const { |
|
346 // The last instruction is recovering the innermost frame, so as long as |
|
347 // there is more instruction there is necesseray more frames. |
|
348 return moreInstructions(); |
|
349 } |
|
350 |
|
351 public: |
|
352 // Connect all informations about the current script in order to recover the |
|
353 // content of baseline frames. |
|
354 |
|
355 SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset, |
|
356 IonJSFrameLayout *fp, const MachineState &machine); |
|
357 SnapshotIterator(const JitFrameIterator &iter); |
|
358 SnapshotIterator(const IonBailoutIterator &iter); |
|
359 SnapshotIterator(); |
|
360 |
|
361 Value read() { |
|
362 return allocationValue(readAllocation()); |
|
363 } |
|
364 Value maybeRead(bool silentFailure = false) { |
|
365 RValueAllocation a = readAllocation(); |
|
366 if (allocationReadable(a)) |
|
367 return allocationValue(a); |
|
368 if (!silentFailure) |
|
369 warnUnreadableAllocation(); |
|
370 return UndefinedValue(); |
|
371 } |
|
372 |
|
373 void readCommonFrameSlots(Value *scopeChain, Value *rval) { |
|
374 if (scopeChain) |
|
375 *scopeChain = read(); |
|
376 else |
|
377 skip(); |
|
378 |
|
379 if (rval) |
|
380 *rval = read(); |
|
381 else |
|
382 skip(); |
|
383 } |
|
384 |
|
385 template <class Op> |
|
386 void readFunctionFrameArgs(Op &op, ArgumentsObject **argsObj, Value *thisv, |
|
387 unsigned start, unsigned end, JSScript *script) |
|
388 { |
|
389 // Assumes that the common frame arguments have already been read. |
|
390 if (script->argumentsHasVarBinding()) { |
|
391 if (argsObj) { |
|
392 Value v = read(); |
|
393 if (v.isObject()) |
|
394 *argsObj = &v.toObject().as<ArgumentsObject>(); |
|
395 } else { |
|
396 skip(); |
|
397 } |
|
398 } |
|
399 |
|
400 if (thisv) |
|
401 *thisv = read(); |
|
402 else |
|
403 skip(); |
|
404 |
|
405 unsigned i = 0; |
|
406 if (end < start) |
|
407 i = start; |
|
408 |
|
409 for (; i < start; i++) |
|
410 skip(); |
|
411 for (; i < end; i++) { |
|
412 // We are not always able to read values from the snapshots, some values |
|
413 // such as non-gc things may still be live in registers and cause an |
|
414 // error while reading the machine state. |
|
415 Value v = maybeRead(); |
|
416 op(v); |
|
417 } |
|
418 } |
|
419 |
|
420 Value maybeReadAllocByIndex(size_t index) { |
|
421 while (index--) { |
|
422 JS_ASSERT(moreAllocations()); |
|
423 skip(); |
|
424 } |
|
425 |
|
426 Value s = maybeRead(true); |
|
427 |
|
428 while (moreAllocations()) |
|
429 skip(); |
|
430 |
|
431 return s; |
|
432 } |
|
433 }; |
|
434 |
|
435 // Reads frame information in callstack order (that is, innermost frame to |
|
436 // outermost frame). |
|
437 template <AllowGC allowGC=CanGC> |
|
438 class InlineFrameIteratorMaybeGC |
|
439 { |
|
440 const JitFrameIterator *frame_; |
|
441 SnapshotIterator start_; |
|
442 SnapshotIterator si_; |
|
443 uint32_t framesRead_; |
|
444 |
|
445 // When the inline-frame-iterator is created, this variable is defined to |
|
446 // UINT32_MAX. Then the first iteration of findNextFrame, which settle on |
|
447 // the innermost frame, is used to update this counter to the number of |
|
448 // frames contained in the recover buffer. |
|
449 uint32_t frameCount_; |
|
450 |
|
451 typename MaybeRooted<JSFunction*, allowGC>::RootType callee_; |
|
452 typename MaybeRooted<JSScript*, allowGC>::RootType script_; |
|
453 jsbytecode *pc_; |
|
454 uint32_t numActualArgs_; |
|
455 |
|
456 struct Nop { |
|
457 void operator()(const Value &v) { } |
|
458 }; |
|
459 |
|
460 private: |
|
461 void findNextFrame(); |
|
462 |
|
463 JSObject *computeScopeChain(Value scopeChainValue) const { |
|
464 if (scopeChainValue.isObject()) |
|
465 return &scopeChainValue.toObject(); |
|
466 |
|
467 if (isFunctionFrame()) { |
|
468 // Heavyweight functions should always have a scope chain. |
|
469 MOZ_ASSERT(!callee()->isHeavyweight()); |
|
470 return callee()->environment(); |
|
471 } |
|
472 |
|
473 // Ion does not handle scripts that are not compile-and-go. |
|
474 MOZ_ASSERT(!script()->isForEval()); |
|
475 MOZ_ASSERT(script()->compileAndGo()); |
|
476 return &script()->global(); |
|
477 } |
|
478 |
|
479 public: |
|
480 InlineFrameIteratorMaybeGC(JSContext *cx, const JitFrameIterator *iter) |
|
481 : callee_(cx), |
|
482 script_(cx) |
|
483 { |
|
484 resetOn(iter); |
|
485 } |
|
486 |
|
487 InlineFrameIteratorMaybeGC(JSRuntime *rt, const JitFrameIterator *iter) |
|
488 : callee_(rt), |
|
489 script_(rt) |
|
490 { |
|
491 resetOn(iter); |
|
492 } |
|
493 |
|
494 InlineFrameIteratorMaybeGC(JSContext *cx, const IonBailoutIterator *iter); |
|
495 |
|
496 InlineFrameIteratorMaybeGC(JSContext *cx, const InlineFrameIteratorMaybeGC *iter) |
|
497 : frame_(iter ? iter->frame_ : nullptr), |
|
498 framesRead_(0), |
|
499 frameCount_(iter ? iter->frameCount_ : UINT32_MAX), |
|
500 callee_(cx), |
|
501 script_(cx) |
|
502 { |
|
503 if (frame_) { |
|
504 start_ = SnapshotIterator(*frame_); |
|
505 // findNextFrame will iterate to the next frame and init. everything. |
|
506 // Therefore to settle on the same frame, we report one frame less readed. |
|
507 framesRead_ = iter->framesRead_ - 1; |
|
508 findNextFrame(); |
|
509 } |
|
510 } |
|
511 |
|
512 bool more() const { |
|
513 return frame_ && framesRead_ < frameCount_; |
|
514 } |
|
515 JSFunction *callee() const { |
|
516 JS_ASSERT(callee_); |
|
517 return callee_; |
|
518 } |
|
519 JSFunction *maybeCallee() const { |
|
520 return callee_; |
|
521 } |
|
522 |
|
523 unsigned numActualArgs() const { |
|
524 // The number of actual arguments of inline frames is recovered by the |
|
525 // iteration process. It is recovered from the bytecode because this |
|
526 // property still hold since the for inlined frames. This property does not |
|
527 // hold for the parent frame because it can have optimize a call to |
|
528 // js_fun_call or js_fun_apply. |
|
529 if (more()) |
|
530 return numActualArgs_; |
|
531 |
|
532 return frame_->numActualArgs(); |
|
533 } |
|
534 |
|
535 template <class ArgOp, class LocalOp> |
|
536 void readFrameArgsAndLocals(JSContext *cx, ArgOp &argOp, LocalOp &localOp, |
|
537 JSObject **scopeChain, Value *rval, |
|
538 ArgumentsObject **argsObj, Value *thisv, |
|
539 ReadFrameArgsBehavior behavior) const |
|
540 { |
|
541 SnapshotIterator s(si_); |
|
542 |
|
543 // Read frame slots common to both function and global frames. |
|
544 Value scopeChainValue; |
|
545 s.readCommonFrameSlots(&scopeChainValue, rval); |
|
546 |
|
547 if (scopeChain) |
|
548 *scopeChain = computeScopeChain(scopeChainValue); |
|
549 |
|
550 // Read arguments, which only function frames have. |
|
551 if (isFunctionFrame()) { |
|
552 unsigned nactual = numActualArgs(); |
|
553 unsigned nformal = callee()->nargs(); |
|
554 |
|
555 // Get the non overflown arguments, which are taken from the inlined |
|
556 // frame, because it will have the updated value when JSOP_SETARG is |
|
557 // done. |
|
558 if (behavior != ReadFrame_Overflown) |
|
559 s.readFunctionFrameArgs(argOp, argsObj, thisv, 0, nformal, script()); |
|
560 |
|
561 if (behavior != ReadFrame_Formals) { |
|
562 if (more()) { |
|
563 // There is still a parent frame of this inlined frame. All |
|
564 // arguments (also the overflown) are the last pushed values |
|
565 // in the parent frame. To get the overflown arguments, we |
|
566 // need to take them from there. |
|
567 |
|
568 // The overflown arguments are not available in current frame. |
|
569 // They are the last pushed arguments in the parent frame of |
|
570 // this inlined frame. |
|
571 InlineFrameIteratorMaybeGC it(cx, this); |
|
572 ++it; |
|
573 unsigned argsObjAdj = it.script()->argumentsHasVarBinding() ? 1 : 0; |
|
574 SnapshotIterator parent_s(it.snapshotIterator()); |
|
575 |
|
576 // Skip over all slots until we get to the last slots |
|
577 // (= arguments slots of callee) the +3 is for [this], [returnvalue], |
|
578 // [scopechain], and maybe +1 for [argsObj] |
|
579 JS_ASSERT(parent_s.numAllocations() >= nactual + 3 + argsObjAdj); |
|
580 unsigned skip = parent_s.numAllocations() - nactual - 3 - argsObjAdj; |
|
581 for (unsigned j = 0; j < skip; j++) |
|
582 parent_s.skip(); |
|
583 |
|
584 // Get the overflown arguments |
|
585 parent_s.readCommonFrameSlots(nullptr, nullptr); |
|
586 parent_s.readFunctionFrameArgs(argOp, nullptr, nullptr, |
|
587 nformal, nactual, it.script()); |
|
588 } else { |
|
589 // There is no parent frame to this inlined frame, we can read |
|
590 // from the frame's Value vector directly. |
|
591 Value *argv = frame_->actualArgs(); |
|
592 for (unsigned i = nformal; i < nactual; i++) |
|
593 argOp(argv[i]); |
|
594 } |
|
595 } |
|
596 } |
|
597 |
|
598 // At this point we've read all the formals in s, and can read the |
|
599 // locals. |
|
600 for (unsigned i = 0; i < script()->nfixed(); i++) |
|
601 localOp(s.read()); |
|
602 } |
|
603 |
|
604 template <class Op> |
|
605 void unaliasedForEachActual(JSContext *cx, Op op, ReadFrameArgsBehavior behavior) const { |
|
606 Nop nop; |
|
607 readFrameArgsAndLocals(cx, op, nop, nullptr, nullptr, nullptr, nullptr, behavior); |
|
608 } |
|
609 |
|
610 JSScript *script() const { |
|
611 return script_; |
|
612 } |
|
613 jsbytecode *pc() const { |
|
614 return pc_; |
|
615 } |
|
616 SnapshotIterator snapshotIterator() const { |
|
617 return si_; |
|
618 } |
|
619 bool isFunctionFrame() const; |
|
620 bool isConstructing() const; |
|
621 |
|
622 JSObject *scopeChain() const { |
|
623 SnapshotIterator s(si_); |
|
624 |
|
625 // scopeChain |
|
626 Value v = s.read(); |
|
627 return computeScopeChain(v); |
|
628 } |
|
629 |
|
630 JSObject *thisObject() const { |
|
631 // In strict modes, |this| may not be an object and thus may not be |
|
632 // readable which can either segv in read or trigger the assertion. |
|
633 Value v = thisValue(); |
|
634 JS_ASSERT(v.isObject()); |
|
635 return &v.toObject(); |
|
636 } |
|
637 |
|
638 Value thisValue() const { |
|
639 // JS_ASSERT(isConstructing(...)); |
|
640 SnapshotIterator s(si_); |
|
641 |
|
642 // scopeChain |
|
643 s.skip(); |
|
644 |
|
645 // return value |
|
646 s.skip(); |
|
647 |
|
648 // Arguments object. |
|
649 if (script()->argumentsHasVarBinding()) |
|
650 s.skip(); |
|
651 |
|
652 return s.read(); |
|
653 } |
|
654 |
|
655 InlineFrameIteratorMaybeGC &operator++() { |
|
656 findNextFrame(); |
|
657 return *this; |
|
658 } |
|
659 |
|
660 void dump() const; |
|
661 |
|
662 void resetOn(const JitFrameIterator *iter); |
|
663 |
|
664 const JitFrameIterator &frame() const { |
|
665 return *frame_; |
|
666 } |
|
667 |
|
668 // Inline frame number, 0 for the outermost (non-inlined) frame. |
|
669 size_t frameNo() const { |
|
670 return frameCount() - framesRead_; |
|
671 } |
|
672 size_t frameCount() const { |
|
673 MOZ_ASSERT(frameCount_ != UINT32_MAX); |
|
674 return frameCount_; |
|
675 } |
|
676 |
|
677 private: |
|
678 InlineFrameIteratorMaybeGC() MOZ_DELETE; |
|
679 InlineFrameIteratorMaybeGC(const InlineFrameIteratorMaybeGC &iter) MOZ_DELETE; |
|
680 }; |
|
681 typedef InlineFrameIteratorMaybeGC<CanGC> InlineFrameIterator; |
|
682 typedef InlineFrameIteratorMaybeGC<NoGC> InlineFrameIteratorNoGC; |
|
683 |
|
684 } // namespace jit |
|
685 } // namespace js |
|
686 |
|
687 #endif // JS_ION |
|
688 |
|
689 #endif /* jit_JitFrameIterator_h */ |