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