Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
7 #include "jit/IonFrames-inl.h"
9 #include "jsfun.h"
10 #include "jsobj.h"
11 #include "jsscript.h"
13 #include "gc/Marking.h"
14 #include "jit/BaselineDebugModeOSR.h"
15 #include "jit/BaselineFrame.h"
16 #include "jit/BaselineIC.h"
17 #include "jit/BaselineJIT.h"
18 #include "jit/Ion.h"
19 #include "jit/IonMacroAssembler.h"
20 #include "jit/IonSpewer.h"
21 #include "jit/JitCompartment.h"
22 #include "jit/ParallelFunctions.h"
23 #include "jit/PcScriptCache.h"
24 #include "jit/Recover.h"
25 #include "jit/Safepoints.h"
26 #include "jit/Snapshots.h"
27 #include "jit/VMFunctions.h"
28 #include "vm/ArgumentsObject.h"
29 #include "vm/ForkJoin.h"
30 #include "vm/Interpreter.h"
32 #include "jsscriptinlines.h"
33 #include "jit/JitFrameIterator-inl.h"
34 #include "vm/Probes-inl.h"
36 namespace js {
37 namespace jit {
39 // Given a slot index, returns the offset, in bytes, of that slot from an
40 // IonJSFrameLayout. Slot distances are uniform across architectures, however,
41 // the distance does depend on the size of the frame header.
42 static inline int32_t
43 OffsetOfFrameSlot(int32_t slot)
44 {
45 return -slot;
46 }
48 static inline uintptr_t
49 ReadFrameSlot(IonJSFrameLayout *fp, int32_t slot)
50 {
51 return *(uintptr_t *)((char *)fp + OffsetOfFrameSlot(slot));
52 }
54 static inline double
55 ReadFrameDoubleSlot(IonJSFrameLayout *fp, int32_t slot)
56 {
57 return *(double *)((char *)fp + OffsetOfFrameSlot(slot));
58 }
60 static inline float
61 ReadFrameFloat32Slot(IonJSFrameLayout *fp, int32_t slot)
62 {
63 return *(float *)((char *)fp + OffsetOfFrameSlot(slot));
64 }
66 static inline int32_t
67 ReadFrameInt32Slot(IonJSFrameLayout *fp, int32_t slot)
68 {
69 return *(int32_t *)((char *)fp + OffsetOfFrameSlot(slot));
70 }
72 static inline bool
73 ReadFrameBooleanSlot(IonJSFrameLayout *fp, int32_t slot)
74 {
75 return *(bool *)((char *)fp + OffsetOfFrameSlot(slot));
76 }
78 JitFrameIterator::JitFrameIterator(JSContext *cx)
79 : current_(cx->mainThread().ionTop),
80 type_(JitFrame_Exit),
81 returnAddressToFp_(nullptr),
82 frameSize_(0),
83 cachedSafepointIndex_(nullptr),
84 activation_(nullptr),
85 mode_(SequentialExecution)
86 {
87 }
89 JitFrameIterator::JitFrameIterator(const ActivationIterator &activations)
90 : current_(activations.jitTop()),
91 type_(JitFrame_Exit),
92 returnAddressToFp_(nullptr),
93 frameSize_(0),
94 cachedSafepointIndex_(nullptr),
95 activation_(activations->asJit()),
96 mode_(SequentialExecution)
97 {
98 }
100 JitFrameIterator::JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode)
101 : current_((uint8_t *)fp),
102 type_(JitFrame_IonJS),
103 returnAddressToFp_(fp->returnAddress()),
104 frameSize_(fp->prevFrameLocalSize()),
105 mode_(mode)
106 {
107 }
109 bool
110 JitFrameIterator::checkInvalidation() const
111 {
112 IonScript *dummy;
113 return checkInvalidation(&dummy);
114 }
116 bool
117 JitFrameIterator::checkInvalidation(IonScript **ionScriptOut) const
118 {
119 uint8_t *returnAddr = returnAddressToFp();
120 JSScript *script = this->script();
121 // N.B. the current IonScript is not the same as the frame's
122 // IonScript if the frame has since been invalidated.
123 bool invalidated;
124 if (mode_ == ParallelExecution) {
125 // Parallel execution does not have invalidating bailouts.
126 invalidated = false;
127 } else {
128 invalidated = !script->hasIonScript() ||
129 !script->ionScript()->containsReturnAddress(returnAddr);
130 }
131 if (!invalidated)
132 return false;
134 int32_t invalidationDataOffset = ((int32_t *) returnAddr)[-1];
135 uint8_t *ionScriptDataOffset = returnAddr + invalidationDataOffset;
136 IonScript *ionScript = (IonScript *) Assembler::getPointer(ionScriptDataOffset);
137 JS_ASSERT(ionScript->containsReturnAddress(returnAddr));
138 *ionScriptOut = ionScript;
139 return true;
140 }
142 CalleeToken
143 JitFrameIterator::calleeToken() const
144 {
145 return ((IonJSFrameLayout *) current_)->calleeToken();
146 }
148 JSFunction *
149 JitFrameIterator::callee() const
150 {
151 JS_ASSERT(isScripted());
152 JS_ASSERT(isFunctionFrame());
153 return CalleeTokenToFunction(calleeToken());
154 }
156 JSFunction *
157 JitFrameIterator::maybeCallee() const
158 {
159 if (isScripted() && (isFunctionFrame()))
160 return callee();
161 return nullptr;
162 }
164 bool
165 JitFrameIterator::isNative() const
166 {
167 if (type_ != JitFrame_Exit || isFakeExitFrame())
168 return false;
169 return exitFrame()->footer()->jitCode() == nullptr;
170 }
172 bool
173 JitFrameIterator::isOOLNative() const
174 {
175 if (type_ != JitFrame_Exit)
176 return false;
177 return exitFrame()->footer()->jitCode() == ION_FRAME_OOL_NATIVE;
178 }
180 bool
181 JitFrameIterator::isOOLPropertyOp() const
182 {
183 if (type_ != JitFrame_Exit)
184 return false;
185 return exitFrame()->footer()->jitCode() == ION_FRAME_OOL_PROPERTY_OP;
186 }
188 bool
189 JitFrameIterator::isOOLProxy() const
190 {
191 if (type_ != JitFrame_Exit)
192 return false;
193 return exitFrame()->footer()->jitCode() == ION_FRAME_OOL_PROXY;
194 }
196 bool
197 JitFrameIterator::isDOMExit() const
198 {
199 if (type_ != JitFrame_Exit)
200 return false;
201 return exitFrame()->isDomExit();
202 }
204 bool
205 JitFrameIterator::isFunctionFrame() const
206 {
207 return CalleeTokenIsFunction(calleeToken());
208 }
210 JSScript *
211 JitFrameIterator::script() const
212 {
213 JS_ASSERT(isScripted());
214 if (isBaselineJS())
215 return baselineFrame()->script();
216 JSScript *script = ScriptFromCalleeToken(calleeToken());
217 JS_ASSERT(script);
218 return script;
219 }
221 void
222 JitFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) const
223 {
224 JS_ASSERT(isBaselineJS());
225 JSScript *script = this->script();
226 if (scriptRes)
227 *scriptRes = script;
228 uint8_t *retAddr = returnAddressToFp();
230 // If we are in the middle of a recompile handler, get the real return
231 // address as stashed in the RecompileInfo.
232 if (BaselineDebugModeOSRInfo *info = baselineFrame()->getDebugModeOSRInfo())
233 retAddr = info->resumeAddr;
235 if (pcRes) {
236 // If the return address is into the prologue entry address or just
237 // after the debug prologue, then assume start of script.
238 if (retAddr == script->baselineScript()->prologueEntryAddr() ||
239 retAddr == script->baselineScript()->postDebugPrologueAddr())
240 {
241 *pcRes = script->code();
242 return;
243 }
245 // The return address _may_ be a return from a callVM or IC chain call done for
246 // some op.
247 ICEntry *icEntry = script->baselineScript()->maybeICEntryFromReturnAddress(retAddr);
248 if (icEntry) {
249 *pcRes = icEntry->pc(script);
250 return;
251 }
253 // If not, the return address _must_ be the start address of an op, which can
254 // be computed from the pc mapping table.
255 *pcRes = script->baselineScript()->pcForReturnAddress(script, retAddr);
256 }
257 }
259 Value *
260 JitFrameIterator::actualArgs() const
261 {
262 return jsFrame()->argv() + 1;
263 }
265 static inline size_t
266 SizeOfFramePrefix(FrameType type)
267 {
268 switch (type) {
269 case JitFrame_Entry:
270 return IonEntryFrameLayout::Size();
271 case JitFrame_BaselineJS:
272 case JitFrame_IonJS:
273 case JitFrame_Unwound_IonJS:
274 return IonJSFrameLayout::Size();
275 case JitFrame_BaselineStub:
276 return IonBaselineStubFrameLayout::Size();
277 case JitFrame_Rectifier:
278 return IonRectifierFrameLayout::Size();
279 case JitFrame_Unwound_Rectifier:
280 return IonUnwoundRectifierFrameLayout::Size();
281 case JitFrame_Exit:
282 return IonExitFrameLayout::Size();
283 default:
284 MOZ_ASSUME_UNREACHABLE("unknown frame type");
285 }
286 }
288 uint8_t *
289 JitFrameIterator::prevFp() const
290 {
291 size_t currentSize = SizeOfFramePrefix(type_);
292 // This quick fix must be removed as soon as bug 717297 land. This is
293 // needed because the descriptor size of JS-to-JS frame which is just after
294 // a Rectifier frame should not change. (cf EnsureExitFrame function)
295 if (isFakeExitFrame()) {
296 JS_ASSERT(SizeOfFramePrefix(JitFrame_BaselineJS) ==
297 SizeOfFramePrefix(JitFrame_IonJS));
298 currentSize = SizeOfFramePrefix(JitFrame_IonJS);
299 }
300 currentSize += current()->prevFrameLocalSize();
301 return current_ + currentSize;
302 }
304 JitFrameIterator &
305 JitFrameIterator::operator++()
306 {
307 JS_ASSERT(type_ != JitFrame_Entry);
309 frameSize_ = prevFrameLocalSize();
310 cachedSafepointIndex_ = nullptr;
312 // If the next frame is the entry frame, just exit. Don't update current_,
313 // since the entry and first frames overlap.
314 if (current()->prevType() == JitFrame_Entry) {
315 type_ = JitFrame_Entry;
316 return *this;
317 }
319 // Note: prevFp() needs the current type, so set it after computing the
320 // next frame.
321 uint8_t *prev = prevFp();
322 type_ = current()->prevType();
323 if (type_ == JitFrame_Unwound_IonJS)
324 type_ = JitFrame_IonJS;
325 else if (type_ == JitFrame_Unwound_BaselineStub)
326 type_ = JitFrame_BaselineStub;
327 returnAddressToFp_ = current()->returnAddress();
328 current_ = prev;
329 return *this;
330 }
332 uintptr_t *
333 JitFrameIterator::spillBase() const
334 {
335 // Get the base address to where safepoint registers are spilled.
336 // Out-of-line calls do not unwind the extra padding space used to
337 // aggregate bailout tables, so we use frameSize instead of frameLocals,
338 // which would only account for local stack slots.
339 return reinterpret_cast<uintptr_t *>(fp() - ionScript()->frameSize());
340 }
342 MachineState
343 JitFrameIterator::machineState() const
344 {
345 SafepointReader reader(ionScript(), safepoint());
346 uintptr_t *spill = spillBase();
348 MachineState machine;
349 for (GeneralRegisterBackwardIterator iter(reader.allGprSpills()); iter.more(); iter++)
350 machine.setRegisterLocation(*iter, --spill);
352 double *floatSpill = reinterpret_cast<double *>(spill);
353 for (FloatRegisterBackwardIterator iter(reader.allFloatSpills()); iter.more(); iter++)
354 machine.setRegisterLocation(*iter, --floatSpill);
356 return machine;
357 }
359 static void
360 CloseLiveIterator(JSContext *cx, const InlineFrameIterator &frame, uint32_t localSlot)
361 {
362 SnapshotIterator si = frame.snapshotIterator();
364 // Skip stack slots until we reach the iterator object.
365 uint32_t base = CountArgSlots(frame.script(), frame.maybeCallee()) + frame.script()->nfixed();
366 uint32_t skipSlots = base + localSlot - 1;
368 for (unsigned i = 0; i < skipSlots; i++)
369 si.skip();
371 Value v = si.read();
372 RootedObject obj(cx, &v.toObject());
374 if (cx->isExceptionPending())
375 UnwindIteratorForException(cx, obj);
376 else
377 UnwindIteratorForUncatchableException(cx, obj);
378 }
380 static void
381 HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromException *rfe,
382 bool *overrecursed)
383 {
384 RootedScript script(cx, frame.script());
385 jsbytecode *pc = frame.pc();
387 bool bailedOutForDebugMode = false;
388 if (cx->compartment()->debugMode()) {
389 // If we have an exception from within Ion and the debugger is active,
390 // we do the following:
391 //
392 // 1. Bailout to baseline to reconstruct a baseline frame.
393 // 2. Resume immediately into the exception tail afterwards, and
394 // handle the exception again with the top frame now a baseline
395 // frame.
396 //
397 // An empty exception info denotes that we're propagating an Ion
398 // exception due to debug mode, which BailoutIonToBaseline needs to
399 // know. This is because we might not be able to fully reconstruct up
400 // to the stack depth at the snapshot, as we could've thrown in the
401 // middle of a call.
402 ExceptionBailoutInfo propagateInfo;
403 uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, propagateInfo, overrecursed);
404 bailedOutForDebugMode = retval == BAILOUT_RETURN_OK;
405 }
407 if (!script->hasTrynotes())
408 return;
410 JSTryNote *tn = script->trynotes()->vector;
411 JSTryNote *tnEnd = tn + script->trynotes()->length;
413 uint32_t pcOffset = uint32_t(pc - script->main());
414 for (; tn != tnEnd; ++tn) {
415 if (pcOffset < tn->start)
416 continue;
417 if (pcOffset >= tn->start + tn->length)
418 continue;
420 switch (tn->kind) {
421 case JSTRY_ITER: {
422 JS_ASSERT(JSOp(*(script->main() + tn->start + tn->length)) == JSOP_ENDITER);
423 JS_ASSERT(tn->stackDepth > 0);
425 uint32_t localSlot = tn->stackDepth;
426 CloseLiveIterator(cx, frame, localSlot);
427 break;
428 }
430 case JSTRY_LOOP:
431 break;
433 case JSTRY_CATCH:
434 if (cx->isExceptionPending() && !bailedOutForDebugMode) {
435 // Ion can compile try-catch, but bailing out to catch
436 // exceptions is slow. Reset the use count so that if we
437 // catch many exceptions we won't Ion-compile the script.
438 script->resetUseCount();
440 // Bailout at the start of the catch block.
441 jsbytecode *catchPC = script->main() + tn->start + tn->length;
442 ExceptionBailoutInfo excInfo(frame.frameNo(), catchPC, tn->stackDepth);
443 uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, excInfo, overrecursed);
444 if (retval == BAILOUT_RETURN_OK)
445 return;
447 // Error on bailout clears pending exception.
448 MOZ_ASSERT(!cx->isExceptionPending());
449 }
450 break;
452 default:
453 MOZ_ASSUME_UNREACHABLE("Unexpected try note");
454 }
455 }
456 }
458 static void
459 HandleExceptionBaseline(JSContext *cx, const JitFrameIterator &frame, ResumeFromException *rfe,
460 bool *calledDebugEpilogue)
461 {
462 JS_ASSERT(frame.isBaselineJS());
463 JS_ASSERT(!*calledDebugEpilogue);
465 RootedScript script(cx);
466 jsbytecode *pc;
467 frame.baselineScriptAndPc(script.address(), &pc);
469 if (cx->isExceptionPending() && cx->compartment()->debugMode()) {
470 BaselineFrame *baselineFrame = frame.baselineFrame();
471 JSTrapStatus status = DebugExceptionUnwind(cx, baselineFrame, pc);
472 switch (status) {
473 case JSTRAP_ERROR:
474 // Uncatchable exception.
475 JS_ASSERT(!cx->isExceptionPending());
476 break;
478 case JSTRAP_CONTINUE:
479 case JSTRAP_THROW:
480 JS_ASSERT(cx->isExceptionPending());
481 break;
483 case JSTRAP_RETURN:
484 JS_ASSERT(baselineFrame->hasReturnValue());
485 if (jit::DebugEpilogue(cx, baselineFrame, pc, true)) {
486 rfe->kind = ResumeFromException::RESUME_FORCED_RETURN;
487 rfe->framePointer = frame.fp() - BaselineFrame::FramePointerOffset;
488 rfe->stackPointer = reinterpret_cast<uint8_t *>(baselineFrame);
489 return;
490 }
492 // DebugEpilogue threw an exception. Propagate to the caller frame.
493 *calledDebugEpilogue = true;
494 return;
496 default:
497 MOZ_ASSUME_UNREACHABLE("Invalid trap status");
498 }
499 }
501 if (!script->hasTrynotes())
502 return;
504 JSTryNote *tn = script->trynotes()->vector;
505 JSTryNote *tnEnd = tn + script->trynotes()->length;
507 uint32_t pcOffset = uint32_t(pc - script->main());
508 ScopeIter si(frame.baselineFrame(), pc, cx);
509 for (; tn != tnEnd; ++tn) {
510 if (pcOffset < tn->start)
511 continue;
512 if (pcOffset >= tn->start + tn->length)
513 continue;
515 // Skip if the try note's stack depth exceeds the frame's stack depth.
516 // See the big comment in TryNoteIter::settle for more info.
517 JS_ASSERT(frame.baselineFrame()->numValueSlots() >= script->nfixed());
518 size_t stackDepth = frame.baselineFrame()->numValueSlots() - script->nfixed();
519 if (tn->stackDepth > stackDepth)
520 continue;
522 // Unwind scope chain (pop block objects).
523 if (cx->isExceptionPending())
524 UnwindScope(cx, si, script->main() + tn->start);
526 // Compute base pointer and stack pointer.
527 rfe->framePointer = frame.fp() - BaselineFrame::FramePointerOffset;
528 rfe->stackPointer = rfe->framePointer - BaselineFrame::Size() -
529 (script->nfixed() + tn->stackDepth) * sizeof(Value);
531 switch (tn->kind) {
532 case JSTRY_CATCH:
533 if (cx->isExceptionPending()) {
534 // Ion can compile try-catch, but bailing out to catch
535 // exceptions is slow. Reset the use count so that if we
536 // catch many exceptions we won't Ion-compile the script.
537 script->resetUseCount();
539 // Resume at the start of the catch block.
540 rfe->kind = ResumeFromException::RESUME_CATCH;
541 jsbytecode *catchPC = script->main() + tn->start + tn->length;
542 rfe->target = script->baselineScript()->nativeCodeForPC(script, catchPC);
543 return;
544 }
545 break;
547 case JSTRY_FINALLY:
548 if (cx->isExceptionPending()) {
549 rfe->kind = ResumeFromException::RESUME_FINALLY;
550 jsbytecode *finallyPC = script->main() + tn->start + tn->length;
551 rfe->target = script->baselineScript()->nativeCodeForPC(script, finallyPC);
552 // Drop the exception instead of leaking cross compartment data.
553 if (!cx->getPendingException(MutableHandleValue::fromMarkedLocation(&rfe->exception)))
554 rfe->exception = UndefinedValue();
555 cx->clearPendingException();
556 return;
557 }
558 break;
560 case JSTRY_ITER: {
561 Value iterValue(* (Value *) rfe->stackPointer);
562 RootedObject iterObject(cx, &iterValue.toObject());
563 if (cx->isExceptionPending())
564 UnwindIteratorForException(cx, iterObject);
565 else
566 UnwindIteratorForUncatchableException(cx, iterObject);
567 break;
568 }
570 case JSTRY_LOOP:
571 break;
573 default:
574 MOZ_ASSUME_UNREACHABLE("Invalid try note");
575 }
576 }
578 }
580 struct AutoDeleteDebugModeOSRInfo
581 {
582 BaselineFrame *frame;
583 AutoDeleteDebugModeOSRInfo(BaselineFrame *frame) : frame(frame) { MOZ_ASSERT(frame); }
584 ~AutoDeleteDebugModeOSRInfo() { frame->deleteDebugModeOSRInfo(); }
585 };
587 void
588 HandleException(ResumeFromException *rfe)
589 {
590 JSContext *cx = GetJSContextFromJitCode();
592 rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
594 IonSpew(IonSpew_Invalidate, "handling exception");
596 // Clear any Ion return override that's been set.
597 // This may happen if a callVM function causes an invalidation (setting the
598 // override), and then fails, bypassing the bailout handlers that would
599 // otherwise clear the return override.
600 if (cx->runtime()->hasIonReturnOverride())
601 cx->runtime()->takeIonReturnOverride();
603 JitFrameIterator iter(cx);
604 while (!iter.isEntry()) {
605 bool overrecursed = false;
606 if (iter.isIonJS()) {
607 // Search each inlined frame for live iterator objects, and close
608 // them.
609 InlineFrameIterator frames(cx, &iter);
611 // Invalidation state will be the same for all inlined scripts in the frame.
612 IonScript *ionScript = nullptr;
613 bool invalidated = iter.checkInvalidation(&ionScript);
615 for (;;) {
616 HandleExceptionIon(cx, frames, rfe, &overrecursed);
618 if (rfe->kind == ResumeFromException::RESUME_BAILOUT) {
619 if (invalidated)
620 ionScript->decref(cx->runtime()->defaultFreeOp());
621 return;
622 }
624 JS_ASSERT(rfe->kind == ResumeFromException::RESUME_ENTRY_FRAME);
626 // Figure out whether SPS frame was pushed for this frame or not.
627 // Even if profiler is enabled, the frame being popped might have
628 // been entered prior to SPS being enabled, and thus not have
629 // a pushed SPS frame.
630 bool popSPSFrame = cx->runtime()->spsProfiler.enabled();
631 if (invalidated)
632 popSPSFrame = ionScript->hasSPSInstrumentation();
634 // If inline-frames are not profiled, then don't pop an SPS frame
635 // for them.
636 if (frames.more() && !js_JitOptions.profileInlineFrames)
637 popSPSFrame = false;
639 // When profiling, each frame popped needs a notification that
640 // the function has exited, so invoke the probe that a function
641 // is exiting.
642 JSScript *script = frames.script();
643 probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
644 if (!frames.more())
645 break;
646 ++frames;
647 }
649 if (invalidated)
650 ionScript->decref(cx->runtime()->defaultFreeOp());
652 } else if (iter.isBaselineJS()) {
653 // It's invalid to call DebugEpilogue twice for the same frame.
654 bool calledDebugEpilogue = false;
656 HandleExceptionBaseline(cx, iter, rfe, &calledDebugEpilogue);
658 // If we are propagating an exception through a frame with
659 // on-stack recompile info, we should free the allocated
660 // RecompileInfo struct before we leave this block, as we will not
661 // be returning to the recompile handler.
662 //
663 // We cannot delete it immediately because of the call to
664 // iter.baselineScriptAndPc below.
665 AutoDeleteDebugModeOSRInfo deleteDebugModeOSRInfo(iter.baselineFrame());
667 if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME)
668 return;
670 // Unwind profiler pseudo-stack
671 JSScript *script = iter.script();
672 probes::ExitScript(cx, script, script->functionNonDelazifying(),
673 iter.baselineFrame()->hasPushedSPSFrame());
674 // After this point, any pushed SPS frame would have been popped if it needed
675 // to be. Unset the flag here so that if we call DebugEpilogue below,
676 // it doesn't try to pop the SPS frame again.
677 iter.baselineFrame()->unsetPushedSPSFrame();
679 if (cx->compartment()->debugMode() && !calledDebugEpilogue) {
680 // If DebugEpilogue returns |true|, we have to perform a forced
681 // return, e.g. return frame->returnValue() to the caller.
682 BaselineFrame *frame = iter.baselineFrame();
683 RootedScript script(cx);
684 jsbytecode *pc;
685 iter.baselineScriptAndPc(script.address(), &pc);
686 if (jit::DebugEpilogue(cx, frame, pc, false)) {
687 JS_ASSERT(frame->hasReturnValue());
688 rfe->kind = ResumeFromException::RESUME_FORCED_RETURN;
689 rfe->framePointer = iter.fp() - BaselineFrame::FramePointerOffset;
690 rfe->stackPointer = reinterpret_cast<uint8_t *>(frame);
691 return;
692 }
693 }
694 }
696 IonJSFrameLayout *current = iter.isScripted() ? iter.jsFrame() : nullptr;
698 ++iter;
700 if (current) {
701 // Unwind the frame by updating ionTop. This is necessary so that
702 // (1) debugger exception unwind and leave frame hooks don't see this
703 // frame when they use ScriptFrameIter, and (2) ScriptFrameIter does
704 // not crash when accessing an IonScript that's destroyed by the
705 // ionScript->decref call.
706 EnsureExitFrame(current);
707 cx->mainThread().ionTop = (uint8_t *)current;
708 }
710 if (overrecursed) {
711 // We hit an overrecursion error during bailout. Report it now.
712 js_ReportOverRecursed(cx);
713 }
714 }
716 rfe->stackPointer = iter.fp();
717 }
719 void
720 HandleParallelFailure(ResumeFromException *rfe)
721 {
722 ForkJoinContext *cx = ForkJoinContext::current();
723 JitFrameIterator iter(cx->perThreadData->ionTop, ParallelExecution);
725 parallel::Spew(parallel::SpewBailouts, "Bailing from VM reentry");
727 while (!iter.isEntry()) {
728 if (iter.isScripted()) {
729 cx->bailoutRecord->updateCause(ParallelBailoutUnsupportedVM,
730 iter.script(), iter.script(), nullptr);
731 break;
732 }
733 ++iter;
734 }
736 while (!iter.isEntry()) {
737 if (iter.isScripted())
738 PropagateAbortPar(iter.script(), iter.script());
739 ++iter;
740 }
742 rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
743 rfe->stackPointer = iter.fp();
744 }
746 void
747 EnsureExitFrame(IonCommonFrameLayout *frame)
748 {
749 if (frame->prevType() == JitFrame_Unwound_IonJS ||
750 frame->prevType() == JitFrame_Unwound_BaselineStub ||
751 frame->prevType() == JitFrame_Unwound_Rectifier)
752 {
753 // Already an exit frame, nothing to do.
754 return;
755 }
757 if (frame->prevType() == JitFrame_Entry) {
758 // The previous frame type is the entry frame, so there's no actual
759 // need for an exit frame.
760 return;
761 }
763 if (frame->prevType() == JitFrame_Rectifier) {
764 // The rectifier code uses the frame descriptor to discard its stack,
765 // so modifying its descriptor size here would be dangerous. Instead,
766 // we change the frame type, and teach the stack walking code how to
767 // deal with this edge case. bug 717297 would obviate the need
768 frame->changePrevType(JitFrame_Unwound_Rectifier);
769 return;
770 }
772 if (frame->prevType() == JitFrame_BaselineStub) {
773 frame->changePrevType(JitFrame_Unwound_BaselineStub);
774 return;
775 }
777 JS_ASSERT(frame->prevType() == JitFrame_IonJS);
778 frame->changePrevType(JitFrame_Unwound_IonJS);
779 }
781 CalleeToken
782 MarkCalleeToken(JSTracer *trc, CalleeToken token)
783 {
784 switch (GetCalleeTokenTag(token)) {
785 case CalleeToken_Function:
786 {
787 JSFunction *fun = CalleeTokenToFunction(token);
788 MarkObjectRoot(trc, &fun, "ion-callee");
789 return CalleeToToken(fun);
790 }
791 case CalleeToken_Script:
792 {
793 JSScript *script = CalleeTokenToScript(token);
794 MarkScriptRoot(trc, &script, "ion-entry");
795 return CalleeToToken(script);
796 }
797 default:
798 MOZ_ASSUME_UNREACHABLE("unknown callee token type");
799 }
800 }
802 #ifdef JS_NUNBOX32
803 static inline uintptr_t
804 ReadAllocation(const JitFrameIterator &frame, const LAllocation *a)
805 {
806 if (a->isGeneralReg()) {
807 Register reg = a->toGeneralReg()->reg();
808 return frame.machineState().read(reg);
809 }
810 if (a->isStackSlot()) {
811 uint32_t slot = a->toStackSlot()->slot();
812 return *frame.jsFrame()->slotRef(slot);
813 }
814 uint32_t index = a->toArgument()->index();
815 uint8_t *argv = reinterpret_cast<uint8_t *>(frame.jsFrame()->argv());
816 return *reinterpret_cast<uintptr_t *>(argv + index);
817 }
818 #endif
820 static void
821 MarkActualArguments(JSTracer *trc, const JitFrameIterator &frame)
822 {
823 IonJSFrameLayout *layout = frame.jsFrame();
824 JS_ASSERT(CalleeTokenIsFunction(layout->calleeToken()));
826 size_t nargs = frame.numActualArgs();
828 // Trace function arguments. Note + 1 for thisv.
829 Value *argv = layout->argv();
830 for (size_t i = 0; i < nargs + 1; i++)
831 gc::MarkValueRoot(trc, &argv[i], "ion-argv");
832 }
834 #ifdef JS_NUNBOX32
835 static inline void
836 WriteAllocation(const JitFrameIterator &frame, const LAllocation *a, uintptr_t value)
837 {
838 if (a->isGeneralReg()) {
839 Register reg = a->toGeneralReg()->reg();
840 frame.machineState().write(reg, value);
841 return;
842 }
843 if (a->isStackSlot()) {
844 uint32_t slot = a->toStackSlot()->slot();
845 *frame.jsFrame()->slotRef(slot) = value;
846 return;
847 }
848 uint32_t index = a->toArgument()->index();
849 uint8_t *argv = reinterpret_cast<uint8_t *>(frame.jsFrame()->argv());
850 *reinterpret_cast<uintptr_t *>(argv + index) = value;
851 }
852 #endif
854 static void
855 MarkIonJSFrame(JSTracer *trc, const JitFrameIterator &frame)
856 {
857 IonJSFrameLayout *layout = (IonJSFrameLayout *)frame.fp();
859 layout->replaceCalleeToken(MarkCalleeToken(trc, layout->calleeToken()));
861 IonScript *ionScript = nullptr;
862 if (frame.checkInvalidation(&ionScript)) {
863 // This frame has been invalidated, meaning that its IonScript is no
864 // longer reachable through the callee token (JSFunction/JSScript->ion
865 // is now nullptr or recompiled). Manually trace it here.
866 IonScript::Trace(trc, ionScript);
867 } else if (CalleeTokenIsFunction(layout->calleeToken())) {
868 ionScript = CalleeTokenToFunction(layout->calleeToken())->nonLazyScript()->ionScript();
869 } else {
870 ionScript = CalleeTokenToScript(layout->calleeToken())->ionScript();
871 }
873 if (CalleeTokenIsFunction(layout->calleeToken()))
874 MarkActualArguments(trc, frame);
876 const SafepointIndex *si = ionScript->getSafepointIndex(frame.returnAddressToFp());
878 SafepointReader safepoint(ionScript, si);
880 // Scan through slots which contain pointers (or on punboxing systems,
881 // actual values).
882 uint32_t slot;
883 while (safepoint.getGcSlot(&slot)) {
884 uintptr_t *ref = layout->slotRef(slot);
885 gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(ref), "ion-gc-slot");
886 }
888 while (safepoint.getValueSlot(&slot)) {
889 Value *v = (Value *)layout->slotRef(slot);
890 gc::MarkValueRoot(trc, v, "ion-gc-slot");
891 }
893 uintptr_t *spill = frame.spillBase();
894 GeneralRegisterSet gcRegs = safepoint.gcSpills();
895 GeneralRegisterSet valueRegs = safepoint.valueSpills();
896 for (GeneralRegisterBackwardIterator iter(safepoint.allGprSpills()); iter.more(); iter++) {
897 --spill;
898 if (gcRegs.has(*iter))
899 gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(spill), "ion-gc-spill");
900 else if (valueRegs.has(*iter))
901 gc::MarkValueRoot(trc, reinterpret_cast<Value *>(spill), "ion-value-spill");
902 }
904 #ifdef JS_NUNBOX32
905 LAllocation type, payload;
906 while (safepoint.getNunboxSlot(&type, &payload)) {
907 jsval_layout layout;
908 layout.s.tag = (JSValueTag)ReadAllocation(frame, &type);
909 layout.s.payload.uintptr = ReadAllocation(frame, &payload);
911 Value v = IMPL_TO_JSVAL(layout);
912 gc::MarkValueRoot(trc, &v, "ion-torn-value");
914 if (v != IMPL_TO_JSVAL(layout)) {
915 // GC moved the value, replace the stored payload.
916 layout = JSVAL_TO_IMPL(v);
917 WriteAllocation(frame, &payload, layout.s.payload.uintptr);
918 }
919 }
920 #endif
921 }
923 #ifdef JSGC_GENERATIONAL
924 static void
925 UpdateIonJSFrameForMinorGC(JSTracer *trc, const JitFrameIterator &frame)
926 {
927 // Minor GCs may move slots/elements allocated in the nursery. Update
928 // any slots/elements pointers stored in this frame.
930 IonJSFrameLayout *layout = (IonJSFrameLayout *)frame.fp();
932 IonScript *ionScript = nullptr;
933 if (frame.checkInvalidation(&ionScript)) {
934 // This frame has been invalidated, meaning that its IonScript is no
935 // longer reachable through the callee token (JSFunction/JSScript->ion
936 // is now nullptr or recompiled).
937 } else if (CalleeTokenIsFunction(layout->calleeToken())) {
938 ionScript = CalleeTokenToFunction(layout->calleeToken())->nonLazyScript()->ionScript();
939 } else {
940 ionScript = CalleeTokenToScript(layout->calleeToken())->ionScript();
941 }
943 const SafepointIndex *si = ionScript->getSafepointIndex(frame.returnAddressToFp());
944 SafepointReader safepoint(ionScript, si);
946 GeneralRegisterSet slotsRegs = safepoint.slotsOrElementsSpills();
947 uintptr_t *spill = frame.spillBase();
948 for (GeneralRegisterBackwardIterator iter(safepoint.allGprSpills()); iter.more(); iter++) {
949 --spill;
950 if (slotsRegs.has(*iter))
951 trc->runtime()->gcNursery.forwardBufferPointer(reinterpret_cast<HeapSlot **>(spill));
952 }
954 // Skip to the right place in the safepoint
955 uint32_t slot;
956 while (safepoint.getGcSlot(&slot));
957 while (safepoint.getValueSlot(&slot));
958 #ifdef JS_NUNBOX32
959 LAllocation type, payload;
960 while (safepoint.getNunboxSlot(&type, &payload));
961 #endif
963 while (safepoint.getSlotsOrElementsSlot(&slot)) {
964 HeapSlot **slots = reinterpret_cast<HeapSlot **>(layout->slotRef(slot));
965 trc->runtime()->gcNursery.forwardBufferPointer(slots);
966 }
967 }
968 #endif
970 static void
971 MarkBaselineStubFrame(JSTracer *trc, const JitFrameIterator &frame)
972 {
973 // Mark the ICStub pointer stored in the stub frame. This is necessary
974 // so that we don't destroy the stub code after unlinking the stub.
976 JS_ASSERT(frame.type() == JitFrame_BaselineStub);
977 IonBaselineStubFrameLayout *layout = (IonBaselineStubFrameLayout *)frame.fp();
979 if (ICStub *stub = layout->maybeStubPtr()) {
980 JS_ASSERT(ICStub::CanMakeCalls(stub->kind()));
981 stub->trace(trc);
982 }
983 }
985 void
986 JitActivationIterator::jitStackRange(uintptr_t *&min, uintptr_t *&end)
987 {
988 JitFrameIterator frames(jitTop(), SequentialExecution);
990 if (frames.isFakeExitFrame()) {
991 min = reinterpret_cast<uintptr_t *>(frames.fp());
992 } else {
993 IonExitFrameLayout *exitFrame = frames.exitFrame();
994 IonExitFooterFrame *footer = exitFrame->footer();
995 const VMFunction *f = footer->function();
996 if (exitFrame->isWrapperExit() && f->outParam == Type_Handle) {
997 switch (f->outParamRootType) {
998 case VMFunction::RootNone:
999 MOZ_ASSUME_UNREACHABLE("Handle outparam must have root type");
1000 case VMFunction::RootObject:
1001 case VMFunction::RootString:
1002 case VMFunction::RootPropertyName:
1003 case VMFunction::RootFunction:
1004 case VMFunction::RootCell:
1005 // These are all handles to GCThing pointers.
1006 min = reinterpret_cast<uintptr_t *>(footer->outParam<void *>());
1007 break;
1008 case VMFunction::RootValue:
1009 min = reinterpret_cast<uintptr_t *>(footer->outParam<Value>());
1010 break;
1011 }
1012 } else {
1013 min = reinterpret_cast<uintptr_t *>(footer);
1014 }
1015 }
1017 while (!frames.done())
1018 ++frames;
1020 end = reinterpret_cast<uintptr_t *>(frames.prevFp());
1021 }
1023 static void
1024 MarkJitExitFrame(JSTracer *trc, const JitFrameIterator &frame)
1025 {
1026 // Ignore fake exit frames created by EnsureExitFrame.
1027 if (frame.isFakeExitFrame())
1028 return;
1030 IonExitFooterFrame *footer = frame.exitFrame()->footer();
1032 // Mark the code of the code handling the exit path. This is needed because
1033 // invalidated script are no longer marked because data are erased by the
1034 // invalidation and relocation data are no longer reliable. So the VM
1035 // wrapper or the invalidation code may be GC if no JitCode keep reference
1036 // on them.
1037 JS_ASSERT(uintptr_t(footer->jitCode()) != uintptr_t(-1));
1039 // This correspond to the case where we have build a fake exit frame in
1040 // CodeGenerator.cpp which handle the case of a native function call. We
1041 // need to mark the argument vector of the function call.
1042 if (frame.isNative()) {
1043 IonNativeExitFrameLayout *native = frame.exitFrame()->nativeExit();
1044 size_t len = native->argc() + 2;
1045 Value *vp = native->vp();
1046 gc::MarkValueRootRange(trc, len, vp, "ion-native-args");
1047 return;
1048 }
1050 if (frame.isOOLNative()) {
1051 IonOOLNativeExitFrameLayout *oolnative = frame.exitFrame()->oolNativeExit();
1052 gc::MarkJitCodeRoot(trc, oolnative->stubCode(), "ion-ool-native-code");
1053 gc::MarkValueRoot(trc, oolnative->vp(), "iol-ool-native-vp");
1054 size_t len = oolnative->argc() + 1;
1055 gc::MarkValueRootRange(trc, len, oolnative->thisp(), "ion-ool-native-thisargs");
1056 return;
1057 }
1059 if (frame.isOOLPropertyOp()) {
1060 IonOOLPropertyOpExitFrameLayout *oolgetter = frame.exitFrame()->oolPropertyOpExit();
1061 gc::MarkJitCodeRoot(trc, oolgetter->stubCode(), "ion-ool-property-op-code");
1062 gc::MarkValueRoot(trc, oolgetter->vp(), "ion-ool-property-op-vp");
1063 gc::MarkIdRoot(trc, oolgetter->id(), "ion-ool-property-op-id");
1064 gc::MarkObjectRoot(trc, oolgetter->obj(), "ion-ool-property-op-obj");
1065 return;
1066 }
1068 if (frame.isOOLProxy()) {
1069 IonOOLProxyExitFrameLayout *oolproxy = frame.exitFrame()->oolProxyExit();
1070 gc::MarkJitCodeRoot(trc, oolproxy->stubCode(), "ion-ool-proxy-code");
1071 gc::MarkValueRoot(trc, oolproxy->vp(), "ion-ool-proxy-vp");
1072 gc::MarkIdRoot(trc, oolproxy->id(), "ion-ool-proxy-id");
1073 gc::MarkObjectRoot(trc, oolproxy->proxy(), "ion-ool-proxy-proxy");
1074 gc::MarkObjectRoot(trc, oolproxy->receiver(), "ion-ool-proxy-receiver");
1075 return;
1076 }
1078 if (frame.isDOMExit()) {
1079 IonDOMExitFrameLayout *dom = frame.exitFrame()->DOMExit();
1080 gc::MarkObjectRoot(trc, dom->thisObjAddress(), "ion-dom-args");
1081 if (dom->isMethodFrame()) {
1082 IonDOMMethodExitFrameLayout *method =
1083 reinterpret_cast<IonDOMMethodExitFrameLayout *>(dom);
1084 size_t len = method->argc() + 2;
1085 Value *vp = method->vp();
1086 gc::MarkValueRootRange(trc, len, vp, "ion-dom-args");
1087 } else {
1088 gc::MarkValueRoot(trc, dom->vp(), "ion-dom-args");
1089 }
1090 return;
1091 }
1093 MarkJitCodeRoot(trc, footer->addressOfJitCode(), "ion-exit-code");
1095 const VMFunction *f = footer->function();
1096 if (f == nullptr)
1097 return;
1099 // Mark arguments of the VM wrapper.
1100 uint8_t *argBase = frame.exitFrame()->argBase();
1101 for (uint32_t explicitArg = 0; explicitArg < f->explicitArgs; explicitArg++) {
1102 switch (f->argRootType(explicitArg)) {
1103 case VMFunction::RootNone:
1104 break;
1105 case VMFunction::RootObject: {
1106 // Sometimes we can bake in HandleObjects to nullptr.
1107 JSObject **pobj = reinterpret_cast<JSObject **>(argBase);
1108 if (*pobj)
1109 gc::MarkObjectRoot(trc, pobj, "ion-vm-args");
1110 break;
1111 }
1112 case VMFunction::RootString:
1113 case VMFunction::RootPropertyName:
1114 gc::MarkStringRoot(trc, reinterpret_cast<JSString**>(argBase), "ion-vm-args");
1115 break;
1116 case VMFunction::RootFunction:
1117 gc::MarkObjectRoot(trc, reinterpret_cast<JSFunction**>(argBase), "ion-vm-args");
1118 break;
1119 case VMFunction::RootValue:
1120 gc::MarkValueRoot(trc, reinterpret_cast<Value*>(argBase), "ion-vm-args");
1121 break;
1122 case VMFunction::RootCell:
1123 gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(argBase), "ion-vm-args");
1124 break;
1125 }
1127 switch (f->argProperties(explicitArg)) {
1128 case VMFunction::WordByValue:
1129 case VMFunction::WordByRef:
1130 argBase += sizeof(void *);
1131 break;
1132 case VMFunction::DoubleByValue:
1133 case VMFunction::DoubleByRef:
1134 argBase += 2 * sizeof(void *);
1135 break;
1136 }
1137 }
1139 if (f->outParam == Type_Handle) {
1140 switch (f->outParamRootType) {
1141 case VMFunction::RootNone:
1142 MOZ_ASSUME_UNREACHABLE("Handle outparam must have root type");
1143 case VMFunction::RootObject:
1144 gc::MarkObjectRoot(trc, footer->outParam<JSObject *>(), "ion-vm-out");
1145 break;
1146 case VMFunction::RootString:
1147 case VMFunction::RootPropertyName:
1148 gc::MarkStringRoot(trc, footer->outParam<JSString *>(), "ion-vm-out");
1149 break;
1150 case VMFunction::RootFunction:
1151 gc::MarkObjectRoot(trc, footer->outParam<JSFunction *>(), "ion-vm-out");
1152 break;
1153 case VMFunction::RootValue:
1154 gc::MarkValueRoot(trc, footer->outParam<Value>(), "ion-vm-outvp");
1155 break;
1156 case VMFunction::RootCell:
1157 gc::MarkGCThingRoot(trc, footer->outParam<void *>(), "ion-vm-out");
1158 break;
1159 }
1160 }
1161 }
1163 static void
1164 MarkRectifierFrame(JSTracer *trc, const JitFrameIterator &frame)
1165 {
1166 // Mark thisv.
1167 //
1168 // Baseline JIT code generated as part of the ICCall_Fallback stub may use
1169 // it if we're calling a constructor that returns a primitive value.
1170 IonRectifierFrameLayout *layout = (IonRectifierFrameLayout *)frame.fp();
1171 gc::MarkValueRoot(trc, &layout->argv()[0], "ion-thisv");
1172 }
1174 static void
1175 MarkJitActivation(JSTracer *trc, const JitActivationIterator &activations)
1176 {
1177 JitActivation *activation = activations->asJit();
1179 #ifdef CHECK_OSIPOINT_REGISTERS
1180 if (js_JitOptions.checkOsiPointRegisters) {
1181 // GC can modify spilled registers, breaking our register checks.
1182 // To handle this, we disable these checks for the current VM call
1183 // when a GC happens.
1184 activation->setCheckRegs(false);
1185 }
1186 #endif
1188 activation->markRematerializedFrames(trc);
1190 for (JitFrameIterator frames(activations); !frames.done(); ++frames) {
1191 switch (frames.type()) {
1192 case JitFrame_Exit:
1193 MarkJitExitFrame(trc, frames);
1194 break;
1195 case JitFrame_BaselineJS:
1196 frames.baselineFrame()->trace(trc, frames);
1197 break;
1198 case JitFrame_BaselineStub:
1199 MarkBaselineStubFrame(trc, frames);
1200 break;
1201 case JitFrame_IonJS:
1202 MarkIonJSFrame(trc, frames);
1203 break;
1204 case JitFrame_Unwound_IonJS:
1205 MOZ_ASSUME_UNREACHABLE("invalid");
1206 case JitFrame_Rectifier:
1207 MarkRectifierFrame(trc, frames);
1208 break;
1209 case JitFrame_Unwound_Rectifier:
1210 break;
1211 default:
1212 MOZ_ASSUME_UNREACHABLE("unexpected frame type");
1213 }
1214 }
1215 }
1217 void
1218 MarkJitActivations(JSRuntime *rt, JSTracer *trc)
1219 {
1220 for (JitActivationIterator activations(rt); !activations.done(); ++activations)
1221 MarkJitActivation(trc, activations);
1222 }
1224 #ifdef JSGC_GENERATIONAL
1225 void
1226 UpdateJitActivationsForMinorGC(JSRuntime *rt, JSTracer *trc)
1227 {
1228 JS_ASSERT(trc->runtime()->isHeapMinorCollecting());
1229 for (JitActivationIterator activations(rt); !activations.done(); ++activations) {
1230 for (JitFrameIterator frames(activations); !frames.done(); ++frames) {
1231 if (frames.type() == JitFrame_IonJS)
1232 UpdateIonJSFrameForMinorGC(trc, frames);
1233 }
1234 }
1235 }
1236 #endif
1238 void
1239 AutoTempAllocatorRooter::trace(JSTracer *trc)
1240 {
1241 for (CompilerRootNode *root = temp->rootList(); root != nullptr; root = root->next)
1242 gc::MarkGCThingRoot(trc, root->address(), "ion-compiler-root");
1243 }
1245 void
1246 GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
1247 {
1248 IonSpew(IonSpew_Snapshots, "Recover PC & Script from the last frame.");
1250 JSRuntime *rt = cx->runtime();
1252 // Recover the return address.
1253 JitFrameIterator it(rt->mainThread.ionTop, SequentialExecution);
1255 // If the previous frame is a rectifier frame (maybe unwound),
1256 // skip past it.
1257 if (it.prevType() == JitFrame_Rectifier || it.prevType() == JitFrame_Unwound_Rectifier) {
1258 ++it;
1259 JS_ASSERT(it.prevType() == JitFrame_BaselineStub ||
1260 it.prevType() == JitFrame_BaselineJS ||
1261 it.prevType() == JitFrame_IonJS);
1262 }
1264 // If the previous frame is a stub frame, skip the exit frame so that
1265 // returnAddress below gets the return address into the BaselineJS
1266 // frame.
1267 if (it.prevType() == JitFrame_BaselineStub || it.prevType() == JitFrame_Unwound_BaselineStub) {
1268 ++it;
1269 JS_ASSERT(it.prevType() == JitFrame_BaselineJS);
1270 }
1272 uint8_t *retAddr = it.returnAddress();
1273 uint32_t hash = PcScriptCache::Hash(retAddr);
1274 JS_ASSERT(retAddr != nullptr);
1276 // Lazily initialize the cache. The allocation may safely fail and will not GC.
1277 if (MOZ_UNLIKELY(rt->ionPcScriptCache == nullptr)) {
1278 rt->ionPcScriptCache = (PcScriptCache *)js_malloc(sizeof(struct PcScriptCache));
1279 if (rt->ionPcScriptCache)
1280 rt->ionPcScriptCache->clear(rt->gcNumber);
1281 }
1283 // Attempt to lookup address in cache.
1284 if (rt->ionPcScriptCache && rt->ionPcScriptCache->get(rt, hash, retAddr, scriptRes, pcRes))
1285 return;
1287 // Lookup failed: undertake expensive process to recover the innermost inlined frame.
1288 ++it; // Skip exit frame.
1289 jsbytecode *pc = nullptr;
1291 if (it.isIonJS()) {
1292 InlineFrameIterator ifi(cx, &it);
1293 *scriptRes = ifi.script();
1294 pc = ifi.pc();
1295 } else {
1296 JS_ASSERT(it.isBaselineJS());
1297 it.baselineScriptAndPc(scriptRes, &pc);
1298 }
1300 if (pcRes)
1301 *pcRes = pc;
1303 // Add entry to cache.
1304 if (rt->ionPcScriptCache)
1305 rt->ionPcScriptCache->add(hash, retAddr, pc, *scriptRes);
1306 }
1308 void
1309 OsiIndex::fixUpOffset(MacroAssembler &masm)
1310 {
1311 callPointDisplacement_ = masm.actualOffset(callPointDisplacement_);
1312 }
1314 uint32_t
1315 OsiIndex::returnPointDisplacement() const
1316 {
1317 // In general, pointer arithmetic on code is bad, but in this case,
1318 // getting the return address from a call instruction, stepping over pools
1319 // would be wrong.
1320 return callPointDisplacement_ + Assembler::patchWrite_NearCallSize();
1321 }
1323 SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset,
1324 IonJSFrameLayout *fp, const MachineState &machine)
1325 : snapshot_(ionScript->snapshots(),
1326 snapshotOffset,
1327 ionScript->snapshotsRVATableSize(),
1328 ionScript->snapshotsListSize()),
1329 recover_(snapshot_,
1330 ionScript->recovers(),
1331 ionScript->recoversSize()),
1332 fp_(fp),
1333 machine_(machine),
1334 ionScript_(ionScript)
1335 {
1336 JS_ASSERT(snapshotOffset < ionScript->snapshotsListSize());
1337 }
1339 SnapshotIterator::SnapshotIterator(const JitFrameIterator &iter)
1340 : snapshot_(iter.ionScript()->snapshots(),
1341 iter.osiIndex()->snapshotOffset(),
1342 iter.ionScript()->snapshotsRVATableSize(),
1343 iter.ionScript()->snapshotsListSize()),
1344 recover_(snapshot_,
1345 iter.ionScript()->recovers(),
1346 iter.ionScript()->recoversSize()),
1347 fp_(iter.jsFrame()),
1348 machine_(iter.machineState()),
1349 ionScript_(iter.ionScript())
1350 {
1351 }
1353 SnapshotIterator::SnapshotIterator()
1354 : snapshot_(nullptr, 0, 0, 0),
1355 recover_(snapshot_, nullptr, 0),
1356 fp_(nullptr),
1357 ionScript_(nullptr)
1358 {
1359 }
1361 uintptr_t
1362 SnapshotIterator::fromStack(int32_t offset) const
1363 {
1364 return ReadFrameSlot(fp_, offset);
1365 }
1367 static Value
1368 FromObjectPayload(uintptr_t payload)
1369 {
1370 return ObjectValue(*reinterpret_cast<JSObject *>(payload));
1371 }
1373 static Value
1374 FromStringPayload(uintptr_t payload)
1375 {
1376 return StringValue(reinterpret_cast<JSString *>(payload));
1377 }
1379 static Value
1380 FromTypedPayload(JSValueType type, uintptr_t payload)
1381 {
1382 switch (type) {
1383 case JSVAL_TYPE_INT32:
1384 return Int32Value(payload);
1385 case JSVAL_TYPE_BOOLEAN:
1386 return BooleanValue(!!payload);
1387 case JSVAL_TYPE_STRING:
1388 return FromStringPayload(payload);
1389 case JSVAL_TYPE_OBJECT:
1390 return FromObjectPayload(payload);
1391 default:
1392 MOZ_ASSUME_UNREACHABLE("unexpected type - needs payload");
1393 }
1394 }
1396 bool
1397 SnapshotIterator::allocationReadable(const RValueAllocation &alloc)
1398 {
1399 switch (alloc.mode()) {
1400 case RValueAllocation::DOUBLE_REG:
1401 return hasRegister(alloc.fpuReg());
1403 case RValueAllocation::TYPED_REG:
1404 return hasRegister(alloc.reg2());
1406 #if defined(JS_NUNBOX32)
1407 case RValueAllocation::UNTYPED_REG_REG:
1408 return hasRegister(alloc.reg()) && hasRegister(alloc.reg2());
1409 case RValueAllocation::UNTYPED_REG_STACK:
1410 return hasRegister(alloc.reg()) && hasStack(alloc.stackOffset2());
1411 case RValueAllocation::UNTYPED_STACK_REG:
1412 return hasStack(alloc.stackOffset()) && hasRegister(alloc.reg2());
1413 case RValueAllocation::UNTYPED_STACK_STACK:
1414 return hasStack(alloc.stackOffset()) && hasStack(alloc.stackOffset2());
1415 #elif defined(JS_PUNBOX64)
1416 case RValueAllocation::UNTYPED_REG:
1417 return hasRegister(alloc.reg());
1418 case RValueAllocation::UNTYPED_STACK:
1419 return hasStack(alloc.stackOffset());
1420 #endif
1422 default:
1423 return true;
1424 }
1425 }
1427 Value
1428 SnapshotIterator::allocationValue(const RValueAllocation &alloc)
1429 {
1430 switch (alloc.mode()) {
1431 case RValueAllocation::CONSTANT:
1432 return ionScript_->getConstant(alloc.index());
1434 case RValueAllocation::CST_UNDEFINED:
1435 return UndefinedValue();
1437 case RValueAllocation::CST_NULL:
1438 return NullValue();
1440 case RValueAllocation::DOUBLE_REG:
1441 return DoubleValue(fromRegister(alloc.fpuReg()));
1443 case RValueAllocation::FLOAT32_REG:
1444 {
1445 union {
1446 double d;
1447 float f;
1448 } pun;
1449 pun.d = fromRegister(alloc.fpuReg());
1450 // The register contains the encoding of a float32. We just read
1451 // the bits without making any conversion.
1452 return Float32Value(pun.f);
1453 }
1455 case RValueAllocation::FLOAT32_STACK:
1456 return Float32Value(ReadFrameFloat32Slot(fp_, alloc.stackOffset()));
1458 case RValueAllocation::TYPED_REG:
1459 return FromTypedPayload(alloc.knownType(), fromRegister(alloc.reg2()));
1461 case RValueAllocation::TYPED_STACK:
1462 {
1463 switch (alloc.knownType()) {
1464 case JSVAL_TYPE_DOUBLE:
1465 return DoubleValue(ReadFrameDoubleSlot(fp_, alloc.stackOffset2()));
1466 case JSVAL_TYPE_INT32:
1467 return Int32Value(ReadFrameInt32Slot(fp_, alloc.stackOffset2()));
1468 case JSVAL_TYPE_BOOLEAN:
1469 return BooleanValue(ReadFrameBooleanSlot(fp_, alloc.stackOffset2()));
1470 case JSVAL_TYPE_STRING:
1471 return FromStringPayload(fromStack(alloc.stackOffset2()));
1472 case JSVAL_TYPE_OBJECT:
1473 return FromObjectPayload(fromStack(alloc.stackOffset2()));
1474 default:
1475 MOZ_ASSUME_UNREACHABLE("Unexpected type");
1476 }
1477 }
1479 #if defined(JS_NUNBOX32)
1480 case RValueAllocation::UNTYPED_REG_REG:
1481 {
1482 jsval_layout layout;
1483 layout.s.tag = (JSValueTag) fromRegister(alloc.reg());
1484 layout.s.payload.word = fromRegister(alloc.reg2());
1485 return IMPL_TO_JSVAL(layout);
1486 }
1488 case RValueAllocation::UNTYPED_REG_STACK:
1489 {
1490 jsval_layout layout;
1491 layout.s.tag = (JSValueTag) fromRegister(alloc.reg());
1492 layout.s.payload.word = fromStack(alloc.stackOffset2());
1493 return IMPL_TO_JSVAL(layout);
1494 }
1496 case RValueAllocation::UNTYPED_STACK_REG:
1497 {
1498 jsval_layout layout;
1499 layout.s.tag = (JSValueTag) fromStack(alloc.stackOffset());
1500 layout.s.payload.word = fromRegister(alloc.reg2());
1501 return IMPL_TO_JSVAL(layout);
1502 }
1504 case RValueAllocation::UNTYPED_STACK_STACK:
1505 {
1506 jsval_layout layout;
1507 layout.s.tag = (JSValueTag) fromStack(alloc.stackOffset());
1508 layout.s.payload.word = fromStack(alloc.stackOffset2());
1509 return IMPL_TO_JSVAL(layout);
1510 }
1511 #elif defined(JS_PUNBOX64)
1512 case RValueAllocation::UNTYPED_REG:
1513 {
1514 jsval_layout layout;
1515 layout.asBits = fromRegister(alloc.reg());
1516 return IMPL_TO_JSVAL(layout);
1517 }
1519 case RValueAllocation::UNTYPED_STACK:
1520 {
1521 jsval_layout layout;
1522 layout.asBits = fromStack(alloc.stackOffset());
1523 return IMPL_TO_JSVAL(layout);
1524 }
1525 #endif
1527 default:
1528 MOZ_ASSUME_UNREACHABLE("huh?");
1529 }
1530 }
1532 const RResumePoint *
1533 SnapshotIterator::resumePoint() const
1534 {
1535 return instruction()->toResumePoint();
1536 }
1538 uint32_t
1539 SnapshotIterator::numAllocations() const
1540 {
1541 return resumePoint()->numOperands();
1542 }
1544 uint32_t
1545 SnapshotIterator::pcOffset() const
1546 {
1547 return resumePoint()->pcOffset();
1548 }
1550 void
1551 SnapshotIterator::skipInstruction()
1552 {
1553 MOZ_ASSERT(snapshot_.numAllocationsRead() == 0);
1554 size_t numOperands = instruction()->numOperands();
1555 for (size_t i = 0; i < numOperands; i++)
1556 skip();
1557 nextInstruction();
1558 }
1560 void
1561 SnapshotIterator::nextFrame()
1562 {
1563 nextInstruction();
1564 while (!instruction()->isResumePoint())
1565 skipInstruction();
1566 }
1568 IonScript *
1569 JitFrameIterator::ionScript() const
1570 {
1571 JS_ASSERT(type() == JitFrame_IonJS);
1573 IonScript *ionScript = nullptr;
1574 if (checkInvalidation(&ionScript))
1575 return ionScript;
1576 switch (GetCalleeTokenTag(calleeToken())) {
1577 case CalleeToken_Function:
1578 case CalleeToken_Script:
1579 return mode_ == ParallelExecution ? script()->parallelIonScript() : script()->ionScript();
1580 default:
1581 MOZ_ASSUME_UNREACHABLE("unknown callee token type");
1582 }
1583 }
1585 const SafepointIndex *
1586 JitFrameIterator::safepoint() const
1587 {
1588 if (!cachedSafepointIndex_)
1589 cachedSafepointIndex_ = ionScript()->getSafepointIndex(returnAddressToFp());
1590 return cachedSafepointIndex_;
1591 }
1593 const OsiIndex *
1594 JitFrameIterator::osiIndex() const
1595 {
1596 SafepointReader reader(ionScript(), safepoint());
1597 return ionScript()->getOsiIndex(reader.osiReturnPointOffset());
1598 }
1600 template <AllowGC allowGC>
1601 void
1602 InlineFrameIteratorMaybeGC<allowGC>::resetOn(const JitFrameIterator *iter)
1603 {
1604 frame_ = iter;
1605 framesRead_ = 0;
1606 frameCount_ = UINT32_MAX;
1608 if (iter) {
1609 start_ = SnapshotIterator(*iter);
1610 findNextFrame();
1611 }
1612 }
1613 template void InlineFrameIteratorMaybeGC<NoGC>::resetOn(const JitFrameIterator *iter);
1614 template void InlineFrameIteratorMaybeGC<CanGC>::resetOn(const JitFrameIterator *iter);
1616 template <AllowGC allowGC>
1617 void
1618 InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
1619 {
1620 JS_ASSERT(more());
1622 si_ = start_;
1624 // Read the initial frame out of the C stack.
1625 callee_ = frame_->maybeCallee();
1626 script_ = frame_->script();
1627 MOZ_ASSERT(script_->hasBaselineScript());
1629 // Settle on the outermost frame without evaluating any instructions before
1630 // looking for a pc.
1631 if (!si_.instruction()->isResumePoint())
1632 si_.nextFrame();
1634 pc_ = script_->offsetToPC(si_.pcOffset());
1635 #ifdef DEBUG
1636 numActualArgs_ = 0xbadbad;
1637 #endif
1639 // This unfortunately is O(n*m), because we must skip over outer frames
1640 // before reading inner ones.
1642 // The first time (frameCount_ == UINT32_MAX) we do not know the number of
1643 // frames that we are going to inspect. So we are iterating until there is
1644 // no more frames, to settle on the inner most frame and to count the number
1645 // of frames.
1646 size_t remaining = (frameCount_ != UINT32_MAX) ? frameNo() - 1 : SIZE_MAX;
1648 size_t i = 1;
1649 for (; i <= remaining && si_.moreFrames(); i++) {
1650 JS_ASSERT(IsIonInlinablePC(pc_));
1652 // Recover the number of actual arguments from the script.
1653 if (JSOp(*pc_) != JSOP_FUNAPPLY)
1654 numActualArgs_ = GET_ARGC(pc_);
1655 if (JSOp(*pc_) == JSOP_FUNCALL) {
1656 JS_ASSERT(GET_ARGC(pc_) > 0);
1657 numActualArgs_ = GET_ARGC(pc_) - 1;
1658 } else if (IsGetPropPC(pc_)) {
1659 numActualArgs_ = 0;
1660 } else if (IsSetPropPC(pc_)) {
1661 numActualArgs_ = 1;
1662 }
1664 JS_ASSERT(numActualArgs_ != 0xbadbad);
1666 // Skip over non-argument slots, as well as |this|.
1667 unsigned skipCount = (si_.numAllocations() - 1) - numActualArgs_ - 1;
1668 for (unsigned j = 0; j < skipCount; j++)
1669 si_.skip();
1671 // The JSFunction is a constant, otherwise we would not have inlined it.
1672 Value funval = si_.read();
1674 // Skip extra value allocations.
1675 while (si_.moreAllocations())
1676 si_.skip();
1678 si_.nextFrame();
1680 callee_ = &funval.toObject().as<JSFunction>();
1682 // Inlined functions may be clones that still point to the lazy script
1683 // for the executed script, if they are clones. The actual script
1684 // exists though, just make sure the function points to it.
1685 script_ = callee_->existingScriptForInlinedFunction();
1686 MOZ_ASSERT(script_->hasBaselineScript());
1688 pc_ = script_->offsetToPC(si_.pcOffset());
1689 }
1691 // The first time we do not know the number of frames, we only settle on the
1692 // last frame, and update the number of frames based on the number of
1693 // iteration that we have done.
1694 if (frameCount_ == UINT32_MAX) {
1695 MOZ_ASSERT(!si_.moreFrames());
1696 frameCount_ = i;
1697 }
1699 framesRead_++;
1700 }
1701 template void InlineFrameIteratorMaybeGC<NoGC>::findNextFrame();
1702 template void InlineFrameIteratorMaybeGC<CanGC>::findNextFrame();
1704 template <AllowGC allowGC>
1705 bool
1706 InlineFrameIteratorMaybeGC<allowGC>::isFunctionFrame() const
1707 {
1708 return !!callee_;
1709 }
1710 template bool InlineFrameIteratorMaybeGC<NoGC>::isFunctionFrame() const;
1711 template bool InlineFrameIteratorMaybeGC<CanGC>::isFunctionFrame() const;
1713 MachineState
1714 MachineState::FromBailout(mozilla::Array<uintptr_t, Registers::Total> ®s,
1715 mozilla::Array<double, FloatRegisters::Total> &fpregs)
1716 {
1717 MachineState machine;
1719 for (unsigned i = 0; i < Registers::Total; i++)
1720 machine.setRegisterLocation(Register::FromCode(i), ®s[i]);
1721 for (unsigned i = 0; i < FloatRegisters::Total; i++)
1722 machine.setRegisterLocation(FloatRegister::FromCode(i), &fpregs[i]);
1724 return machine;
1725 }
1727 template <AllowGC allowGC>
1728 bool
1729 InlineFrameIteratorMaybeGC<allowGC>::isConstructing() const
1730 {
1731 // Skip the current frame and look at the caller's.
1732 if (more()) {
1733 InlineFrameIteratorMaybeGC<allowGC> parent(GetJSContextFromJitCode(), this);
1734 ++parent;
1736 // Inlined Getters and Setters are never constructing.
1737 if (IsGetPropPC(parent.pc()) || IsSetPropPC(parent.pc()))
1738 return false;
1740 // In the case of a JS frame, look up the pc from the snapshot.
1741 JS_ASSERT(IsCallPC(parent.pc()));
1743 return (JSOp)*parent.pc() == JSOP_NEW;
1744 }
1746 return frame_->isConstructing();
1747 }
1748 template bool InlineFrameIteratorMaybeGC<NoGC>::isConstructing() const;
1749 template bool InlineFrameIteratorMaybeGC<CanGC>::isConstructing() const;
1751 bool
1752 JitFrameIterator::isConstructing() const
1753 {
1754 JitFrameIterator parent(*this);
1756 // Skip the current frame and look at the caller's.
1757 do {
1758 ++parent;
1759 } while (!parent.done() && !parent.isScripted());
1761 if (parent.isIonJS()) {
1762 // In the case of a JS frame, look up the pc from the snapshot.
1763 InlineFrameIterator inlinedParent(GetJSContextFromJitCode(), &parent);
1765 //Inlined Getters and Setters are never constructing.
1766 if (IsGetPropPC(inlinedParent.pc()) || IsSetPropPC(inlinedParent.pc()))
1767 return false;
1769 JS_ASSERT(IsCallPC(inlinedParent.pc()));
1771 return (JSOp)*inlinedParent.pc() == JSOP_NEW;
1772 }
1774 if (parent.isBaselineJS()) {
1775 jsbytecode *pc;
1776 parent.baselineScriptAndPc(nullptr, &pc);
1778 // Inlined Getters and Setters are never constructing.
1779 // Baseline may call getters from [GET|SET]PROP or [GET|SET]ELEM ops.
1780 if (IsGetPropPC(pc) || IsSetPropPC(pc) || IsGetElemPC(pc) || IsSetElemPC(pc))
1781 return false;
1783 JS_ASSERT(IsCallPC(pc));
1785 return JSOp(*pc) == JSOP_NEW;
1786 }
1788 JS_ASSERT(parent.done());
1789 return activation_->firstFrameIsConstructing();
1790 }
1792 unsigned
1793 JitFrameIterator::numActualArgs() const
1794 {
1795 if (isScripted())
1796 return jsFrame()->numActualArgs();
1798 JS_ASSERT(isNative());
1799 return exitFrame()->nativeExit()->argc();
1800 }
1802 void
1803 SnapshotIterator::warnUnreadableAllocation()
1804 {
1805 fprintf(stderr, "Warning! Tried to access unreadable value allocation (possible f.arguments).\n");
1806 }
1808 struct DumpOp {
1809 DumpOp(unsigned int i) : i_(i) {}
1811 unsigned int i_;
1812 void operator()(const Value& v) {
1813 fprintf(stderr, " actual (arg %d): ", i_);
1814 #ifdef DEBUG
1815 js_DumpValue(v);
1816 #else
1817 fprintf(stderr, "?\n");
1818 #endif
1819 i_++;
1820 }
1821 };
1823 void
1824 JitFrameIterator::dumpBaseline() const
1825 {
1826 JS_ASSERT(isBaselineJS());
1828 fprintf(stderr, " JS Baseline frame\n");
1829 if (isFunctionFrame()) {
1830 fprintf(stderr, " callee fun: ");
1831 #ifdef DEBUG
1832 js_DumpObject(callee());
1833 #else
1834 fprintf(stderr, "?\n");
1835 #endif
1836 } else {
1837 fprintf(stderr, " global frame, no callee\n");
1838 }
1840 fprintf(stderr, " file %s line %u\n",
1841 script()->filename(), (unsigned) script()->lineno());
1843 JSContext *cx = GetJSContextFromJitCode();
1844 RootedScript script(cx);
1845 jsbytecode *pc;
1846 baselineScriptAndPc(script.address(), &pc);
1848 fprintf(stderr, " script = %p, pc = %p (offset %u)\n", (void *)script, pc, uint32_t(script->pcToOffset(pc)));
1849 fprintf(stderr, " current op: %s\n", js_CodeName[*pc]);
1851 fprintf(stderr, " actual args: %d\n", numActualArgs());
1853 BaselineFrame *frame = baselineFrame();
1855 for (unsigned i = 0; i < frame->numValueSlots(); i++) {
1856 fprintf(stderr, " slot %u: ", i);
1857 #ifdef DEBUG
1858 Value *v = frame->valueSlot(i);
1859 js_DumpValue(*v);
1860 #else
1861 fprintf(stderr, "?\n");
1862 #endif
1863 }
1864 }
1866 template <AllowGC allowGC>
1867 void
1868 InlineFrameIteratorMaybeGC<allowGC>::dump() const
1869 {
1870 if (more())
1871 fprintf(stderr, " JS frame (inlined)\n");
1872 else
1873 fprintf(stderr, " JS frame\n");
1875 bool isFunction = false;
1876 if (isFunctionFrame()) {
1877 isFunction = true;
1878 fprintf(stderr, " callee fun: ");
1879 #ifdef DEBUG
1880 js_DumpObject(callee());
1881 #else
1882 fprintf(stderr, "?\n");
1883 #endif
1884 } else {
1885 fprintf(stderr, " global frame, no callee\n");
1886 }
1888 fprintf(stderr, " file %s line %u\n",
1889 script()->filename(), (unsigned) script()->lineno());
1891 fprintf(stderr, " script = %p, pc = %p\n", (void*) script(), pc());
1892 fprintf(stderr, " current op: %s\n", js_CodeName[*pc()]);
1894 if (!more()) {
1895 numActualArgs();
1896 }
1898 SnapshotIterator si = snapshotIterator();
1899 fprintf(stderr, " slots: %u\n", si.numAllocations() - 1);
1900 for (unsigned i = 0; i < si.numAllocations() - 1; i++) {
1901 if (isFunction) {
1902 if (i == 0)
1903 fprintf(stderr, " scope chain: ");
1904 else if (i == 1)
1905 fprintf(stderr, " this: ");
1906 else if (i - 2 < callee()->nargs())
1907 fprintf(stderr, " formal (arg %d): ", i - 2);
1908 else {
1909 if (i - 2 == callee()->nargs() && numActualArgs() > callee()->nargs()) {
1910 DumpOp d(callee()->nargs());
1911 unaliasedForEachActual(GetJSContextFromJitCode(), d, ReadFrame_Overflown);
1912 }
1914 fprintf(stderr, " slot %d: ", int(i - 2 - callee()->nargs()));
1915 }
1916 } else
1917 fprintf(stderr, " slot %u: ", i);
1918 #ifdef DEBUG
1919 js_DumpValue(si.maybeRead());
1920 #else
1921 fprintf(stderr, "?\n");
1922 #endif
1923 }
1925 fputc('\n', stderr);
1926 }
1927 template void InlineFrameIteratorMaybeGC<NoGC>::dump() const;
1928 template void InlineFrameIteratorMaybeGC<CanGC>::dump() const;
1930 void
1931 JitFrameIterator::dump() const
1932 {
1933 switch (type_) {
1934 case JitFrame_Entry:
1935 fprintf(stderr, " Entry frame\n");
1936 fprintf(stderr, " Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
1937 break;
1938 case JitFrame_BaselineJS:
1939 dumpBaseline();
1940 break;
1941 case JitFrame_BaselineStub:
1942 case JitFrame_Unwound_BaselineStub:
1943 fprintf(stderr, " Baseline stub frame\n");
1944 fprintf(stderr, " Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
1945 break;
1946 case JitFrame_IonJS:
1947 {
1948 InlineFrameIterator frames(GetJSContextFromJitCode(), this);
1949 for (;;) {
1950 frames.dump();
1951 if (!frames.more())
1952 break;
1953 ++frames;
1954 }
1955 break;
1956 }
1957 case JitFrame_Rectifier:
1958 case JitFrame_Unwound_Rectifier:
1959 fprintf(stderr, " Rectifier frame\n");
1960 fprintf(stderr, " Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
1961 break;
1962 case JitFrame_Unwound_IonJS:
1963 fprintf(stderr, "Warning! Unwound JS frames are not observable.\n");
1964 break;
1965 case JitFrame_Exit:
1966 break;
1967 };
1968 fputc('\n', stderr);
1969 }
1971 IonJSFrameLayout *
1972 InvalidationBailoutStack::fp() const
1973 {
1974 return (IonJSFrameLayout *) (sp() + ionScript_->frameSize());
1975 }
1977 void
1978 InvalidationBailoutStack::checkInvariants() const
1979 {
1980 #ifdef DEBUG
1981 IonJSFrameLayout *frame = fp();
1982 CalleeToken token = frame->calleeToken();
1983 JS_ASSERT(token);
1985 uint8_t *rawBase = ionScript()->method()->raw();
1986 uint8_t *rawLimit = rawBase + ionScript()->method()->instructionsSize();
1987 uint8_t *osiPoint = osiPointReturnAddress();
1988 JS_ASSERT(rawBase <= osiPoint && osiPoint <= rawLimit);
1989 #endif
1990 }
1992 } // namespace jit
1993 } // namespace js