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 #include "vm/Stack-inl.h"
8 
9 #include "mozilla/PodOperations.h"
10 
11 #include "jscntxt.h"
12 
13 #include "asmjs/AsmJSFrameIterator.h"
14 #include "asmjs/AsmJSModule.h"
15 #include "gc/Marking.h"
16 #include "jit/BaselineFrame.h"
17 #include "jit/JitcodeMap.h"
18 #include "jit/JitCompartment.h"
19 #include "js/GCAPI.h"
20 #include "vm/Debugger.h"
21 #include "vm/Opcodes.h"
22 
23 #include "jit/JitFrameIterator-inl.h"
24 #include "vm/Interpreter-inl.h"
25 #include "vm/Probes-inl.h"
26 #include "vm/ScopeObject-inl.h"
27 
28 using namespace js;
29 
30 using mozilla::Maybe;
31 using mozilla::PodCopy;
32 
33 /*****************************************************************************/
34 
35 void
initExecuteFrame(JSContext * cx,HandleScript script,AbstractFramePtr evalInFramePrev,const Value & newTargetValue,HandleObject scopeChain,ExecuteType type)36 InterpreterFrame::initExecuteFrame(JSContext* cx, HandleScript script, AbstractFramePtr evalInFramePrev,
37                                    const Value& newTargetValue, HandleObject scopeChain,
38                                    ExecuteType type)
39 {
40     /*
41      * See encoding of ExecuteType. When GLOBAL isn't set, we are executing a
42      * script in the context of another frame and the frame type is determined
43      * by the context.
44      */
45     flags_ = type | HAS_SCOPECHAIN;
46 
47     JSObject* callee = nullptr;
48 
49     // newTarget = NullValue is an initial sentinel for "please fill me in from the stack".
50     // It should never be passed from Ion code.
51     RootedValue newTarget(cx, newTargetValue);
52     if (!(flags_ & (GLOBAL | MODULE))) {
53         if (evalInFramePrev) {
54             MOZ_ASSERT(evalInFramePrev.isFunctionFrame() || evalInFramePrev.isGlobalFrame());
55             if (evalInFramePrev.isFunctionFrame()) {
56                 callee = evalInFramePrev.callee();
57                 if (newTarget.isNull())
58                     newTarget = evalInFramePrev.newTarget();
59                 flags_ |= FUNCTION;
60             } else {
61                 flags_ |= GLOBAL;
62             }
63         } else {
64             FrameIter iter(cx);
65             MOZ_ASSERT(iter.isFunctionFrame() || iter.isGlobalFrame());
66             MOZ_ASSERT(!iter.isAsmJS());
67             if (iter.isFunctionFrame()) {
68                 if (newTarget.isNull())
69                     newTarget = iter.newTarget();
70                 callee = iter.callee(cx);
71                 flags_ |= FUNCTION;
72             } else {
73                 flags_ |= GLOBAL;
74             }
75         }
76     }
77 
78     Value* dstvp = (Value*)this - 2;
79 
80     if (isFunctionFrame()) {
81         dstvp[1] = ObjectValue(*callee);
82         exec.fun = &callee->as<JSFunction>();
83         u.evalScript = script;
84     } else {
85         MOZ_ASSERT(isGlobalFrame() || isModuleFrame());
86         dstvp[1] = NullValue();
87         exec.script = script;
88 #ifdef DEBUG
89         u.evalScript = (JSScript*)0xbad;
90 #endif
91     }
92     dstvp[0] = newTarget;
93 
94     scopeChain_ = scopeChain.get();
95     prev_ = nullptr;
96     prevpc_ = nullptr;
97     prevsp_ = nullptr;
98 
99     MOZ_ASSERT_IF(evalInFramePrev, isDebuggerEvalFrame());
100     evalInFramePrev_ = evalInFramePrev;
101 
102     if (script->isDebuggee())
103         setIsDebuggee();
104 
105 #ifdef DEBUG
106     Debug_SetValueRangeToCrashOnTouch(&rval_, 1);
107 #endif
108 }
109 
110 bool
isNonGlobalEvalFrame() const111 InterpreterFrame::isNonGlobalEvalFrame() const
112 {
113     return isEvalFrame() &&
114            script()->enclosingStaticScope()->as<StaticEvalObject>().isNonGlobal();
115 }
116 
117 bool
copyRawFrameSlots(AutoValueVector * vec)118 InterpreterFrame::copyRawFrameSlots(AutoValueVector* vec)
119 {
120     if (!vec->resize(numFormalArgs() + script()->nfixed()))
121         return false;
122     PodCopy(vec->begin(), argv(), numFormalArgs());
123     PodCopy(vec->begin() + numFormalArgs(), slots(), script()->nfixed());
124     return true;
125 }
126 
127 JSObject*
createRestParameter(JSContext * cx)128 InterpreterFrame::createRestParameter(JSContext* cx)
129 {
130     MOZ_ASSERT(fun()->hasRest());
131     unsigned nformal = fun()->nargs() - 1, nactual = numActualArgs();
132     unsigned nrest = (nactual > nformal) ? nactual - nformal : 0;
133     Value* restvp = argv() + nformal;
134     return ObjectGroup::newArrayObject(cx, restvp, nrest, GenericObject,
135                                        ObjectGroup::NewArrayKind::UnknownIndex);
136 }
137 
138 static inline void
AssertDynamicScopeMatchesStaticScope(JSContext * cx,JSScript * script,JSObject * scope)139 AssertDynamicScopeMatchesStaticScope(JSContext* cx, JSScript* script, JSObject* scope)
140 {
141 #ifdef DEBUG
142     RootedObject originalScope(cx, scope);
143     RootedObject enclosingScope(cx, script->enclosingStaticScope());
144     for (StaticScopeIter<NoGC> i(enclosingScope); !i.done(); i++) {
145         if (i.type() == StaticScopeIter<NoGC>::NonSyntactic) {
146             while (scope->is<DynamicWithObject>() ||
147                    scope->is<NonSyntacticVariablesObject>() ||
148                    (scope->is<ClonedBlockObject>() &&
149                     !scope->as<ClonedBlockObject>().isSyntactic()))
150             {
151                 MOZ_ASSERT(!IsSyntacticScope(scope));
152                 scope = &scope->as<ScopeObject>().enclosingScope();
153             }
154         } else if (i.hasSyntacticDynamicScopeObject()) {
155             switch (i.type()) {
156               case StaticScopeIter<NoGC>::Module:
157                 MOZ_ASSERT(scope->as<ModuleEnvironmentObject>().module().script() == i.moduleScript());
158                 scope = &scope->as<ModuleEnvironmentObject>().enclosingScope();
159                 break;
160               case StaticScopeIter<NoGC>::Function:
161                 MOZ_ASSERT(scope->as<CallObject>().callee().nonLazyScript() == i.funScript());
162                 scope = &scope->as<CallObject>().enclosingScope();
163                 break;
164               case StaticScopeIter<NoGC>::Block:
165                 MOZ_ASSERT(&i.block() == scope->as<ClonedBlockObject>().staticScope());
166                 scope = &scope->as<ClonedBlockObject>().enclosingScope();
167                 break;
168               case StaticScopeIter<NoGC>::With:
169                 MOZ_ASSERT(&i.staticWith() == scope->as<DynamicWithObject>().staticScope());
170                 scope = &scope->as<DynamicWithObject>().enclosingScope();
171                 break;
172               case StaticScopeIter<NoGC>::NamedLambda:
173                 scope = &scope->as<DeclEnvObject>().enclosingScope();
174                 break;
175               case StaticScopeIter<NoGC>::Eval:
176                 scope = &scope->as<CallObject>().enclosingScope();
177                 break;
178               case StaticScopeIter<NoGC>::NonSyntactic:
179                 MOZ_CRASH("NonSyntactic should not have a syntactic scope");
180                 break;
181             }
182         }
183     }
184 
185     // In the case of a non-syntactic scope chain, the immediate parent of the
186     // outermost non-syntactic scope may be the global lexical scope, or, if
187     // called from Debugger, a DebugScopeObject.
188     //
189     // In the case of a syntactic scope chain, the outermost scope is always a
190     // GlobalObject.
191     MOZ_ASSERT(scope->is<GlobalObject>() || IsGlobalLexicalScope(scope) ||
192                scope->is<DebugScopeObject>());
193 #endif
194 }
195 
196 bool
initFunctionScopeObjects(JSContext * cx)197 InterpreterFrame::initFunctionScopeObjects(JSContext* cx)
198 {
199     CallObject* callobj = CallObject::createForFunction(cx, this);
200     if (!callobj)
201         return false;
202     pushOnScopeChain(*callobj);
203     flags_ |= HAS_CALL_OBJ;
204     return true;
205 }
206 
207 bool
prologue(JSContext * cx)208 InterpreterFrame::prologue(JSContext* cx)
209 {
210     RootedScript script(cx, this->script());
211 
212     MOZ_ASSERT(isModuleFrame() == !!script->module());
213     MOZ_ASSERT(cx->interpreterRegs().pc == script->code());
214 
215     if (isEvalFrame()) {
216         if (script->strict()) {
217             CallObject* callobj = CallObject::createForStrictEval(cx, this);
218             if (!callobj)
219                 return false;
220             pushOnScopeChain(*callobj);
221             flags_ |= HAS_CALL_OBJ;
222         } else {
223             // Non-strict eval may introduce var bindings that conflict with
224             // lexical bindings in an enclosing lexical scope.
225             RootedObject varObjRoot(cx, &varObj());
226             if (!CheckEvalDeclarationConflicts(cx, script, scopeChain(), varObjRoot))
227                 return false;
228         }
229         return probes::EnterScript(cx, script, nullptr, this);
230     }
231 
232     if (isGlobalFrame()) {
233         Rooted<ClonedBlockObject*> lexicalScope(cx);
234         RootedObject varObjRoot(cx);
235         if (script->hasNonSyntacticScope()) {
236             lexicalScope = &extensibleLexicalScope();
237             varObjRoot = &varObj();
238         } else {
239             lexicalScope = &cx->global()->lexicalScope();
240             varObjRoot = cx->global();
241         }
242         if (!CheckGlobalDeclarationConflicts(cx, script, lexicalScope, varObjRoot))
243             return false;
244         return probes::EnterScript(cx, script, nullptr, this);
245     }
246 
247     AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain());
248 
249     if (isModuleFrame())
250         return probes::EnterScript(cx, script, nullptr, this);
251 
252     MOZ_ASSERT(isNonEvalFunctionFrame());
253     if (fun()->needsCallObject() && !initFunctionScopeObjects(cx))
254         return false;
255 
256     if (isConstructing()) {
257         if (script->isDerivedClassConstructor()) {
258             MOZ_ASSERT(callee().isClassConstructor());
259             thisArgument() = MagicValue(JS_UNINITIALIZED_LEXICAL);
260         } else if (thisArgument().isPrimitive()) {
261             RootedObject callee(cx, &this->callee());
262             RootedObject newTarget(cx, &this->newTarget().toObject());
263             JSObject* obj = CreateThisForFunction(cx, callee, newTarget,
264                                                   createSingleton() ? SingletonObject : GenericObject);
265             if (!obj)
266                 return false;
267             thisArgument() = ObjectValue(*obj);
268         }
269     }
270 
271     return probes::EnterScript(cx, script, script->functionNonDelazifying(), this);
272 }
273 
274 void
epilogue(JSContext * cx)275 InterpreterFrame::epilogue(JSContext* cx)
276 {
277     RootedScript script(cx, this->script());
278     probes::ExitScript(cx, script, script->functionNonDelazifying(), hasPushedSPSFrame());
279 
280     if (isEvalFrame()) {
281         if (isStrictEvalFrame()) {
282             MOZ_ASSERT_IF(hasCallObj(), scopeChain()->as<CallObject>().isForEval());
283             if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
284                 DebugScopes::onPopStrictEvalScope(this);
285         } else if (isNonGlobalEvalFrame()) {
286             MOZ_ASSERT_IF(isDebuggerEvalFrame(), !IsSyntacticScope(scopeChain()));
287         }
288         return;
289     }
290 
291     if (isGlobalFrame()) {
292         // Confusingly, global frames may run in non-global scopes (that is,
293         // not directly under the GlobalObject and its lexical scope).
294         //
295         // Gecko often runs global scripts under custom scopes. See users of
296         // CreateNonSyntacticScopeChain.
297         MOZ_ASSERT(IsGlobalLexicalScope(scopeChain()) || !IsSyntacticScope(scopeChain()));
298         return;
299     }
300 
301     if (isModuleFrame())
302         return;
303 
304     MOZ_ASSERT(isNonEvalFunctionFrame());
305 
306     if (fun()->needsCallObject()) {
307         MOZ_ASSERT_IF(hasCallObj() && !fun()->isGenerator(),
308                       scopeChain()->as<CallObject>().callee().nonLazyScript() == script);
309     } else {
310         AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain());
311     }
312 
313     if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
314         DebugScopes::onPopCall(this, cx);
315 
316     if (!fun()->isGenerator() &&
317         isConstructing() &&
318         thisArgument().isObject() &&
319         returnValue().isPrimitive())
320     {
321         setReturnValue(thisArgument());
322     }
323 }
324 
325 bool
checkReturn(JSContext * cx,HandleValue thisv)326 InterpreterFrame::checkReturn(JSContext* cx, HandleValue thisv)
327 {
328     MOZ_ASSERT(script()->isDerivedClassConstructor());
329     MOZ_ASSERT(isFunctionFrame());
330     MOZ_ASSERT(callee().isClassConstructor());
331 
332     HandleValue retVal = returnValue();
333     if (retVal.isObject())
334         return true;
335 
336     if (!retVal.isUndefined()) {
337         ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN, JSDVG_IGNORE_STACK, retVal, nullptr);
338         return false;
339     }
340 
341     if (thisv.isMagic(JS_UNINITIALIZED_LEXICAL))
342         return ThrowUninitializedThis(cx, this);
343 
344     setReturnValue(thisv);
345     return true;
346 }
347 
348 bool
pushBlock(JSContext * cx,StaticBlockObject & block)349 InterpreterFrame::pushBlock(JSContext* cx, StaticBlockObject& block)
350 {
351     MOZ_ASSERT(block.needsClone());
352 
353     Rooted<StaticBlockObject*> blockHandle(cx, &block);
354     ClonedBlockObject* clone = ClonedBlockObject::create(cx, blockHandle, this);
355     if (!clone)
356         return false;
357 
358     pushOnScopeChain(*clone);
359 
360     return true;
361 }
362 
363 bool
freshenBlock(JSContext * cx)364 InterpreterFrame::freshenBlock(JSContext* cx)
365 {
366     MOZ_ASSERT(flags_ & HAS_SCOPECHAIN);
367     Rooted<ClonedBlockObject*> block(cx, &scopeChain_->as<ClonedBlockObject>());
368     ClonedBlockObject* fresh = ClonedBlockObject::clone(cx, block);
369     if (!fresh)
370         return false;
371 
372     replaceInnermostScope(*fresh);
373     return true;
374 }
375 
376 void
popBlock(JSContext * cx)377 InterpreterFrame::popBlock(JSContext* cx)
378 {
379     MOZ_ASSERT(scopeChain_->is<ClonedBlockObject>());
380     popOffScopeChain();
381 }
382 
383 void
popWith(JSContext * cx)384 InterpreterFrame::popWith(JSContext* cx)
385 {
386     if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
387         DebugScopes::onPopWith(this);
388 
389     MOZ_ASSERT(scopeChain()->is<DynamicWithObject>());
390     popOffScopeChain();
391 }
392 
393 void
mark(JSTracer * trc)394 InterpreterFrame::mark(JSTracer* trc)
395 {
396     /*
397      * Normally we would use MarkRoot here, except that generators also take
398      * this path. However, generators use a special write barrier when the stack
399      * frame is copied to the floating frame. Therefore, no barrier is needed.
400      */
401     if (flags_ & HAS_SCOPECHAIN)
402         TraceManuallyBarrieredEdge(trc, &scopeChain_, "scope chain");
403     if (flags_ & HAS_ARGS_OBJ)
404         TraceManuallyBarrieredEdge(trc, &argsObj_, "arguments");
405     if (isFunctionFrame()) {
406         TraceManuallyBarrieredEdge(trc, &exec.fun, "fun");
407         if (isEvalFrame())
408             TraceManuallyBarrieredEdge(trc, &u.evalScript, "eval script");
409     } else {
410         TraceManuallyBarrieredEdge(trc, &exec.script, "script");
411     }
412     if (trc->isMarkingTracer())
413         script()->compartment()->zone()->active = true;
414     if (hasReturnValue())
415         TraceManuallyBarrieredEdge(trc, &rval_, "rval");
416 }
417 
418 void
markValues(JSTracer * trc,unsigned start,unsigned end)419 InterpreterFrame::markValues(JSTracer* trc, unsigned start, unsigned end)
420 {
421     if (start < end)
422         TraceRootRange(trc, end - start, slots() + start, "vm_stack");
423 }
424 
425 void
markValues(JSTracer * trc,Value * sp,jsbytecode * pc)426 InterpreterFrame::markValues(JSTracer* trc, Value* sp, jsbytecode* pc)
427 {
428     MOZ_ASSERT(sp >= slots());
429 
430     JSScript* script = this->script();
431     size_t nfixed = script->nfixed();
432     size_t nlivefixed = script->calculateLiveFixed(pc);
433 
434     if (nfixed == nlivefixed) {
435         // All locals are live.
436         markValues(trc, 0, sp - slots());
437     } else {
438         // Mark operand stack.
439         markValues(trc, nfixed, sp - slots());
440 
441         // Clear dead block-scoped locals.
442         while (nfixed > nlivefixed)
443             unaliasedLocal(--nfixed).setMagic(JS_UNINITIALIZED_LEXICAL);
444 
445         // Mark live locals.
446         markValues(trc, 0, nlivefixed);
447     }
448 
449     if (hasArgs()) {
450         // Mark callee, |this| and arguments.
451         unsigned argc = Max(numActualArgs(), numFormalArgs());
452         TraceRootRange(trc, argc + 2 + isConstructing(), argv_ - 2, "fp argv");
453     } else {
454         // Mark callee and newTarget
455         TraceRootRange(trc, 2, ((Value*)this) - 2, "stack callee and newTarget");
456     }
457 }
458 
459 static void
MarkInterpreterActivation(JSTracer * trc,InterpreterActivation * act)460 MarkInterpreterActivation(JSTracer* trc, InterpreterActivation* act)
461 {
462     for (InterpreterFrameIterator frames(act); !frames.done(); ++frames) {
463         InterpreterFrame* fp = frames.frame();
464         fp->markValues(trc, frames.sp(), frames.pc());
465         fp->mark(trc);
466     }
467 }
468 
469 void
MarkInterpreterActivations(JSRuntime * rt,JSTracer * trc)470 js::MarkInterpreterActivations(JSRuntime* rt, JSTracer* trc)
471 {
472     for (ActivationIterator iter(rt); !iter.done(); ++iter) {
473         Activation* act = iter.activation();
474         if (act->isInterpreter())
475             MarkInterpreterActivation(trc, act->asInterpreter());
476     }
477 }
478 
479 /*****************************************************************************/
480 
481 // Unlike the other methods of this class, this method is defined here so that
482 // we don't have to #include jsautooplen.h in vm/Stack.h.
483 void
setToEndOfScript()484 InterpreterRegs::setToEndOfScript()
485 {
486     sp = fp()->base();
487     pc = fp()->script()->lastPC();
488 }
489 
490 /*****************************************************************************/
491 
492 InterpreterFrame*
pushInvokeFrame(JSContext * cx,const CallArgs & args,InitialFrameFlags initial)493 InterpreterStack::pushInvokeFrame(JSContext* cx, const CallArgs& args, InitialFrameFlags initial)
494 {
495     LifoAlloc::Mark mark = allocator_.mark();
496 
497     RootedFunction fun(cx, &args.callee().as<JSFunction>());
498     RootedScript script(cx, fun->nonLazyScript());
499 
500     InterpreterFrame::Flags flags = ToFrameFlags(initial);
501     Value* argv;
502     InterpreterFrame* fp = getCallFrame(cx, args, script, &flags, &argv);
503     if (!fp)
504         return nullptr;
505 
506     fp->mark_ = mark;
507     fp->initCallFrame(cx, nullptr, nullptr, nullptr, *fun, script, argv, args.length(), flags);
508     return fp;
509 }
510 
511 InterpreterFrame*
pushExecuteFrame(JSContext * cx,HandleScript script,const Value & newTargetValue,HandleObject scopeChain,ExecuteType type,AbstractFramePtr evalInFrame)512 InterpreterStack::pushExecuteFrame(JSContext* cx, HandleScript script, const Value& newTargetValue,
513                                    HandleObject scopeChain, ExecuteType type,
514                                    AbstractFramePtr evalInFrame)
515 {
516     LifoAlloc::Mark mark = allocator_.mark();
517 
518     unsigned nvars = 2 /* callee, newTarget */ + script->nslots();
519     uint8_t* buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvars * sizeof(Value));
520     if (!buffer)
521         return nullptr;
522 
523     InterpreterFrame* fp = reinterpret_cast<InterpreterFrame*>(buffer + 2 * sizeof(Value));
524     fp->mark_ = mark;
525     fp->initExecuteFrame(cx, script, evalInFrame, newTargetValue, scopeChain, type);
526     fp->initLocals();
527 
528     return fp;
529 }
530 
531 /*****************************************************************************/
532 
533 void
popActivation()534 FrameIter::popActivation()
535 {
536     ++data_.activations_;
537     settleOnActivation();
538 }
539 
540 void
popInterpreterFrame()541 FrameIter::popInterpreterFrame()
542 {
543     MOZ_ASSERT(data_.state_ == INTERP);
544 
545     ++data_.interpFrames_;
546 
547     if (data_.interpFrames_.done())
548         popActivation();
549     else
550         data_.pc_ = data_.interpFrames_.pc();
551 }
552 
553 void
settleOnActivation()554 FrameIter::settleOnActivation()
555 {
556     while (true) {
557         if (data_.activations_.done()) {
558             data_.state_ = DONE;
559             return;
560         }
561 
562         Activation* activation = data_.activations_.activation();
563 
564         // If JS_SaveFrameChain was called, stop iterating here (unless
565         // GO_THROUGH_SAVED is set).
566         if (data_.savedOption_ == STOP_AT_SAVED && activation->hasSavedFrameChain()) {
567             data_.state_ = DONE;
568             return;
569         }
570 
571         // Skip activations from another context if needed.
572         MOZ_ASSERT(activation->cx());
573         MOZ_ASSERT(data_.cx_);
574         if (data_.contextOption_ == CURRENT_CONTEXT && activation->cx() != data_.cx_) {
575             ++data_.activations_;
576             continue;
577         }
578 
579         // If the caller supplied principals, only show activations which are subsumed (of the same
580         // origin or of an origin accessible) by these principals.
581         if (data_.principals_) {
582             JSContext* cx = data_.cx_->asJSContext();
583             if (JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes) {
584                 if (!subsumes(data_.principals_, activation->compartment()->principals())) {
585                     ++data_.activations_;
586                     continue;
587                 }
588             }
589         }
590 
591         if (activation->isJit()) {
592             data_.jitFrames_ = jit::JitFrameIterator(data_.activations_);
593 
594             // Stop at the first scripted frame.
595             while (!data_.jitFrames_.isScripted() && !data_.jitFrames_.done())
596                 ++data_.jitFrames_;
597 
598             // It's possible to have an JitActivation with no scripted frames,
599             // for instance if we hit an over-recursion during bailout.
600             if (data_.jitFrames_.done()) {
601                 ++data_.activations_;
602                 continue;
603             }
604 
605             nextJitFrame();
606             data_.state_ = JIT;
607             return;
608         }
609 
610         if (activation->isAsmJS()) {
611             data_.asmJSFrames_ = AsmJSFrameIterator(*data_.activations_->asAsmJS());
612 
613             if (data_.asmJSFrames_.done()) {
614                 ++data_.activations_;
615                 continue;
616             }
617 
618             data_.state_ = ASMJS;
619             return;
620         }
621 
622         MOZ_ASSERT(activation->isInterpreter());
623 
624         InterpreterActivation* interpAct = activation->asInterpreter();
625         data_.interpFrames_ = InterpreterFrameIterator(interpAct);
626 
627         // If we OSR'ed into JIT code, skip the interpreter frame so that
628         // the same frame is not reported twice.
629         if (data_.interpFrames_.frame()->runningInJit()) {
630             ++data_.interpFrames_;
631             if (data_.interpFrames_.done()) {
632                 ++data_.activations_;
633                 continue;
634             }
635         }
636 
637         MOZ_ASSERT(!data_.interpFrames_.frame()->runningInJit());
638         data_.pc_ = data_.interpFrames_.pc();
639         data_.state_ = INTERP;
640         return;
641     }
642 }
643 
Data(JSContext * cx,SavedOption savedOption,ContextOption contextOption,DebuggerEvalOption debuggerEvalOption,JSPrincipals * principals)644 FrameIter::Data::Data(JSContext* cx, SavedOption savedOption,
645                       ContextOption contextOption, DebuggerEvalOption debuggerEvalOption,
646                       JSPrincipals* principals)
647   : cx_(cx),
648     savedOption_(savedOption),
649     contextOption_(contextOption),
650     debuggerEvalOption_(debuggerEvalOption),
651     principals_(principals),
652     pc_(nullptr),
653     interpFrames_(nullptr),
654     activations_(cx->runtime()),
655     jitFrames_(),
656     ionInlineFrameNo_(0),
657     asmJSFrames_()
658 {
659 }
660 
Data(const FrameIter::Data & other)661 FrameIter::Data::Data(const FrameIter::Data& other)
662   : cx_(other.cx_),
663     savedOption_(other.savedOption_),
664     contextOption_(other.contextOption_),
665     debuggerEvalOption_(other.debuggerEvalOption_),
666     principals_(other.principals_),
667     state_(other.state_),
668     pc_(other.pc_),
669     interpFrames_(other.interpFrames_),
670     activations_(other.activations_),
671     jitFrames_(other.jitFrames_),
672     ionInlineFrameNo_(other.ionInlineFrameNo_),
673     asmJSFrames_(other.asmJSFrames_)
674 {
675 }
676 
FrameIter(JSContext * cx,SavedOption savedOption)677 FrameIter::FrameIter(JSContext* cx, SavedOption savedOption)
678   : data_(cx, savedOption, CURRENT_CONTEXT, FOLLOW_DEBUGGER_EVAL_PREV_LINK, nullptr),
679     ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
680 {
681     // settleOnActivation can only GC if principals are given.
682     JS::AutoSuppressGCAnalysis nogc;
683     settleOnActivation();
684 }
685 
FrameIter(JSContext * cx,ContextOption contextOption,SavedOption savedOption,DebuggerEvalOption debuggerEvalOption)686 FrameIter::FrameIter(JSContext* cx, ContextOption contextOption,
687                      SavedOption savedOption, DebuggerEvalOption debuggerEvalOption)
688   : data_(cx, savedOption, contextOption, debuggerEvalOption, nullptr),
689     ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
690 {
691     // settleOnActivation can only GC if principals are given.
692     JS::AutoSuppressGCAnalysis nogc;
693     settleOnActivation();
694 }
695 
FrameIter(JSContext * cx,ContextOption contextOption,SavedOption savedOption,DebuggerEvalOption debuggerEvalOption,JSPrincipals * principals)696 FrameIter::FrameIter(JSContext* cx, ContextOption contextOption,
697                      SavedOption savedOption, DebuggerEvalOption debuggerEvalOption,
698                      JSPrincipals* principals)
699   : data_(cx, savedOption, contextOption, debuggerEvalOption, principals),
700     ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
701 {
702     settleOnActivation();
703 }
704 
FrameIter(const FrameIter & other)705 FrameIter::FrameIter(const FrameIter& other)
706   : data_(other.data_),
707     ionInlineFrames_(other.data_.cx_,
708                      data_.jitFrames_.isIonScripted() ? &other.ionInlineFrames_ : nullptr)
709 {
710 }
711 
FrameIter(const Data & data)712 FrameIter::FrameIter(const Data& data)
713   : data_(data),
714     ionInlineFrames_(data.cx_, data_.jitFrames_.isIonScripted() ? &data_.jitFrames_ : nullptr)
715 {
716     MOZ_ASSERT(data.cx_);
717 
718     if (data_.jitFrames_.isIonScripted()) {
719         while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_)
720             ++ionInlineFrames_;
721     }
722 }
723 
724 void
nextJitFrame()725 FrameIter::nextJitFrame()
726 {
727     if (data_.jitFrames_.isIonScripted()) {
728         ionInlineFrames_.resetOn(&data_.jitFrames_);
729         data_.pc_ = ionInlineFrames_.pc();
730     } else {
731         MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
732         data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
733     }
734 }
735 
736 void
popJitFrame()737 FrameIter::popJitFrame()
738 {
739     MOZ_ASSERT(data_.state_ == JIT);
740 
741     if (data_.jitFrames_.isIonScripted() && ionInlineFrames_.more()) {
742         ++ionInlineFrames_;
743         data_.pc_ = ionInlineFrames_.pc();
744         return;
745     }
746 
747     ++data_.jitFrames_;
748     while (!data_.jitFrames_.done() && !data_.jitFrames_.isScripted())
749         ++data_.jitFrames_;
750 
751     if (!data_.jitFrames_.done()) {
752         nextJitFrame();
753         return;
754     }
755 
756     popActivation();
757 }
758 
759 void
popAsmJSFrame()760 FrameIter::popAsmJSFrame()
761 {
762     MOZ_ASSERT(data_.state_ == ASMJS);
763 
764     ++data_.asmJSFrames_;
765     if (data_.asmJSFrames_.done())
766         popActivation();
767 }
768 
769 FrameIter&
operator ++()770 FrameIter::operator++()
771 {
772     switch (data_.state_) {
773       case DONE:
774         MOZ_CRASH("Unexpected state");
775       case INTERP:
776         if (interpFrame()->isDebuggerEvalFrame() &&
777             interpFrame()->evalInFramePrev() &&
778             data_.debuggerEvalOption_ == FOLLOW_DEBUGGER_EVAL_PREV_LINK)
779         {
780             AbstractFramePtr eifPrev = interpFrame()->evalInFramePrev();
781 
782             // Eval-in-frame can cross contexts and works across saved frame
783             // chains.
784             ContextOption prevContextOption = data_.contextOption_;
785             SavedOption prevSavedOption = data_.savedOption_;
786             data_.contextOption_ = ALL_CONTEXTS;
787             data_.savedOption_ = GO_THROUGH_SAVED;
788 
789             popInterpreterFrame();
790 
791             while (!hasUsableAbstractFramePtr() || abstractFramePtr() != eifPrev) {
792                 if (data_.state_ == JIT)
793                     popJitFrame();
794                 else
795                     popInterpreterFrame();
796             }
797 
798             data_.contextOption_ = prevContextOption;
799             data_.savedOption_ = prevSavedOption;
800             data_.cx_ = data_.activations_->cx();
801             break;
802         }
803         popInterpreterFrame();
804         break;
805       case JIT:
806         popJitFrame();
807         break;
808       case ASMJS:
809         popAsmJSFrame();
810         break;
811     }
812     return *this;
813 }
814 
815 FrameIter::Data*
copyData() const816 FrameIter::copyData() const
817 {
818     Data* data = data_.cx_->new_<Data>(data_);
819     if (!data)
820         return nullptr;
821 
822     MOZ_ASSERT(data_.state_ != ASMJS);
823     if (data && data_.jitFrames_.isIonScripted())
824         data->ionInlineFrameNo_ = ionInlineFrames_.frameNo();
825     // Give the copied Data the cx of the current activation, which may be
826     // different than the cx that the current FrameIter was constructed
827     // with. This ensures that when we instantiate another FrameIter with the
828     // copied data, its cx is still alive.
829     data->cx_ = activation()->cx();
830     return data;
831 }
832 
833 AbstractFramePtr
copyDataAsAbstractFramePtr() const834 FrameIter::copyDataAsAbstractFramePtr() const
835 {
836     AbstractFramePtr frame;
837     if (Data* data = copyData())
838         frame.ptr_ = uintptr_t(data);
839     return frame;
840 }
841 
842 void*
rawFramePtr() const843 FrameIter::rawFramePtr() const
844 {
845     switch (data_.state_) {
846       case DONE:
847       case ASMJS:
848         return nullptr;
849       case JIT:
850         return data_.jitFrames_.fp();
851       case INTERP:
852         return interpFrame();
853     }
854     MOZ_CRASH("Unexpected state");
855 }
856 
857 JSCompartment*
compartment() const858 FrameIter::compartment() const
859 {
860     switch (data_.state_) {
861       case DONE:
862         break;
863       case INTERP:
864       case JIT:
865       case ASMJS:
866         return data_.activations_->compartment();
867     }
868     MOZ_CRASH("Unexpected state");
869 }
870 
871 bool
isFunctionFrame() const872 FrameIter::isFunctionFrame() const
873 {
874     switch (data_.state_) {
875       case DONE:
876         break;
877       case INTERP:
878         return interpFrame()->isFunctionFrame();
879       case JIT:
880         MOZ_ASSERT(data_.jitFrames_.isScripted());
881         if (data_.jitFrames_.isBaselineJS())
882             return data_.jitFrames_.isFunctionFrame();
883         return ionInlineFrames_.isFunctionFrame();
884       case ASMJS:
885         return true;
886     }
887     MOZ_CRASH("Unexpected state");
888 }
889 
890 bool
isGlobalFrame() const891 FrameIter::isGlobalFrame() const
892 {
893     switch (data_.state_) {
894       case DONE:
895         break;
896       case INTERP:
897         return interpFrame()->isGlobalFrame();
898       case JIT:
899         if (data_.jitFrames_.isBaselineJS())
900             return data_.jitFrames_.baselineFrame()->isGlobalFrame();
901         MOZ_ASSERT(!script()->isForEval());
902         return !script()->functionNonDelazifying();
903       case ASMJS:
904         return false;
905     }
906     MOZ_CRASH("Unexpected state");
907 }
908 
909 bool
isEvalFrame() const910 FrameIter::isEvalFrame() const
911 {
912     switch (data_.state_) {
913       case DONE:
914         break;
915       case INTERP:
916         return interpFrame()->isEvalFrame();
917       case JIT:
918         if (data_.jitFrames_.isBaselineJS())
919             return data_.jitFrames_.baselineFrame()->isEvalFrame();
920         MOZ_ASSERT(!script()->isForEval());
921         return false;
922       case ASMJS:
923         return false;
924     }
925     MOZ_CRASH("Unexpected state");
926 }
927 
928 bool
isNonEvalFunctionFrame() const929 FrameIter::isNonEvalFunctionFrame() const
930 {
931     MOZ_ASSERT(!done());
932     switch (data_.state_) {
933       case DONE:
934         break;
935       case INTERP:
936         return interpFrame()->isNonEvalFunctionFrame();
937       case JIT:
938         return !isEvalFrame() && isFunctionFrame();
939       case ASMJS:
940         return true;
941     }
942     MOZ_CRASH("Unexpected state");
943 }
944 
945 JSAtom*
functionDisplayAtom() const946 FrameIter::functionDisplayAtom() const
947 {
948     MOZ_ASSERT(isNonEvalFunctionFrame());
949 
950     switch (data_.state_) {
951       case DONE:
952         break;
953       case INTERP:
954       case JIT:
955         return calleeTemplate()->displayAtom();
956       case ASMJS:
957         return data_.asmJSFrames_.functionDisplayAtom();
958     }
959 
960     MOZ_CRASH("Unexpected state");
961 }
962 
963 ScriptSource*
scriptSource() const964 FrameIter::scriptSource() const
965 {
966     switch (data_.state_) {
967       case DONE:
968         break;
969       case INTERP:
970       case JIT:
971         return script()->scriptSource();
972       case ASMJS:
973         return data_.activations_->asAsmJS()->module().scriptSource();
974     }
975 
976     MOZ_CRASH("Unexpected state");
977 }
978 
979 const char*
scriptFilename() const980 FrameIter::scriptFilename() const
981 {
982     switch (data_.state_) {
983       case DONE:
984         break;
985       case INTERP:
986       case JIT:
987         return script()->filename();
988       case ASMJS:
989         return data_.activations_->asAsmJS()->module().scriptSource()->filename();
990     }
991 
992     MOZ_CRASH("Unexpected state");
993 }
994 
995 const char16_t*
scriptDisplayURL() const996 FrameIter::scriptDisplayURL() const
997 {
998     ScriptSource* ss = scriptSource();
999     return ss->hasDisplayURL() ? ss->displayURL() : nullptr;
1000 }
1001 
1002 unsigned
computeLine(uint32_t * column) const1003 FrameIter::computeLine(uint32_t* column) const
1004 {
1005     switch (data_.state_) {
1006       case DONE:
1007         break;
1008       case INTERP:
1009       case JIT:
1010         return PCToLineNumber(script(), pc(), column);
1011       case ASMJS:
1012         return data_.asmJSFrames_.computeLine(column);
1013     }
1014 
1015     MOZ_CRASH("Unexpected state");
1016 }
1017 
1018 bool
mutedErrors() const1019 FrameIter::mutedErrors() const
1020 {
1021     switch (data_.state_) {
1022       case DONE:
1023         break;
1024       case INTERP:
1025       case JIT:
1026         return script()->mutedErrors();
1027       case ASMJS:
1028         return data_.activations_->asAsmJS()->module().scriptSource()->mutedErrors();
1029     }
1030 
1031     MOZ_CRASH("Unexpected state");
1032 }
1033 
1034 bool
isConstructing() const1035 FrameIter::isConstructing() const
1036 {
1037     switch (data_.state_) {
1038       case DONE:
1039       case ASMJS:
1040         break;
1041       case JIT:
1042         if (data_.jitFrames_.isIonScripted())
1043             return ionInlineFrames_.isConstructing();
1044         MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
1045         return data_.jitFrames_.isConstructing();
1046       case INTERP:
1047         return interpFrame()->isConstructing();
1048     }
1049 
1050     MOZ_CRASH("Unexpected state");
1051 }
1052 
1053 bool
ensureHasRematerializedFrame(JSContext * cx)1054 FrameIter::ensureHasRematerializedFrame(JSContext* cx)
1055 {
1056     MOZ_ASSERT(isIon());
1057     return !!activation()->asJit()->getRematerializedFrame(cx, data_.jitFrames_);
1058 }
1059 
1060 bool
hasUsableAbstractFramePtr() const1061 FrameIter::hasUsableAbstractFramePtr() const
1062 {
1063     switch (data_.state_) {
1064       case DONE:
1065       case ASMJS:
1066         return false;
1067       case JIT:
1068         if (data_.jitFrames_.isBaselineJS())
1069             return true;
1070 
1071         MOZ_ASSERT(data_.jitFrames_.isIonScripted());
1072         return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
1073                                                                   ionInlineFrames_.frameNo());
1074         break;
1075       case INTERP:
1076         return true;
1077     }
1078     MOZ_CRASH("Unexpected state");
1079 }
1080 
1081 AbstractFramePtr
abstractFramePtr() const1082 FrameIter::abstractFramePtr() const
1083 {
1084     MOZ_ASSERT(hasUsableAbstractFramePtr());
1085     switch (data_.state_) {
1086       case DONE:
1087       case ASMJS:
1088         break;
1089       case JIT: {
1090         if (data_.jitFrames_.isBaselineJS())
1091             return data_.jitFrames_.baselineFrame();
1092 
1093         MOZ_ASSERT(data_.jitFrames_.isIonScripted());
1094         return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
1095                                                                 ionInlineFrames_.frameNo());
1096         break;
1097       }
1098       case INTERP:
1099         MOZ_ASSERT(interpFrame());
1100         return AbstractFramePtr(interpFrame());
1101     }
1102     MOZ_CRASH("Unexpected state");
1103 }
1104 
1105 void
updatePcQuadratic()1106 FrameIter::updatePcQuadratic()
1107 {
1108     switch (data_.state_) {
1109       case DONE:
1110       case ASMJS:
1111         break;
1112       case INTERP: {
1113         InterpreterFrame* frame = interpFrame();
1114         InterpreterActivation* activation = data_.activations_->asInterpreter();
1115 
1116         // Look for the current frame.
1117         data_.interpFrames_ = InterpreterFrameIterator(activation);
1118         while (data_.interpFrames_.frame() != frame)
1119             ++data_.interpFrames_;
1120 
1121         // Update the pc.
1122         MOZ_ASSERT(data_.interpFrames_.frame() == frame);
1123         data_.pc_ = data_.interpFrames_.pc();
1124         return;
1125       }
1126       case JIT:
1127         if (data_.jitFrames_.isBaselineJS()) {
1128             jit::BaselineFrame* frame = data_.jitFrames_.baselineFrame();
1129             jit::JitActivation* activation = data_.activations_->asJit();
1130 
1131             // ActivationIterator::jitTop_ may be invalid, so create a new
1132             // activation iterator.
1133             data_.activations_ = ActivationIterator(data_.cx_->runtime());
1134             while (data_.activations_.activation() != activation)
1135                 ++data_.activations_;
1136 
1137             // Look for the current frame.
1138             data_.jitFrames_ = jit::JitFrameIterator(data_.activations_);
1139             while (!data_.jitFrames_.isBaselineJS() || data_.jitFrames_.baselineFrame() != frame)
1140                 ++data_.jitFrames_;
1141 
1142             // Update the pc.
1143             MOZ_ASSERT(data_.jitFrames_.baselineFrame() == frame);
1144             data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
1145             return;
1146         }
1147         break;
1148     }
1149     MOZ_CRASH("Unexpected state");
1150 }
1151 
1152 JSFunction*
calleeTemplate() const1153 FrameIter::calleeTemplate() const
1154 {
1155     switch (data_.state_) {
1156       case DONE:
1157       case ASMJS:
1158         break;
1159       case INTERP:
1160         MOZ_ASSERT(isFunctionFrame());
1161         return &interpFrame()->callee();
1162       case JIT:
1163         if (data_.jitFrames_.isBaselineJS())
1164             return data_.jitFrames_.callee();
1165         MOZ_ASSERT(data_.jitFrames_.isIonScripted());
1166         return ionInlineFrames_.calleeTemplate();
1167     }
1168     MOZ_CRASH("Unexpected state");
1169 }
1170 
1171 JSFunction*
callee(JSContext * cx) const1172 FrameIter::callee(JSContext* cx) const
1173 {
1174     switch (data_.state_) {
1175       case DONE:
1176       case ASMJS:
1177         break;
1178       case INTERP:
1179         return calleeTemplate();
1180       case JIT:
1181         if (data_.jitFrames_.isIonScripted()) {
1182             jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
1183             return ionInlineFrames_.callee(recover);
1184         }
1185         MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
1186         return calleeTemplate();
1187     }
1188     MOZ_CRASH("Unexpected state");
1189 }
1190 
1191 bool
matchCallee(JSContext * cx,HandleFunction fun) const1192 FrameIter::matchCallee(JSContext* cx, HandleFunction fun) const
1193 {
1194     RootedFunction currentCallee(cx, calleeTemplate());
1195 
1196     // As we do not know if the calleeTemplate is the real function, or the
1197     // template from which it would be cloned, we compare properties which are
1198     // stable across the cloning of JSFunctions.
1199     if (((currentCallee->flags() ^ fun->flags()) & JSFunction::STABLE_ACROSS_CLONES) != 0 ||
1200         currentCallee->nargs() != fun->nargs())
1201     {
1202         return false;
1203     }
1204 
1205     // Use the same condition as |js::CloneFunctionObject|, to know if we should
1206     // expect both functions to have the same JSScript. If so, and if they are
1207     // different, then they cannot be equal.
1208     RootedObject global(cx, &fun->global());
1209     bool useSameScript = CanReuseScriptForClone(fun->compartment(), currentCallee, global);
1210     if (useSameScript &&
1211         (currentCallee->hasScript() != fun->hasScript() ||
1212          currentCallee->nonLazyScript() != fun->nonLazyScript()))
1213     {
1214         return false;
1215     }
1216 
1217     // If none of the previous filters worked, then take the risk of
1218     // invalidating the frame to identify the JSFunction.
1219     return callee(cx) == fun;
1220 }
1221 
1222 unsigned
numActualArgs() const1223 FrameIter::numActualArgs() const
1224 {
1225     switch (data_.state_) {
1226       case DONE:
1227       case ASMJS:
1228         break;
1229       case INTERP:
1230         MOZ_ASSERT(isFunctionFrame());
1231         return interpFrame()->numActualArgs();
1232       case JIT:
1233         if (data_.jitFrames_.isIonScripted())
1234             return ionInlineFrames_.numActualArgs();
1235 
1236         MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
1237         return data_.jitFrames_.numActualArgs();
1238     }
1239     MOZ_CRASH("Unexpected state");
1240 }
1241 
1242 unsigned
numFormalArgs() const1243 FrameIter::numFormalArgs() const
1244 {
1245     return script()->functionNonDelazifying()->nargs();
1246 }
1247 
1248 Value
unaliasedActual(unsigned i,MaybeCheckAliasing checkAliasing) const1249 FrameIter::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) const
1250 {
1251     return abstractFramePtr().unaliasedActual(i, checkAliasing);
1252 }
1253 
1254 JSObject*
scopeChain(JSContext * cx) const1255 FrameIter::scopeChain(JSContext* cx) const
1256 {
1257     switch (data_.state_) {
1258       case DONE:
1259       case ASMJS:
1260         break;
1261       case JIT:
1262         if (data_.jitFrames_.isIonScripted()) {
1263             jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
1264             return ionInlineFrames_.scopeChain(recover);
1265         }
1266         return data_.jitFrames_.baselineFrame()->scopeChain();
1267       case INTERP:
1268         return interpFrame()->scopeChain();
1269     }
1270     MOZ_CRASH("Unexpected state");
1271 }
1272 
1273 CallObject&
callObj(JSContext * cx) const1274 FrameIter::callObj(JSContext* cx) const
1275 {
1276     MOZ_ASSERT(calleeTemplate()->needsCallObject());
1277 
1278     JSObject* pobj = scopeChain(cx);
1279     while (!pobj->is<CallObject>())
1280         pobj = pobj->enclosingScope();
1281     return pobj->as<CallObject>();
1282 }
1283 
1284 bool
hasArgsObj() const1285 FrameIter::hasArgsObj() const
1286 {
1287     return abstractFramePtr().hasArgsObj();
1288 }
1289 
1290 ArgumentsObject&
argsObj() const1291 FrameIter::argsObj() const
1292 {
1293     MOZ_ASSERT(hasArgsObj());
1294     return abstractFramePtr().argsObj();
1295 }
1296 
1297 Value
thisArgument(JSContext * cx) const1298 FrameIter::thisArgument(JSContext* cx) const
1299 {
1300     MOZ_ASSERT(isNonEvalFunctionFrame());
1301 
1302     switch (data_.state_) {
1303       case DONE:
1304       case ASMJS:
1305         break;
1306       case JIT:
1307         if (data_.jitFrames_.isIonScripted()) {
1308             jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
1309             return ionInlineFrames_.thisArgument(recover);
1310         }
1311         return data_.jitFrames_.baselineFrame()->thisArgument();
1312       case INTERP:
1313         return interpFrame()->thisArgument();
1314     }
1315     MOZ_CRASH("Unexpected state");
1316 }
1317 
1318 Value
newTarget() const1319 FrameIter::newTarget() const
1320 {
1321     switch (data_.state_) {
1322       case DONE:
1323       case ASMJS:
1324         break;
1325       case INTERP:
1326         return interpFrame()->newTarget();
1327       case JIT:
1328         MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
1329         return data_.jitFrames_.baselineFrame()->newTarget();
1330     }
1331     MOZ_CRASH("Unexpected state");
1332 }
1333 
1334 Value
returnValue() const1335 FrameIter::returnValue() const
1336 {
1337     switch (data_.state_) {
1338       case DONE:
1339       case ASMJS:
1340         break;
1341       case JIT:
1342         if (data_.jitFrames_.isBaselineJS())
1343             return data_.jitFrames_.baselineFrame()->returnValue();
1344         break;
1345       case INTERP:
1346         return interpFrame()->returnValue();
1347     }
1348     MOZ_CRASH("Unexpected state");
1349 }
1350 
1351 void
setReturnValue(const Value & v)1352 FrameIter::setReturnValue(const Value& v)
1353 {
1354     switch (data_.state_) {
1355       case DONE:
1356       case ASMJS:
1357         break;
1358       case JIT:
1359         if (data_.jitFrames_.isBaselineJS()) {
1360             data_.jitFrames_.baselineFrame()->setReturnValue(v);
1361             return;
1362         }
1363         break;
1364       case INTERP:
1365         interpFrame()->setReturnValue(v);
1366         return;
1367     }
1368     MOZ_CRASH("Unexpected state");
1369 }
1370 
1371 size_t
numFrameSlots() const1372 FrameIter::numFrameSlots() const
1373 {
1374     switch (data_.state_) {
1375       case DONE:
1376       case ASMJS:
1377         break;
1378       case JIT: {
1379         if (data_.jitFrames_.isIonScripted()) {
1380             return ionInlineFrames_.snapshotIterator().numAllocations() -
1381                 ionInlineFrames_.script()->nfixed();
1382         }
1383         jit::BaselineFrame* frame = data_.jitFrames_.baselineFrame();
1384         return frame->numValueSlots() - data_.jitFrames_.script()->nfixed();
1385       }
1386       case INTERP:
1387         MOZ_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base());
1388         return data_.interpFrames_.sp() - interpFrame()->base();
1389     }
1390     MOZ_CRASH("Unexpected state");
1391 }
1392 
1393 Value
frameSlotValue(size_t index) const1394 FrameIter::frameSlotValue(size_t index) const
1395 {
1396     switch (data_.state_) {
1397       case DONE:
1398       case ASMJS:
1399         break;
1400       case JIT:
1401         if (data_.jitFrames_.isIonScripted()) {
1402             jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
1403             index += ionInlineFrames_.script()->nfixed();
1404             return si.maybeReadAllocByIndex(index);
1405         }
1406 
1407         index += data_.jitFrames_.script()->nfixed();
1408         return *data_.jitFrames_.baselineFrame()->valueSlot(index);
1409       case INTERP:
1410           return interpFrame()->base()[index];
1411     }
1412     MOZ_CRASH("Unexpected state");
1413 }
1414 
1415 #ifdef DEBUG
1416 bool
SelfHostedFramesVisible()1417 js::SelfHostedFramesVisible()
1418 {
1419     static bool checked = false;
1420     static bool visible = false;
1421     if (!checked) {
1422         checked = true;
1423         char* env = getenv("MOZ_SHOW_ALL_JS_FRAMES");
1424         visible = !!env;
1425     }
1426     return visible;
1427 }
1428 #endif
1429 
1430 void
settle()1431 NonBuiltinFrameIter::settle()
1432 {
1433     if (!SelfHostedFramesVisible()) {
1434         while (!done() && hasScript() && script()->selfHosted())
1435             FrameIter::operator++();
1436     }
1437 }
1438 
1439 void
settle()1440 NonBuiltinScriptFrameIter::settle()
1441 {
1442     if (!SelfHostedFramesVisible()) {
1443         while (!done() && script()->selfHosted())
1444             ScriptFrameIter::operator++();
1445     }
1446 }
1447 
ActivationEntryMonitor(JSContext * cx)1448 ActivationEntryMonitor::ActivationEntryMonitor(JSContext* cx)
1449   : cx_(cx), entryMonitor_(cx->runtime()->entryMonitor)
1450 {
1451     cx->runtime()->entryMonitor = nullptr;
1452 }
1453 
1454 Value
asyncStack(JSContext * cx)1455 ActivationEntryMonitor::asyncStack(JSContext* cx)
1456 {
1457     RootedValue stack(cx, ObjectOrNullValue(cx->runtime()->asyncStackForNewActivations));
1458     if (!cx->compartment()->wrap(cx, &stack)) {
1459         cx->clearPendingException();
1460         return UndefinedValue();
1461     }
1462     return stack;
1463 }
1464 
ActivationEntryMonitor(JSContext * cx,InterpreterFrame * entryFrame)1465 ActivationEntryMonitor::ActivationEntryMonitor(JSContext* cx, InterpreterFrame* entryFrame)
1466   : ActivationEntryMonitor(cx)
1467 {
1468     if (entryMonitor_) {
1469         // The InterpreterFrame is not yet part of an Activation, so it won't
1470         // be traced if we trigger GC here. Suppress GC to avoid this.
1471         gc::AutoSuppressGC suppressGC(cx);
1472         RootedValue stack(cx, asyncStack(cx));
1473         RootedString asyncCause(cx, cx->runtime()->asyncCauseForNewActivations);
1474         if (entryFrame->isFunctionFrame())
1475             entryMonitor_->Entry(cx, entryFrame->fun(), stack, asyncCause);
1476         else
1477             entryMonitor_->Entry(cx, entryFrame->script(), stack, asyncCause);
1478     }
1479 }
1480 
ActivationEntryMonitor(JSContext * cx,jit::CalleeToken entryToken)1481 ActivationEntryMonitor::ActivationEntryMonitor(JSContext* cx, jit::CalleeToken entryToken)
1482   : ActivationEntryMonitor(cx)
1483 {
1484     if (entryMonitor_) {
1485         // The CalleeToken is not traced at this point and we also don't want
1486         // a GC to discard the code we're about to enter, so we suppress GC.
1487         gc::AutoSuppressGC suppressGC(cx);
1488         RootedValue stack(cx, asyncStack(cx));
1489         RootedString asyncCause(cx, cx->runtime()->asyncCauseForNewActivations);
1490         if (jit::CalleeTokenIsFunction(entryToken))
1491             entryMonitor_->Entry(cx_, jit::CalleeTokenToFunction(entryToken), stack, asyncCause);
1492         else
1493             entryMonitor_->Entry(cx_, jit::CalleeTokenToScript(entryToken), stack, asyncCause);
1494     }
1495 }
1496 
1497 /*****************************************************************************/
1498 
JitActivation(JSContext * cx,bool active)1499 jit::JitActivation::JitActivation(JSContext* cx, bool active)
1500   : Activation(cx, Jit),
1501     active_(active),
1502     isLazyLinkExitFrame_(false),
1503     rematerializedFrames_(nullptr),
1504     ionRecovery_(cx),
1505     bailoutData_(nullptr),
1506     lastProfilingFrame_(nullptr),
1507     lastProfilingCallSite_(nullptr)
1508 {
1509     if (active) {
1510         prevJitTop_ = cx->runtime()->jitTop;
1511         prevJitJSContext_ = cx->runtime()->jitJSContext;
1512         prevJitActivation_ = cx->runtime()->jitActivation;
1513         cx->runtime()->jitJSContext = cx;
1514         cx->runtime()->jitActivation = this;
1515 
1516         registerProfiling();
1517     } else {
1518         prevJitTop_ = nullptr;
1519         prevJitJSContext_ = nullptr;
1520         prevJitActivation_ = nullptr;
1521     }
1522 }
1523 
~JitActivation()1524 jit::JitActivation::~JitActivation()
1525 {
1526     if (active_) {
1527         if (isProfiling())
1528             unregisterProfiling();
1529 
1530         cx_->runtime()->jitTop = prevJitTop_;
1531         cx_->runtime()->jitJSContext = prevJitJSContext_;
1532         cx_->runtime()->jitActivation = prevJitActivation_;
1533     }
1534 
1535     // All reocvered value are taken from activation during the bailout.
1536     MOZ_ASSERT(ionRecovery_.empty());
1537 
1538     // The BailoutFrameInfo should have unregistered itself from the
1539     // JitActivations.
1540     MOZ_ASSERT(!bailoutData_);
1541 
1542     clearRematerializedFrames();
1543     js_delete(rematerializedFrames_);
1544 }
1545 
1546 bool
isProfiling() const1547 jit::JitActivation::isProfiling() const
1548 {
1549     // All JitActivations can be profiled.
1550     return true;
1551 }
1552 
1553 void
setBailoutData(jit::BailoutFrameInfo * bailoutData)1554 jit::JitActivation::setBailoutData(jit::BailoutFrameInfo* bailoutData)
1555 {
1556     MOZ_ASSERT(!bailoutData_);
1557     bailoutData_ = bailoutData;
1558 }
1559 
1560 void
cleanBailoutData()1561 jit::JitActivation::cleanBailoutData()
1562 {
1563     MOZ_ASSERT(bailoutData_);
1564     bailoutData_ = nullptr;
1565 }
1566 
1567 // setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so
1568 // changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable
1569 // and disable activation instruction sequences.
1570 void
setActive(JSContext * cx,bool active)1571 jit::JitActivation::setActive(JSContext* cx, bool active)
1572 {
1573     // Only allowed to deactivate/activate if activation is top.
1574     // (Not tested and will probably fail in other situations.)
1575     MOZ_ASSERT(cx->runtime()->activation_ == this);
1576     MOZ_ASSERT(active != active_);
1577 
1578     if (active) {
1579         *((volatile bool*) active_) = true;
1580         prevJitTop_ = cx->runtime()->jitTop;
1581         prevJitJSContext_ = cx->runtime()->jitJSContext;
1582         prevJitActivation_ = cx->runtime()->jitActivation;
1583         cx->runtime()->jitJSContext = cx;
1584         cx->runtime()->jitActivation = this;
1585 
1586         registerProfiling();
1587 
1588     } else {
1589         unregisterProfiling();
1590 
1591         cx->runtime()->jitTop = prevJitTop_;
1592         cx->runtime()->jitJSContext = prevJitJSContext_;
1593         cx->runtime()->jitActivation = prevJitActivation_;
1594 
1595         *((volatile bool*) active_) = false;
1596     }
1597 }
1598 
1599 void
removeRematerializedFrame(uint8_t * top)1600 jit::JitActivation::removeRematerializedFrame(uint8_t* top)
1601 {
1602     if (!rematerializedFrames_)
1603         return;
1604 
1605     if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) {
1606         RematerializedFrame::FreeInVector(p->value());
1607         rematerializedFrames_->remove(p);
1608     }
1609 }
1610 
1611 void
clearRematerializedFrames()1612 jit::JitActivation::clearRematerializedFrames()
1613 {
1614     if (!rematerializedFrames_)
1615         return;
1616 
1617     for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront()) {
1618         RematerializedFrame::FreeInVector(e.front().value());
1619         e.removeFront();
1620     }
1621 }
1622 
1623 jit::RematerializedFrame*
getRematerializedFrame(JSContext * cx,const JitFrameIterator & iter,size_t inlineDepth)1624 jit::JitActivation::getRematerializedFrame(JSContext* cx, const JitFrameIterator& iter, size_t inlineDepth)
1625 {
1626     MOZ_ASSERT(iter.activation() == this);
1627     MOZ_ASSERT(iter.isIonScripted());
1628 
1629     if (!rematerializedFrames_) {
1630         rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx);
1631         if (!rematerializedFrames_)
1632             return nullptr;
1633         if (!rematerializedFrames_->init()) {
1634             rematerializedFrames_ = nullptr;
1635             ReportOutOfMemory(cx);
1636             return nullptr;
1637         }
1638     }
1639 
1640     uint8_t* top = iter.fp();
1641     RematerializedFrameTable::AddPtr p = rematerializedFrames_->lookupForAdd(top);
1642     if (!p) {
1643         RematerializedFrameVector empty(cx);
1644         if (!rematerializedFrames_->add(p, top, Move(empty))) {
1645             ReportOutOfMemory(cx);
1646             return nullptr;
1647         }
1648 
1649         // The unit of rematerialization is an uninlined frame and its inlined
1650         // frames. Since inlined frames do not exist outside of snapshots, it
1651         // is impossible to synchronize their rematerialized copies to
1652         // preserve identity. Therefore, we always rematerialize an uninlined
1653         // frame and all its inlined frames at once.
1654         InlineFrameIterator inlineIter(cx, &iter);
1655         MaybeReadFallback recover(cx, this, &iter);
1656 
1657         // Frames are often rematerialized with the cx inside a Debugger's
1658         // compartment. To recover slots and to create CallObjects, we need to
1659         // be in the activation's compartment.
1660         AutoCompartment ac(cx, compartment_);
1661 
1662         if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, recover,
1663                                                             p->value()))
1664         {
1665             return nullptr;
1666         }
1667 
1668         // See comment in unsetPrevUpToDateUntil.
1669         DebugScopes::unsetPrevUpToDateUntil(cx, p->value()[inlineDepth]);
1670     }
1671 
1672     return p->value()[inlineDepth];
1673 }
1674 
1675 jit::RematerializedFrame*
lookupRematerializedFrame(uint8_t * top,size_t inlineDepth)1676 jit::JitActivation::lookupRematerializedFrame(uint8_t* top, size_t inlineDepth)
1677 {
1678     if (!rematerializedFrames_)
1679         return nullptr;
1680     if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top))
1681         return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr;
1682     return nullptr;
1683 }
1684 
1685 void
removeRematerializedFramesFromDebugger(JSContext * cx,uint8_t * top)1686 jit::JitActivation::removeRematerializedFramesFromDebugger(JSContext* cx, uint8_t* top)
1687 {
1688     // Ion bailout can fail due to overrecursion and OOM. In such cases we
1689     // cannot honor any further Debugger hooks on the frame, and need to
1690     // ensure that its Debugger.Frame entry is cleaned up.
1691     if (!cx->compartment()->isDebuggee() || !rematerializedFrames_)
1692         return;
1693     if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) {
1694         for (uint32_t i = 0; i < p->value().length(); i++)
1695             Debugger::handleUnrecoverableIonBailoutError(cx, p->value()[i]);
1696     }
1697 }
1698 
1699 void
markRematerializedFrames(JSTracer * trc)1700 jit::JitActivation::markRematerializedFrames(JSTracer* trc)
1701 {
1702     if (!rematerializedFrames_)
1703         return;
1704     for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront())
1705         RematerializedFrame::MarkInVector(trc, e.front().value());
1706 }
1707 
1708 bool
registerIonFrameRecovery(RInstructionResults && results)1709 jit::JitActivation::registerIonFrameRecovery(RInstructionResults&& results)
1710 {
1711     // Check that there is no entry in the vector yet.
1712     MOZ_ASSERT(!maybeIonFrameRecovery(results.frame()));
1713     if (!ionRecovery_.append(mozilla::Move(results)))
1714         return false;
1715 
1716     return true;
1717 }
1718 
1719 jit::RInstructionResults*
maybeIonFrameRecovery(JitFrameLayout * fp)1720 jit::JitActivation::maybeIonFrameRecovery(JitFrameLayout* fp)
1721 {
1722     for (RInstructionResults* it = ionRecovery_.begin(); it != ionRecovery_.end(); ) {
1723         if (it->frame() == fp)
1724             return it;
1725     }
1726 
1727     return nullptr;
1728 }
1729 
1730 void
removeIonFrameRecovery(JitFrameLayout * fp)1731 jit::JitActivation::removeIonFrameRecovery(JitFrameLayout* fp)
1732 {
1733     RInstructionResults* elem = maybeIonFrameRecovery(fp);
1734     if (!elem)
1735         return;
1736 
1737     ionRecovery_.erase(elem);
1738 }
1739 
1740 void
markIonRecovery(JSTracer * trc)1741 jit::JitActivation::markIonRecovery(JSTracer* trc)
1742 {
1743     for (RInstructionResults* it = ionRecovery_.begin(); it != ionRecovery_.end(); it++)
1744         it->trace(trc);
1745 }
1746 
AsmJSActivation(JSContext * cx,AsmJSModule & module)1747 AsmJSActivation::AsmJSActivation(JSContext* cx, AsmJSModule& module)
1748   : Activation(cx, AsmJS),
1749     module_(module),
1750     entrySP_(nullptr),
1751     resumePC_(nullptr),
1752     fp_(nullptr),
1753     packedExitReason_(wasm::ExitReason(wasm::ExitReason::None).pack())
1754 {
1755     (void) entrySP_;  // squelch GCC warning
1756 
1757     prevAsmJSForModule_ = module.activation();
1758     module.activation() = this;
1759 
1760     prevAsmJS_ = cx->runtime()->asmJSActivationStack_;
1761     cx->runtime()->asmJSActivationStack_ = this;
1762 
1763     // Now that the AsmJSActivation is fully initialized, make it visible to
1764     // asynchronous profiling.
1765     registerProfiling();
1766 }
1767 
~AsmJSActivation()1768 AsmJSActivation::~AsmJSActivation()
1769 {
1770     // Hide this activation from the profiler before is is destroyed.
1771     unregisterProfiling();
1772 
1773     MOZ_ASSERT(fp_ == nullptr);
1774 
1775     MOZ_ASSERT(module_.activation() == this);
1776     module_.activation() = prevAsmJSForModule_;
1777 
1778     JSContext* cx = cx_->asJSContext();
1779     MOZ_ASSERT(cx->runtime()->asmJSActivationStack_ == this);
1780 
1781     cx->runtime()->asmJSActivationStack_ = prevAsmJS_;
1782 }
1783 
1784 InterpreterFrameIterator&
operator ++()1785 InterpreterFrameIterator::operator++()
1786 {
1787     MOZ_ASSERT(!done());
1788     if (fp_ != activation_->entryFrame_) {
1789         pc_ = fp_->prevpc();
1790         sp_ = fp_->prevsp();
1791         fp_ = fp_->prev();
1792     } else {
1793         pc_ = nullptr;
1794         sp_ = nullptr;
1795         fp_ = nullptr;
1796     }
1797     return *this;
1798 }
1799 
1800 void
registerProfiling()1801 Activation::registerProfiling()
1802 {
1803     MOZ_ASSERT(isProfiling());
1804     cx_->runtime()->profilingActivation_ = this;
1805 }
1806 
1807 void
unregisterProfiling()1808 Activation::unregisterProfiling()
1809 {
1810     MOZ_ASSERT(isProfiling());
1811     MOZ_ASSERT(cx_->runtime()->profilingActivation_ == this);
1812 
1813     // There may be a non-active jit activation in the linked list.  Skip past it.
1814     Activation* prevProfiling = prevProfiling_;
1815     while (prevProfiling && prevProfiling->isJit() && !prevProfiling->asJit()->isActive())
1816         prevProfiling = prevProfiling->prevProfiling_;
1817 
1818     cx_->runtime()->profilingActivation_ = prevProfiling;
1819 }
1820 
ActivationIterator(JSRuntime * rt)1821 ActivationIterator::ActivationIterator(JSRuntime* rt)
1822   : jitTop_(rt->jitTop),
1823     activation_(rt->activation_)
1824 {
1825     settle();
1826 }
1827 
1828 ActivationIterator&
operator ++()1829 ActivationIterator::operator++()
1830 {
1831     MOZ_ASSERT(activation_);
1832     if (activation_->isJit() && activation_->asJit()->isActive())
1833         jitTop_ = activation_->asJit()->prevJitTop();
1834     activation_ = activation_->prev();
1835     settle();
1836     return *this;
1837 }
1838 
1839 void
settle()1840 ActivationIterator::settle()
1841 {
1842     // Stop at the next active activation. No need to update jitTop_, since
1843     // we don't iterate over an active jit activation.
1844     while (!done() && activation_->isJit() && !activation_->asJit()->isActive())
1845         activation_ = activation_->prev();
1846 }
1847 
ProfilingFrameIterator(JSRuntime * rt,const RegisterState & state,uint32_t sampleBufferGen)1848 JS::ProfilingFrameIterator::ProfilingFrameIterator(JSRuntime* rt, const RegisterState& state,
1849                                                    uint32_t sampleBufferGen)
1850   : rt_(rt),
1851     sampleBufferGen_(sampleBufferGen),
1852     activation_(nullptr),
1853     savedPrevJitTop_(nullptr)
1854 {
1855     if (!rt->spsProfiler.enabled())
1856         MOZ_CRASH("ProfilingFrameIterator called when spsProfiler not enabled for runtime.");
1857 
1858     if (!rt->profilingActivation())
1859         return;
1860 
1861     // If profiler sampling is not enabled, skip.
1862     if (!rt_->isProfilerSamplingEnabled())
1863         return;
1864 
1865     activation_ = rt->profilingActivation();
1866 
1867     MOZ_ASSERT(activation_->isProfiling());
1868 
1869     static_assert(sizeof(AsmJSProfilingFrameIterator) <= StorageSpace &&
1870                   sizeof(jit::JitProfilingFrameIterator) <= StorageSpace,
1871                   "Need to increase storage");
1872 
1873     iteratorConstruct(state);
1874     settle();
1875 }
1876 
~ProfilingFrameIterator()1877 JS::ProfilingFrameIterator::~ProfilingFrameIterator()
1878 {
1879     if (!done()) {
1880         MOZ_ASSERT(activation_->isProfiling());
1881         iteratorDestroy();
1882     }
1883 }
1884 
1885 void
operator ++()1886 JS::ProfilingFrameIterator::operator++()
1887 {
1888     MOZ_ASSERT(!done());
1889     MOZ_ASSERT(activation_->isAsmJS() || activation_->isJit());
1890 
1891     if (activation_->isAsmJS()) {
1892         ++asmJSIter();
1893         settle();
1894         return;
1895     }
1896 
1897     ++jitIter();
1898     settle();
1899 }
1900 
1901 void
settle()1902 JS::ProfilingFrameIterator::settle()
1903 {
1904     while (iteratorDone()) {
1905         iteratorDestroy();
1906         activation_ = activation_->prevProfiling();
1907 
1908         // Skip past any non-active jit activations in the list.
1909         while (activation_ && activation_->isJit() && !activation_->asJit()->isActive())
1910             activation_ = activation_->prevProfiling();
1911 
1912         if (!activation_)
1913             return;
1914         iteratorConstruct();
1915     }
1916 }
1917 
1918 void
iteratorConstruct(const RegisterState & state)1919 JS::ProfilingFrameIterator::iteratorConstruct(const RegisterState& state)
1920 {
1921     MOZ_ASSERT(!done());
1922     MOZ_ASSERT(activation_->isAsmJS() || activation_->isJit());
1923 
1924     if (activation_->isAsmJS()) {
1925         new (storage_.addr()) AsmJSProfilingFrameIterator(*activation_->asAsmJS(), state);
1926         // Set savedPrevJitTop_ to the actual jitTop_ from the runtime.
1927         savedPrevJitTop_ = activation_->cx()->runtime()->jitTop;
1928         return;
1929     }
1930 
1931     MOZ_ASSERT(activation_->asJit()->isActive());
1932     new (storage_.addr()) jit::JitProfilingFrameIterator(rt_, state);
1933 }
1934 
1935 void
iteratorConstruct()1936 JS::ProfilingFrameIterator::iteratorConstruct()
1937 {
1938     MOZ_ASSERT(!done());
1939     MOZ_ASSERT(activation_->isAsmJS() || activation_->isJit());
1940 
1941     if (activation_->isAsmJS()) {
1942         new (storage_.addr()) AsmJSProfilingFrameIterator(*activation_->asAsmJS());
1943         return;
1944     }
1945 
1946     MOZ_ASSERT(activation_->asJit()->isActive());
1947     MOZ_ASSERT(savedPrevJitTop_ != nullptr);
1948     new (storage_.addr()) jit::JitProfilingFrameIterator(savedPrevJitTop_);
1949 }
1950 
1951 void
iteratorDestroy()1952 JS::ProfilingFrameIterator::iteratorDestroy()
1953 {
1954     MOZ_ASSERT(!done());
1955     MOZ_ASSERT(activation_->isAsmJS() || activation_->isJit());
1956 
1957     if (activation_->isAsmJS()) {
1958         asmJSIter().~AsmJSProfilingFrameIterator();
1959         return;
1960     }
1961 
1962     // Save prevjitTop for later use
1963     savedPrevJitTop_ = activation_->asJit()->prevJitTop();
1964     jitIter().~JitProfilingFrameIterator();
1965 }
1966 
1967 bool
iteratorDone()1968 JS::ProfilingFrameIterator::iteratorDone()
1969 {
1970     MOZ_ASSERT(!done());
1971     MOZ_ASSERT(activation_->isAsmJS() || activation_->isJit());
1972 
1973     if (activation_->isAsmJS())
1974         return asmJSIter().done();
1975 
1976     return jitIter().done();
1977 }
1978 
1979 void*
stackAddress() const1980 JS::ProfilingFrameIterator::stackAddress() const
1981 {
1982     MOZ_ASSERT(!done());
1983     MOZ_ASSERT(activation_->isAsmJS() || activation_->isJit());
1984 
1985     if (activation_->isAsmJS())
1986         return asmJSIter().stackAddress();
1987 
1988     return jitIter().stackAddress();
1989 }
1990 
1991 Maybe<JS::ProfilingFrameIterator::Frame>
getPhysicalFrameAndEntry(jit::JitcodeGlobalEntry * entry) const1992 JS::ProfilingFrameIterator::getPhysicalFrameAndEntry(jit::JitcodeGlobalEntry* entry) const
1993 {
1994     void* stackAddr = stackAddress();
1995 
1996     if (isAsmJS()) {
1997         Frame frame;
1998         frame.kind = Frame_AsmJS;
1999         frame.stackAddress = stackAddr;
2000         frame.returnAddress = nullptr;
2001         frame.activation = activation_;
2002         frame.label = nullptr;
2003         return mozilla::Some(frame);
2004     }
2005 
2006     MOZ_ASSERT(isJit());
2007 
2008     // Look up an entry for the return address.
2009     void* returnAddr = jitIter().returnAddressToFp();
2010     jit::JitcodeGlobalTable* table = rt_->jitRuntime()->getJitcodeGlobalTable();
2011     if (hasSampleBufferGen())
2012         table->lookupForSampler(returnAddr, entry, rt_, sampleBufferGen_);
2013     else
2014         table->lookupInfallible(returnAddr, entry, rt_);
2015 
2016     MOZ_ASSERT(entry->isIon() || entry->isIonCache() || entry->isBaseline() || entry->isDummy());
2017 
2018     // Dummy frames produce no stack frames.
2019     if (entry->isDummy())
2020         return mozilla::Nothing();
2021 
2022     Frame frame;
2023     frame.kind = entry->isBaseline() ? Frame_Baseline : Frame_Ion;
2024     frame.stackAddress = stackAddr;
2025     frame.returnAddress = returnAddr;
2026     frame.activation = activation_;
2027     frame.label = nullptr;
2028     return mozilla::Some(frame);
2029 }
2030 
2031 uint32_t
extractStack(Frame * frames,uint32_t offset,uint32_t end) const2032 JS::ProfilingFrameIterator::extractStack(Frame* frames, uint32_t offset, uint32_t end) const
2033 {
2034     if (offset >= end)
2035         return 0;
2036 
2037     jit::JitcodeGlobalEntry entry;
2038     Maybe<Frame> physicalFrame = getPhysicalFrameAndEntry(&entry);
2039 
2040     // Dummy frames produce no stack frames.
2041     if (physicalFrame.isNothing())
2042         return 0;
2043 
2044     if (isAsmJS()) {
2045         frames[offset] = physicalFrame.value();
2046         frames[offset].label = asmJSIter().label();
2047         return 1;
2048     }
2049 
2050     // Extract the stack for the entry.  Assume maximum inlining depth is <64
2051     const char* labels[64];
2052     uint32_t depth = entry.callStackAtAddr(rt_, jitIter().returnAddressToFp(), labels, 64);
2053     MOZ_ASSERT(depth < 64);
2054     for (uint32_t i = 0; i < depth; i++) {
2055         if (offset + i >= end)
2056             return i;
2057         frames[offset + i] = physicalFrame.value();
2058         frames[offset + i].label = labels[i];
2059     }
2060 
2061     return depth;
2062 }
2063 
2064 Maybe<JS::ProfilingFrameIterator::Frame>
getPhysicalFrameWithoutLabel() const2065 JS::ProfilingFrameIterator::getPhysicalFrameWithoutLabel() const
2066 {
2067     jit::JitcodeGlobalEntry unused;
2068     return getPhysicalFrameAndEntry(&unused);
2069 }
2070 
2071 bool
isAsmJS() const2072 JS::ProfilingFrameIterator::isAsmJS() const
2073 {
2074     MOZ_ASSERT(!done());
2075     return activation_->isAsmJS();
2076 }
2077 
2078 bool
isJit() const2079 JS::ProfilingFrameIterator::isJit() const
2080 {
2081     return activation_->isJit();
2082 }
2083