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 : #ifndef vm_Stack_h
8 : #define vm_Stack_h
9 :
10 : #include "mozilla/Atomics.h"
11 : #include "mozilla/Maybe.h"
12 : #include "mozilla/MemoryReporting.h"
13 : #include "mozilla/Variant.h"
14 :
15 : #include "jsfun.h"
16 : #include "jsscript.h"
17 : #include "jsutil.h"
18 :
19 : #include "gc/Rooting.h"
20 : #include "jit/JitFrameIterator.h"
21 : #ifdef CHECK_OSIPOINT_REGISTERS
22 : #include "jit/Registers.h" // for RegisterDump
23 : #endif
24 : #include "js/RootingAPI.h"
25 : #include "vm/ArgumentsObject.h"
26 : #include "vm/SavedFrame.h"
27 : #include "wasm/WasmFrameIterator.h"
28 : #include "wasm/WasmTypes.h"
29 :
30 : struct JSCompartment;
31 :
32 : namespace JS {
33 : namespace dbg {
34 : #ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING
35 : #pragma GCC diagnostic push
36 : #pragma GCC diagnostic ignored "-Wattributes"
37 : #endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING
38 :
39 : class JS_PUBLIC_API(AutoEntryMonitor);
40 :
41 : #ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING
42 : #pragma GCC diagnostic pop
43 : #endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING
44 : } // namespace dbg
45 : } // namespace JS
46 :
47 : namespace js {
48 :
49 : class InterpreterRegs;
50 : class CallObject;
51 : class FrameIter;
52 : class EnvironmentObject;
53 : class ScriptFrameIter;
54 : class GeckoProfiler;
55 : class InterpreterFrame;
56 : class LexicalEnvironmentObject;
57 : class EnvironmentIter;
58 : class EnvironmentCoordinate;
59 :
60 : class SavedFrame;
61 :
62 : namespace jit {
63 : class CommonFrameLayout;
64 : }
65 : namespace wasm {
66 : class DebugFrame;
67 : class Instance;
68 : }
69 :
70 : // VM stack layout
71 : //
72 : // A JSRuntime's stack consists of a linked list of activations. Every activation
73 : // contains a number of scripted frames that are either running in the interpreter
74 : // (InterpreterActivation) or JIT code (JitActivation). The frames inside a single
75 : // activation are contiguous: whenever C++ calls back into JS, a new activation is
76 : // pushed.
77 : //
78 : // Every activation is tied to a single JSContext and JSCompartment. This means we
79 : // can reconstruct a given context's stack by skipping activations belonging to other
80 : // contexts. This happens whenever an embedding enters the JS engine on cx1 and
81 : // then, from a native called by the JS engine, reenters the VM on cx2.
82 :
83 : // Interpreter frames (InterpreterFrame)
84 : //
85 : // Each interpreter script activation (global or function code) is given a
86 : // fixed-size header (js::InterpreterFrame). The frame contains bookkeeping
87 : // information about the activation and links to the previous frame.
88 : //
89 : // The values after an InterpreterFrame in memory are its locals followed by its
90 : // expression stack. InterpreterFrame::argv_ points to the frame's arguments.
91 : // Missing formal arguments are padded with |undefined|, so the number of
92 : // arguments is always >= the number of formals.
93 : //
94 : // The top of an activation's current frame's expression stack is pointed to by
95 : // the activation's "current regs", which contains the stack pointer 'sp'. In
96 : // the interpreter, sp is adjusted as individual values are pushed and popped
97 : // from the stack and the InterpreterRegs struct (pointed to by the
98 : // InterpreterActivation) is a local var of js::Interpret.
99 :
100 : enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false };
101 : enum MaybeCheckTDZ { CheckTDZ = true, DontCheckTDZ = false };
102 :
103 : /*****************************************************************************/
104 :
105 : namespace jit {
106 : class BaselineFrame;
107 : class RematerializedFrame;
108 : } // namespace jit
109 :
110 : /*
111 : * Pointer to either a ScriptFrameIter::Data, an InterpreterFrame, or a Baseline
112 : * JIT frame.
113 : *
114 : * The Debugger may cache ScriptFrameIter::Data as a bookmark to reconstruct a
115 : * ScriptFrameIter without doing a full stack walk.
116 : *
117 : * There is no way to directly create such an AbstractFramePtr. To do so, the
118 : * user must call ScriptFrameIter::copyDataAsAbstractFramePtr().
119 : *
120 : * ScriptFrameIter::abstractFramePtr() will never return an AbstractFramePtr
121 : * that is in fact a ScriptFrameIter::Data.
122 : *
123 : * To recover a ScriptFrameIter settled at the location pointed to by an
124 : * AbstractFramePtr, use the THIS_FRAME_ITER macro in Debugger.cpp. As an
125 : * aside, no asScriptFrameIterData() is provided because C++ is stupid and
126 : * cannot forward declare inner classes.
127 : */
128 :
129 : class AbstractFramePtr
130 : {
131 : friend class FrameIter;
132 :
133 : uintptr_t ptr_;
134 :
135 : enum {
136 : Tag_ScriptFrameIterData = 0x0,
137 : Tag_InterpreterFrame = 0x1,
138 : Tag_BaselineFrame = 0x2,
139 : Tag_RematerializedFrame = 0x3,
140 : Tag_WasmDebugFrame = 0x4,
141 : TagMask = 0x7
142 : };
143 :
144 : public:
145 12757 : AbstractFramePtr()
146 12757 : : ptr_(0)
147 12757 : {}
148 :
149 65008 : MOZ_IMPLICIT AbstractFramePtr(InterpreterFrame* fp)
150 65008 : : ptr_(fp ? uintptr_t(fp) | Tag_InterpreterFrame : 0)
151 : {
152 65008 : MOZ_ASSERT_IF(fp, asInterpreterFrame() == fp);
153 65008 : }
154 :
155 18261 : MOZ_IMPLICIT AbstractFramePtr(jit::BaselineFrame* fp)
156 18261 : : ptr_(fp ? uintptr_t(fp) | Tag_BaselineFrame : 0)
157 : {
158 18261 : MOZ_ASSERT_IF(fp, asBaselineFrame() == fp);
159 18261 : }
160 :
161 0 : MOZ_IMPLICIT AbstractFramePtr(jit::RematerializedFrame* fp)
162 0 : : ptr_(fp ? uintptr_t(fp) | Tag_RematerializedFrame : 0)
163 : {
164 0 : MOZ_ASSERT_IF(fp, asRematerializedFrame() == fp);
165 0 : }
166 :
167 0 : MOZ_IMPLICIT AbstractFramePtr(wasm::DebugFrame* fp)
168 0 : : ptr_(fp ? uintptr_t(fp) | Tag_WasmDebugFrame : 0)
169 : {
170 : static_assert(wasm::DebugFrame::Alignment >= TagMask, "aligned");
171 0 : MOZ_ASSERT_IF(fp, asWasmDebugFrame() == fp);
172 0 : }
173 :
174 0 : static AbstractFramePtr FromRaw(void* raw) {
175 0 : AbstractFramePtr frame;
176 0 : frame.ptr_ = uintptr_t(raw);
177 0 : return frame;
178 : }
179 :
180 0 : bool isScriptFrameIterData() const {
181 0 : return !!ptr_ && (ptr_ & TagMask) == Tag_ScriptFrameIterData;
182 : }
183 574268 : bool isInterpreterFrame() const {
184 574268 : return (ptr_ & TagMask) == Tag_InterpreterFrame;
185 : }
186 290524 : InterpreterFrame* asInterpreterFrame() const {
187 290524 : MOZ_ASSERT(isInterpreterFrame());
188 290524 : InterpreterFrame* res = (InterpreterFrame*)(ptr_ & ~TagMask);
189 290524 : MOZ_ASSERT(res);
190 290524 : return res;
191 : }
192 134251 : bool isBaselineFrame() const {
193 134251 : return (ptr_ & TagMask) == Tag_BaselineFrame;
194 : }
195 76281 : jit::BaselineFrame* asBaselineFrame() const {
196 76281 : MOZ_ASSERT(isBaselineFrame());
197 76281 : jit::BaselineFrame* res = (jit::BaselineFrame*)(ptr_ & ~TagMask);
198 76281 : MOZ_ASSERT(res);
199 76281 : return res;
200 : }
201 0 : bool isRematerializedFrame() const {
202 0 : return (ptr_ & TagMask) == Tag_RematerializedFrame;
203 : }
204 0 : jit::RematerializedFrame* asRematerializedFrame() const {
205 0 : MOZ_ASSERT(isRematerializedFrame());
206 0 : jit::RematerializedFrame* res = (jit::RematerializedFrame*)(ptr_ & ~TagMask);
207 0 : MOZ_ASSERT(res);
208 0 : return res;
209 : }
210 111586 : bool isWasmDebugFrame() const {
211 111586 : return (ptr_ & TagMask) == Tag_WasmDebugFrame;
212 : }
213 0 : wasm::DebugFrame* asWasmDebugFrame() const {
214 0 : MOZ_ASSERT(isWasmDebugFrame());
215 0 : wasm::DebugFrame* res = (wasm::DebugFrame*)(ptr_ & ~TagMask);
216 0 : MOZ_ASSERT(res);
217 0 : return res;
218 : }
219 :
220 0 : void* raw() const { return reinterpret_cast<void*>(ptr_); }
221 :
222 1640 : bool operator ==(const AbstractFramePtr& other) const { return ptr_ == other.ptr_; }
223 0 : bool operator !=(const AbstractFramePtr& other) const { return ptr_ != other.ptr_; }
224 :
225 113007 : explicit operator bool() const { return !!ptr_; }
226 :
227 : inline JSObject* environmentChain() const;
228 : inline CallObject& callObj() const;
229 : inline bool initFunctionEnvironmentObjects(JSContext* cx);
230 : inline bool pushVarEnvironment(JSContext* cx, HandleScope scope);
231 : template <typename SpecificEnvironment>
232 : inline void pushOnEnvironmentChain(SpecificEnvironment& env);
233 : template <typename SpecificEnvironment>
234 : inline void popOffEnvironmentChain();
235 :
236 : inline JSCompartment* compartment() const;
237 :
238 : inline bool hasInitialEnvironment() const;
239 : inline bool isGlobalFrame() const;
240 : inline bool isModuleFrame() const;
241 : inline bool isEvalFrame() const;
242 : inline bool isDebuggerEvalFrame() const;
243 : inline bool hasCachedSavedFrame() const;
244 : inline void setHasCachedSavedFrame();
245 :
246 : inline bool hasScript() const;
247 : inline JSScript* script() const;
248 : inline wasm::Instance* wasmInstance() const;
249 : inline GlobalObject* global() const;
250 : inline JSFunction* callee() const;
251 : inline Value calleev() const;
252 : inline Value& thisArgument() const;
253 :
254 : inline Value newTarget() const;
255 :
256 : inline bool debuggerNeedsCheckPrimitiveReturn() const;
257 :
258 : inline bool isFunctionFrame() const;
259 : inline bool isNonStrictDirectEvalFrame() const;
260 : inline bool isStrictEvalFrame() const;
261 :
262 : inline unsigned numActualArgs() const;
263 : inline unsigned numFormalArgs() const;
264 :
265 : inline Value* argv() const;
266 :
267 : inline bool hasArgs() const;
268 : inline bool hasArgsObj() const;
269 : inline ArgumentsObject& argsObj() const;
270 : inline void initArgsObj(ArgumentsObject& argsobj) const;
271 : inline bool createSingleton() const;
272 :
273 : inline Value& unaliasedLocal(uint32_t i);
274 : inline Value& unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
275 : inline Value& unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
276 : template <class Op> inline void unaliasedForEachActual(JSContext* cx, Op op);
277 :
278 : inline bool prevUpToDate() const;
279 : inline void setPrevUpToDate() const;
280 : inline void unsetPrevUpToDate() const;
281 :
282 : inline bool isDebuggee() const;
283 : inline void setIsDebuggee();
284 : inline void unsetIsDebuggee();
285 :
286 : inline HandleValue returnValue() const;
287 : inline void setReturnValue(const Value& rval) const;
288 :
289 : friend void GDBTestInitAbstractFramePtr(AbstractFramePtr&, void*);
290 : friend void GDBTestInitAbstractFramePtr(AbstractFramePtr&, InterpreterFrame*);
291 : friend void GDBTestInitAbstractFramePtr(AbstractFramePtr&, jit::BaselineFrame*);
292 : friend void GDBTestInitAbstractFramePtr(AbstractFramePtr&, jit::RematerializedFrame*);
293 : friend void GDBTestInitAbstractFramePtr(AbstractFramePtr& frame, wasm::DebugFrame* ptr);
294 : };
295 :
296 : class NullFramePtr : public AbstractFramePtr
297 : {
298 : public:
299 12757 : NullFramePtr()
300 12757 : : AbstractFramePtr()
301 12757 : { }
302 : };
303 :
304 : enum MaybeConstruct { NO_CONSTRUCT = false, CONSTRUCT = true };
305 :
306 : /*****************************************************************************/
307 :
308 : class InterpreterFrame
309 : {
310 : enum Flags : uint32_t {
311 : CONSTRUCTING = 0x1, /* frame is for a constructor invocation */
312 :
313 : RESUMED_GENERATOR = 0x2, /* frame is for a resumed generator invocation */
314 :
315 : /* Function prologue state */
316 : HAS_INITIAL_ENV = 0x4, /* callobj created for function or var env for eval */
317 : HAS_ARGS_OBJ = 0x8, /* ArgumentsObject created for needsArgsObj script */
318 :
319 : /* Lazy frame initialization */
320 : HAS_RVAL = 0x10, /* frame has rval_ set */
321 :
322 : /* Debugger state */
323 : PREV_UP_TO_DATE = 0x20, /* see DebugScopes::updateLiveScopes */
324 :
325 : /*
326 : * See comment above 'isDebuggee' in jscompartment.h for explanation of
327 : * invariants of debuggee compartments, scripts, and frames.
328 : */
329 : DEBUGGEE = 0x40, /* Execution is being observed by Debugger */
330 :
331 : /* Used in tracking calls and profiling (see vm/GeckoProfiler.cpp) */
332 : HAS_PUSHED_PROF_FRAME = 0x80, /* Gecko Profiler was notified of entry */
333 :
334 : /*
335 : * If set, we entered one of the JITs and ScriptFrameIter should skip
336 : * this frame.
337 : */
338 : RUNNING_IN_JIT = 0x100,
339 :
340 : /* Miscellaneous state. */
341 : CREATE_SINGLETON = 0x200, /* Constructed |this| object should be singleton. */
342 :
343 : /*
344 : * If set, this frame has been on the stack when
345 : * |js::SavedStacks::saveCurrentStack| was called, and so there is a
346 : * |js::SavedFrame| object cached for this frame.
347 : */
348 : HAS_CACHED_SAVED_FRAME = 0x400,
349 : };
350 :
351 : mutable uint32_t flags_; /* bits described by Flags */
352 : uint32_t nactual_; /* number of actual arguments, for function frames */
353 : JSScript* script_; /* the script we're executing */
354 : JSObject* envChain_; /* current environment chain */
355 : Value rval_; /* if HAS_RVAL, return value of the frame */
356 : ArgumentsObject* argsObj_; /* if HAS_ARGS_OBJ, the call's arguments object */
357 :
358 : /*
359 : * Previous frame and its pc and sp. Always nullptr for
360 : * InterpreterActivation's entry frame, always non-nullptr for inline
361 : * frames.
362 : */
363 : InterpreterFrame* prev_;
364 : jsbytecode* prevpc_;
365 : Value* prevsp_;
366 :
367 : void* unused;
368 :
369 : /*
370 : * For an eval-in-frame DEBUGGER_EVAL frame, the frame in whose scope
371 : * we're evaluating code. Iteration treats this as our previous frame.
372 : */
373 : AbstractFramePtr evalInFramePrev_;
374 :
375 : Value* argv_; /* If hasArgs(), points to frame's arguments. */
376 : LifoAlloc::Mark mark_; /* Used to release memory for this frame. */
377 :
378 : static void staticAsserts() {
379 : JS_STATIC_ASSERT(offsetof(InterpreterFrame, rval_) % sizeof(Value) == 0);
380 : JS_STATIC_ASSERT(sizeof(InterpreterFrame) % sizeof(Value) == 0);
381 : }
382 :
383 : /*
384 : * The utilities are private since they are not able to assert that only
385 : * unaliased vars/formals are accessed. Normal code should prefer the
386 : * InterpreterFrame::unaliased* members (or InterpreterRegs::stackDepth for
387 : * the usual "depth is at least" assertions).
388 : */
389 304695 : Value* slots() const { return (Value*)(this + 1); }
390 194492 : Value* base() const { return slots() + script()->nfixed(); }
391 :
392 : friend class FrameIter;
393 : friend class InterpreterRegs;
394 : friend class InterpreterStack;
395 : friend class jit::BaselineFrame;
396 :
397 : /*
398 : * Frame initialization, called by InterpreterStack operations after acquiring
399 : * the raw memory for the frame:
400 : */
401 :
402 : /* Used for Invoke and Interpret. */
403 : void initCallFrame(JSContext* cx, InterpreterFrame* prev, jsbytecode* prevpc, Value* prevsp,
404 : JSFunction& callee, JSScript* script, Value* argv, uint32_t nactual,
405 : MaybeConstruct constructing);
406 :
407 : /* Used for global and eval frames. */
408 : void initExecuteFrame(JSContext* cx, HandleScript script, AbstractFramePtr prev,
409 : const Value& newTargetValue, HandleObject envChain);
410 :
411 : public:
412 : /*
413 : * Frame prologue/epilogue
414 : *
415 : * Every stack frame must have 'prologue' called before executing the
416 : * first op and 'epilogue' called after executing the last op and before
417 : * popping the frame (whether the exit is exceptional or not).
418 : *
419 : * For inline JS calls/returns, it is easy to call the prologue/epilogue
420 : * exactly once. When calling JS from C++, Invoke/Execute push the stack
421 : * frame but do *not* call the prologue/epilogue. That means Interpret
422 : * must call the prologue/epilogue for the entry frame. This scheme
423 : * simplifies jit compilation.
424 : *
425 : * An important corner case is what happens when an error occurs (OOM,
426 : * over-recursed) after pushing the stack frame but before 'prologue' is
427 : * called or completes fully. To simplify usage, 'epilogue' does not assume
428 : * 'prologue' has completed and handles all the intermediate state details.
429 : */
430 :
431 : bool prologue(JSContext* cx);
432 : void epilogue(JSContext* cx, jsbytecode* pc);
433 :
434 : bool checkReturn(JSContext* cx, HandleValue thisv);
435 :
436 : bool initFunctionEnvironmentObjects(JSContext* cx);
437 :
438 : /*
439 : * Initialize locals of newly-pushed frame to undefined.
440 : */
441 : void initLocals();
442 :
443 : /*
444 : * Stack frame type
445 : *
446 : * A stack frame may have one of four types, which determines which
447 : * members of the frame may be accessed and other invariants:
448 : *
449 : * global frame: execution of global code
450 : * function frame: execution of function code
451 : * module frame: execution of a module
452 : * eval frame: execution of eval code
453 : */
454 :
455 12585 : bool isGlobalFrame() const {
456 12585 : return script_->isGlobalCode();
457 : }
458 :
459 11603 : bool isModuleFrame() const {
460 11603 : return script_->module();
461 : }
462 :
463 46424 : bool isEvalFrame() const {
464 46424 : return script_->isForEval();
465 : }
466 :
467 405585 : bool isFunctionFrame() const {
468 405585 : return script_->functionNonDelazifying();
469 : }
470 :
471 : inline bool isStrictEvalFrame() const {
472 : return isEvalFrame() && script()->strict();
473 : }
474 :
475 : bool isNonStrictEvalFrame() const {
476 : return isEvalFrame() && !script()->strict();
477 : }
478 :
479 : bool isNonGlobalEvalFrame() const;
480 :
481 : bool isNonStrictDirectEvalFrame() const {
482 : return isNonStrictEvalFrame() && isNonGlobalEvalFrame();
483 : }
484 :
485 : /*
486 : * Previous frame
487 : *
488 : * A frame's 'prev' frame is either null or the previous frame pointed to
489 : * by cx->regs->fp when this frame was pushed. Often, given two prev-linked
490 : * frames, the next-frame is a function or eval that was called by the
491 : * prev-frame, but not always: the prev-frame may have called a native that
492 : * reentered the VM through JS_CallFunctionValue on the same context
493 : * (without calling JS_SaveFrameChain) which pushed the next-frame. Thus,
494 : * 'prev' has little semantic meaning and basically just tells the VM what
495 : * to set cx->regs->fp to when this frame is popped.
496 : */
497 :
498 3222 : InterpreterFrame* prev() const {
499 3222 : return prev_;
500 : }
501 :
502 0 : AbstractFramePtr evalInFramePrev() const {
503 0 : MOZ_ASSERT(isEvalFrame());
504 0 : return evalInFramePrev_;
505 : }
506 :
507 : /*
508 : * (Unaliased) locals and arguments
509 : *
510 : * Only non-eval function frames have arguments. The arguments pushed by
511 : * the caller are the 'actual' arguments. The declared arguments of the
512 : * callee are the 'formal' arguments. When the caller passes less actual
513 : * arguments, missing formal arguments are padded with |undefined|.
514 : *
515 : * When a local/formal variable is aliased (accessed by nested closures,
516 : * environment operations, or 'arguments'), the canonical location for
517 : * that value is the slot of an environment object. Aliased locals don't
518 : * have stack slots assigned to them. These functions assert that
519 : * accesses to stack values are unaliased.
520 : */
521 :
522 : inline Value& unaliasedLocal(uint32_t i);
523 :
524 156778 : bool hasArgs() const { return isFunctionFrame(); }
525 : inline Value& unaliasedFormal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
526 : inline Value& unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
527 : template <class Op> inline void unaliasedForEachActual(Op op);
528 :
529 24510 : unsigned numFormalArgs() const { MOZ_ASSERT(hasArgs()); return callee().nargs(); }
530 5546 : unsigned numActualArgs() const { MOZ_ASSERT(hasArgs()); return nactual_; }
531 :
532 : /* Watch out, this exposes a pointer to the unaliased formal arg array. */
533 126617 : Value* argv() const { MOZ_ASSERT(hasArgs()); return argv_; }
534 :
535 : /*
536 : * Arguments object
537 : *
538 : * If a non-eval function has script->needsArgsObj, an arguments object is
539 : * created in the prologue and stored in the local variable for the
540 : * 'arguments' binding (script->argumentsLocal). Since this local is
541 : * mutable, the arguments object can be overwritten and we can "lose" the
542 : * arguments object. Thus, InterpreterFrame keeps an explicit argsObj_ field so
543 : * that the original arguments object is always available.
544 : */
545 :
546 : ArgumentsObject& argsObj() const;
547 : void initArgsObj(ArgumentsObject& argsobj);
548 :
549 : JSObject* createRestParameter(JSContext* cx);
550 :
551 : /*
552 : * Environment chain
553 : *
554 : * In theory, the environment chain would contain an object for every
555 : * lexical scope. However, only objects that are required for dynamic
556 : * lookup are actually created.
557 : *
558 : * Given that an InterpreterFrame corresponds roughly to a ES Execution
559 : * Context (ES 10.3), InterpreterFrame::varObj corresponds to the
560 : * VariableEnvironment component of a Exection Context. Intuitively, the
561 : * variables object is where new bindings (variables and functions) are
562 : * stored. One might expect that this is either the Call object or
563 : * envChain.globalObj for function or global code, respectively, however
564 : * the JSAPI allows calls of Execute to specify a variables object on the
565 : * environment chain other than the call/global object. This allows
566 : * embeddings to run multiple scripts under the same global, each time
567 : * using a new variables object to collect and discard the script's global
568 : * variables.
569 : */
570 :
571 : inline HandleObject environmentChain() const;
572 :
573 : inline EnvironmentObject& aliasedEnvironment(EnvironmentCoordinate ec) const;
574 : inline GlobalObject& global() const;
575 : inline CallObject& callObj() const;
576 : inline JSObject& varObj() const;
577 : inline LexicalEnvironmentObject& extensibleLexicalEnvironment() const;
578 :
579 : template <typename SpecificEnvironment>
580 : inline void pushOnEnvironmentChain(SpecificEnvironment& env);
581 : template <typename SpecificEnvironment>
582 : inline void popOffEnvironmentChain();
583 : inline void replaceInnermostEnvironment(EnvironmentObject& env);
584 :
585 : // Push a VarEnvironmentObject for function frames of functions that have
586 : // parameter expressions with closed over var bindings.
587 : bool pushVarEnvironment(JSContext* cx, HandleScope scope);
588 :
589 : /*
590 : * For lexical envs with aliased locals, these interfaces push and pop
591 : * entries on the environment chain. The "freshen" operation replaces the
592 : * current lexical env with a fresh copy of it, to implement semantics
593 : * providing distinct bindings per iteration of a for(;;) loop whose head
594 : * has a lexical declaration. The "recreate" operation replaces the
595 : * current lexical env with a copy of it containing uninitialized
596 : * bindings, to implement semantics providing distinct bindings per
597 : * iteration of a for-in/of loop.
598 : */
599 :
600 : bool pushLexicalEnvironment(JSContext* cx, Handle<LexicalScope*> scope);
601 : bool freshenLexicalEnvironment(JSContext* cx);
602 : bool recreateLexicalEnvironment(JSContext* cx);
603 :
604 : /*
605 : * Script
606 : *
607 : * All frames have an associated JSScript which holds the bytecode being
608 : * executed for the frame.
609 : */
610 :
611 571927 : JSScript* script() const {
612 571927 : return script_;
613 : }
614 :
615 : /* Return the previous frame's pc. */
616 3222 : jsbytecode* prevpc() {
617 3222 : MOZ_ASSERT(prev_);
618 3222 : return prevpc_;
619 : }
620 :
621 : /* Return the previous frame's sp. */
622 3222 : Value* prevsp() {
623 3222 : MOZ_ASSERT(prev_);
624 3222 : return prevsp_;
625 : }
626 :
627 : /*
628 : * Return the 'this' argument passed to a non-eval function frame. This is
629 : * not necessarily the frame's this-binding, for instance non-strict
630 : * functions will box primitive 'this' values and thisArgument() will
631 : * return the original, unboxed Value.
632 : */
633 12470 : Value& thisArgument() const {
634 12470 : MOZ_ASSERT(isFunctionFrame());
635 12470 : return argv()[-1];
636 : }
637 :
638 : /*
639 : * Callee
640 : *
641 : * Only function frames have a callee. An eval frame in a function has the
642 : * same callee as its containing function frame.
643 : */
644 :
645 89472 : JSFunction& callee() const {
646 89472 : MOZ_ASSERT(isFunctionFrame());
647 89472 : return calleev().toObject().as<JSFunction>();
648 : }
649 :
650 89485 : const Value& calleev() const {
651 89485 : MOZ_ASSERT(isFunctionFrame());
652 89485 : return argv()[-2];
653 : }
654 :
655 : /*
656 : * New Target
657 : *
658 : * Only function frames have a meaningful newTarget. An eval frame in a
659 : * function will have a copy of the newTarget of the enclosing function
660 : * frame.
661 : */
662 693 : Value newTarget() const {
663 693 : if (isEvalFrame())
664 0 : return ((Value*)this)[-1];
665 :
666 693 : MOZ_ASSERT(isFunctionFrame());
667 :
668 693 : if (callee().isArrow())
669 96 : return callee().getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
670 :
671 597 : if (isConstructing()) {
672 113 : unsigned pushedArgs = Max(numFormalArgs(), numActualArgs());
673 113 : return argv()[pushedArgs];
674 : }
675 484 : return UndefinedValue();
676 : }
677 :
678 : /* Profiler flags */
679 :
680 44354 : bool hasPushedGeckoProfilerFrame() {
681 44354 : return !!(flags_ & HAS_PUSHED_PROF_FRAME);
682 : }
683 :
684 0 : void setPushedGeckoProfilerFrame() {
685 0 : flags_ |= HAS_PUSHED_PROF_FRAME;
686 0 : }
687 :
688 : void unsetPushedGeckoProfilerFrame() {
689 : flags_ &= ~HAS_PUSHED_PROF_FRAME;
690 : }
691 :
692 : /* Return value */
693 :
694 12963 : bool hasReturnValue() const {
695 12963 : return flags_ & HAS_RVAL;
696 : }
697 :
698 12717 : MutableHandleValue returnValue() {
699 12717 : if (!hasReturnValue())
700 3072 : rval_.setUndefined();
701 12717 : return MutableHandleValue::fromMarkedLocation(&rval_);
702 : }
703 :
704 10004 : void markReturnValue() {
705 10004 : flags_ |= HAS_RVAL;
706 10004 : }
707 :
708 10004 : void setReturnValue(const Value& v) {
709 10004 : rval_ = v;
710 10004 : markReturnValue();
711 10004 : }
712 :
713 : void clearReturnValue() {
714 : rval_.setUndefined();
715 : markReturnValue();
716 : }
717 :
718 198 : void resumeGeneratorFrame(JSObject* envChain) {
719 198 : MOZ_ASSERT(script()->isStarGenerator() || script()->isLegacyGenerator() ||
720 : script()->isAsync());
721 198 : MOZ_ASSERT(isFunctionFrame());
722 198 : flags_ |= HAS_INITIAL_ENV;
723 198 : envChain_ = envChain;
724 198 : }
725 :
726 : /*
727 : * Other flags
728 : */
729 :
730 25572 : bool isConstructing() const {
731 25572 : return !!(flags_ & CONSTRUCTING);
732 : }
733 :
734 198 : void setResumedGenerator() {
735 198 : flags_ |= RESUMED_GENERATOR;
736 198 : }
737 1869 : bool isResumedGenerator() const {
738 1869 : return !!(flags_ & RESUMED_GENERATOR);
739 : }
740 :
741 : /*
742 : * These two queries should not be used in general: the presence/absence of
743 : * the call/args object is determined by the static(ish) properties of the
744 : * JSFunction/JSScript. These queries should only be performed when probing
745 : * a stack frame that may be in the middle of the prologue (during which
746 : * time the call/args object are created).
747 : */
748 :
749 : inline bool hasInitialEnvironment() const;
750 :
751 141 : bool hasInitialEnvironmentUnchecked() const {
752 141 : return flags_ & HAS_INITIAL_ENV;
753 : }
754 :
755 0 : bool hasArgsObj() const {
756 0 : MOZ_ASSERT(script()->needsArgsObj());
757 0 : return flags_ & HAS_ARGS_OBJ;
758 : }
759 :
760 0 : void setCreateSingleton() {
761 0 : MOZ_ASSERT(isConstructing());
762 0 : flags_ |= CREATE_SINGLETON;
763 0 : }
764 0 : bool createSingleton() const {
765 0 : MOZ_ASSERT(isConstructing());
766 0 : return flags_ & CREATE_SINGLETON;
767 : }
768 :
769 : /*
770 : * Debugger eval frames.
771 : *
772 : * - If evalInFramePrev_ is non-null, frame was created for an "eval in
773 : * frame" call, which can push a successor to any live frame; so its
774 : * logical "prev" frame is not necessarily the previous frame in memory.
775 : * Iteration should treat evalInFramePrev_ as this frame's previous frame.
776 : *
777 : * - Don't bother to JIT it, because it's probably short-lived.
778 : *
779 : * - It is required to have a environment chain object outside the
780 : * js::EnvironmentObject hierarchy: either a global object, or a
781 : * DebugEnvironmentProxy.
782 : */
783 9771 : bool isDebuggerEvalFrame() const {
784 9771 : return isEvalFrame() && !!evalInFramePrev_;
785 : }
786 :
787 0 : bool prevUpToDate() const {
788 0 : return !!(flags_ & PREV_UP_TO_DATE);
789 : }
790 :
791 0 : void setPrevUpToDate() {
792 0 : flags_ |= PREV_UP_TO_DATE;
793 0 : }
794 :
795 0 : void unsetPrevUpToDate() {
796 0 : flags_ &= ~PREV_UP_TO_DATE;
797 0 : }
798 :
799 26818 : bool isDebuggee() const {
800 26818 : return !!(flags_ & DEBUGGEE);
801 : }
802 :
803 0 : void setIsDebuggee() {
804 0 : flags_ |= DEBUGGEE;
805 0 : }
806 :
807 : inline void unsetIsDebuggee();
808 :
809 4900 : bool hasCachedSavedFrame() const {
810 4900 : return flags_ & HAS_CACHED_SAVED_FRAME;
811 : }
812 2170 : void setHasCachedSavedFrame() {
813 2170 : flags_ |= HAS_CACHED_SAVED_FRAME;
814 2170 : }
815 :
816 : public:
817 : void trace(JSTracer* trc, Value* sp, jsbytecode* pc);
818 : void traceValues(JSTracer* trc, unsigned start, unsigned end);
819 :
820 : // Entered Baseline/Ion from the interpreter.
821 40067 : bool runningInJit() const {
822 40067 : return !!(flags_ & RUNNING_IN_JIT);
823 : }
824 141 : void setRunningInJit() {
825 141 : flags_ |= RUNNING_IN_JIT;
826 141 : }
827 141 : void clearRunningInJit() {
828 141 : flags_ &= ~RUNNING_IN_JIT;
829 141 : }
830 : };
831 :
832 : /*****************************************************************************/
833 :
834 : class InterpreterRegs
835 : {
836 : public:
837 : Value* sp;
838 : jsbytecode* pc;
839 : private:
840 : InterpreterFrame* fp_;
841 : public:
842 366288 : InterpreterFrame* fp() const { return fp_; }
843 :
844 96996 : unsigned stackDepth() const {
845 96996 : MOZ_ASSERT(sp >= fp_->base());
846 96996 : return sp - fp_->base();
847 : }
848 :
849 482 : Value* spForStackDepth(unsigned depth) const {
850 482 : MOZ_ASSERT(fp_->script()->nfixed() + depth <= fp_->script()->nslots());
851 482 : return fp_->base() + depth;
852 : }
853 :
854 : /* For generators. */
855 : void rebaseFromTo(const InterpreterRegs& from, InterpreterFrame& to) {
856 : fp_ = &to;
857 : sp = to.slots() + (from.sp - from.fp_->slots());
858 : pc = from.pc;
859 : MOZ_ASSERT(fp_);
860 : }
861 :
862 1869 : void popInlineFrame() {
863 1869 : pc = fp_->prevpc();
864 1869 : unsigned spForNewTarget = fp_->isResumedGenerator() ? 0 : fp_->isConstructing();
865 1869 : sp = fp_->prevsp() - fp_->numActualArgs() - 1 - spForNewTarget;
866 1869 : fp_ = fp_->prev();
867 1869 : MOZ_ASSERT(fp_);
868 1869 : }
869 12299 : void prepareToRun(InterpreterFrame& fp, JSScript* script) {
870 12299 : pc = script->code();
871 12299 : sp = fp.slots() + script->nfixed();
872 12299 : fp_ = &fp;
873 12299 : }
874 :
875 : void setToEndOfScript();
876 :
877 122265 : MutableHandleValue stackHandleAt(int i) {
878 122265 : return MutableHandleValue::fromMarkedLocation(&sp[i]);
879 : }
880 :
881 : HandleValue stackHandleAt(int i) const {
882 : return HandleValue::fromMarkedLocation(&sp[i]);
883 : }
884 :
885 : friend void GDBTestInitInterpreterRegs(InterpreterRegs&, js::InterpreterFrame*,
886 : JS::Value*, uint8_t*);
887 : };
888 :
889 : /*****************************************************************************/
890 :
891 : class InterpreterStack
892 : {
893 : friend class InterpreterActivation;
894 :
895 : static const size_t DEFAULT_CHUNK_SIZE = 4 * 1024;
896 : LifoAlloc allocator_;
897 :
898 : // Number of interpreter frames on the stack, for over-recursion checks.
899 : static const size_t MAX_FRAMES = 50 * 1000;
900 : static const size_t MAX_FRAMES_TRUSTED = MAX_FRAMES + 1000;
901 : size_t frameCount_;
902 :
903 : inline uint8_t* allocateFrame(JSContext* cx, size_t size);
904 :
905 : inline InterpreterFrame*
906 : getCallFrame(JSContext* cx, const CallArgs& args, HandleScript script,
907 : MaybeConstruct constructing, Value** pargv);
908 :
909 12288 : void releaseFrame(InterpreterFrame* fp) {
910 12288 : frameCount_--;
911 12288 : allocator_.release(fp->mark_);
912 12288 : }
913 :
914 : public:
915 40 : InterpreterStack()
916 40 : : allocator_(DEFAULT_CHUNK_SIZE),
917 40 : frameCount_(0)
918 40 : { }
919 :
920 0 : ~InterpreterStack() {
921 0 : MOZ_ASSERT(frameCount_ == 0);
922 0 : }
923 :
924 : // For execution of eval or global code.
925 : InterpreterFrame* pushExecuteFrame(JSContext* cx, HandleScript script,
926 : const Value& newTargetValue, HandleObject envChain,
927 : AbstractFramePtr evalInFrame);
928 :
929 : // Called to invoke a function.
930 : InterpreterFrame* pushInvokeFrame(JSContext* cx, const CallArgs& args,
931 : MaybeConstruct constructing);
932 :
933 : // The interpreter can push light-weight, "inline" frames without entering a
934 : // new InterpreterActivation or recursively calling Interpret.
935 : bool pushInlineFrame(JSContext* cx, InterpreterRegs& regs, const CallArgs& args,
936 : HandleScript script, MaybeConstruct constructing);
937 :
938 : void popInlineFrame(InterpreterRegs& regs);
939 :
940 : bool resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs,
941 : HandleFunction callee, HandleValue newTarget,
942 : HandleObject envChain);
943 :
944 : inline void purge(JSRuntime* rt);
945 :
946 0 : size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
947 0 : return allocator_.sizeOfExcludingThis(mallocSizeOf);
948 : }
949 : };
950 :
951 : // CooperatingContext is a wrapper for a JSContext that is participating in
952 : // cooperative scheduling and may be different from the current thread. It is
953 : // in place to make it clearer when we might be operating on another thread,
954 : // and harder to accidentally pass in another thread's context to an API that
955 : // expects the current thread's context.
956 : class CooperatingContext
957 : {
958 : JSContext* cx;
959 :
960 : public:
961 5263 : explicit CooperatingContext(JSContext* cx) : cx(cx) {}
962 1030449 : JSContext* context() const { return cx; }
963 :
964 : // For &cx. The address should not be taken for other CooperatingContexts.
965 : friend class ZoneGroup;
966 : };
967 :
968 : void TraceInterpreterActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc);
969 :
970 : /*****************************************************************************/
971 :
972 : /** Base class for all function call args. */
973 15385 : class AnyInvokeArgs : public JS::CallArgs
974 : {
975 : };
976 :
977 : /** Base class for all function construction args. */
978 178 : class AnyConstructArgs : public JS::CallArgs
979 : {
980 : // Only js::Construct (or internal methods that call the qualified CallArgs
981 : // versions) should do these things!
982 : void setCallee(const Value& v) = delete;
983 : void setThis(const Value& v) = delete;
984 : MutableHandleValue newTarget() const = delete;
985 : MutableHandleValue rval() const = delete;
986 : };
987 :
988 : namespace detail {
989 :
990 : /** Function call/construct args of statically-unknown count. */
991 : template <MaybeConstruct Construct>
992 7595 : class GenericArgsBase
993 : : public mozilla::Conditional<Construct, AnyConstructArgs, AnyInvokeArgs>::Type
994 : {
995 : protected:
996 : AutoValueVector v_;
997 :
998 7597 : explicit GenericArgsBase(JSContext* cx) : v_(cx) {}
999 :
1000 : public:
1001 7597 : bool init(JSContext* cx, unsigned argc) {
1002 7597 : if (argc > ARGS_LENGTH_MAX) {
1003 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TOO_MANY_ARGUMENTS);
1004 0 : return false;
1005 : }
1006 :
1007 : // callee, this, arguments[, new.target iff constructing]
1008 7597 : size_t len = 2 + argc + uint32_t(Construct);
1009 7597 : MOZ_ASSERT(len > argc); // no overflow
1010 7597 : if (!v_.resize(len))
1011 0 : return false;
1012 :
1013 7597 : *static_cast<JS::CallArgs*>(this) = CallArgsFromVp(argc, v_.begin());
1014 7597 : this->constructing_ = Construct;
1015 : if (Construct)
1016 175 : this->CallArgs::setThis(MagicValue(JS_IS_CONSTRUCTING));
1017 7597 : return true;
1018 : }
1019 : };
1020 :
1021 : /** Function call/construct args of statically-known count. */
1022 : template <MaybeConstruct Construct, size_t N>
1023 7965 : class FixedArgsBase
1024 : : public mozilla::Conditional<Construct, AnyConstructArgs, AnyInvokeArgs>::Type
1025 : {
1026 : static_assert(N <= ARGS_LENGTH_MAX, "o/~ too many args o/~");
1027 :
1028 : protected:
1029 : JS::AutoValueArray<2 + N + uint32_t(Construct)> v_;
1030 :
1031 7966 : explicit FixedArgsBase(JSContext* cx) : v_(cx) {
1032 7966 : *static_cast<JS::CallArgs*>(this) = CallArgsFromVp(N, v_.begin());
1033 7966 : this->constructing_ = Construct;
1034 : if (Construct)
1035 3 : this->CallArgs::setThis(MagicValue(JS_IS_CONSTRUCTING));
1036 7966 : }
1037 : };
1038 :
1039 : } // namespace detail
1040 :
1041 : /** Function call args of statically-unknown count. */
1042 7418 : class InvokeArgs : public detail::GenericArgsBase<NO_CONSTRUCT>
1043 : {
1044 : using Base = detail::GenericArgsBase<NO_CONSTRUCT>;
1045 :
1046 : public:
1047 7420 : explicit InvokeArgs(JSContext* cx) : Base(cx) {}
1048 : };
1049 :
1050 : /** Function call args of statically-unknown count. */
1051 2 : class InvokeArgsMaybeIgnoresReturnValue : public detail::GenericArgsBase<NO_CONSTRUCT>
1052 : {
1053 : using Base = detail::GenericArgsBase<NO_CONSTRUCT>;
1054 :
1055 : public:
1056 2 : explicit InvokeArgsMaybeIgnoresReturnValue(JSContext* cx, bool ignoresReturnValue) : Base(cx) {
1057 2 : this->ignoresReturnValue_ = ignoresReturnValue;
1058 2 : }
1059 : };
1060 :
1061 : /** Function call args of statically-known count. */
1062 : template <size_t N>
1063 7962 : class FixedInvokeArgs : public detail::FixedArgsBase<NO_CONSTRUCT, N>
1064 : {
1065 : using Base = detail::FixedArgsBase<NO_CONSTRUCT, N>;
1066 :
1067 : public:
1068 7963 : explicit FixedInvokeArgs(JSContext* cx) : Base(cx) {}
1069 : };
1070 :
1071 : /** Function construct args of statically-unknown count. */
1072 175 : class ConstructArgs : public detail::GenericArgsBase<CONSTRUCT>
1073 : {
1074 : using Base = detail::GenericArgsBase<CONSTRUCT>;
1075 :
1076 : public:
1077 175 : explicit ConstructArgs(JSContext* cx) : Base(cx) {}
1078 : };
1079 :
1080 : /** Function call args of statically-known count. */
1081 : template <size_t N>
1082 3 : class FixedConstructArgs : public detail::FixedArgsBase<CONSTRUCT, N>
1083 : {
1084 : using Base = detail::FixedArgsBase<CONSTRUCT, N>;
1085 :
1086 : public:
1087 3 : explicit FixedConstructArgs(JSContext* cx) : Base(cx) {}
1088 : };
1089 :
1090 : template <class Args, class Arraylike>
1091 : inline bool
1092 6989 : FillArgumentsFromArraylike(JSContext* cx, Args& args, const Arraylike& arraylike)
1093 : {
1094 6989 : uint32_t len = arraylike.length();
1095 6989 : if (!args.init(cx, len))
1096 0 : return false;
1097 :
1098 17299 : for (uint32_t i = 0; i < len; i++)
1099 10310 : args[i].set(arraylike[i]);
1100 :
1101 6989 : return true;
1102 : }
1103 :
1104 : template <>
1105 : struct DefaultHasher<AbstractFramePtr> {
1106 : typedef AbstractFramePtr Lookup;
1107 :
1108 0 : static js::HashNumber hash(const Lookup& key) {
1109 0 : return size_t(key.raw());
1110 : }
1111 :
1112 0 : static bool match(const AbstractFramePtr& k, const Lookup& l) {
1113 0 : return k == l;
1114 : }
1115 : };
1116 :
1117 : /*****************************************************************************/
1118 :
1119 : // SavedFrame caching to minimize stack walking.
1120 : //
1121 : // SavedFrames are hash consed to minimize expensive (with regards to both space
1122 : // and time) allocations in the face of many stack frames that tend to share the
1123 : // same older tail frames. Despite that, in scenarios where we are frequently
1124 : // saving the same or similar stacks, such as when the Debugger's allocation
1125 : // site tracking is enabled, these older stack frames still get walked
1126 : // repeatedly just to create the lookup structs to find their corresponding
1127 : // SavedFrames in the hash table. This stack walking is slow, and we would like
1128 : // to minimize it.
1129 : //
1130 : // We have reserved a bit on most of SpiderMonkey's various frame
1131 : // representations (the exceptions being asm and inlined ion frames). As we
1132 : // create SavedFrame objects for live stack frames in SavedStacks::insertFrames,
1133 : // we set this bit and append the SavedFrame object to the cache. As we walk the
1134 : // stack, if we encounter a frame that has this bit set, that indicates that we
1135 : // have already captured a SavedFrame object for the given stack frame (but not
1136 : // necessarily the current pc) during a previous call to insertFrames. We know
1137 : // that the frame's parent was also captured and has its bit set as well, but
1138 : // additionally we know the parent was captured at its current pc. For the
1139 : // parent, rather than continuing the expensive stack walk, we do a quick and
1140 : // cache-friendly linear search through the frame cache. Upon finishing search
1141 : // through the frame cache, stale entries are removed.
1142 : //
1143 : // The frame cache maintains the invariant that its first E[0] .. E[j-1]
1144 : // entries are live and sorted from oldest to younger frames, where 0 < j < n
1145 : // and n = the length of the cache. When searching the cache, we require
1146 : // that we are considering the youngest live frame whose bit is set. Every
1147 : // cache entry E[i] where i >= j is a stale entry. Consider the following
1148 : // scenario:
1149 : //
1150 : // P > Q > R > S Initial stack, bits not set.
1151 : // P* > Q* > R* > S* Capture a SavedFrame stack, set bits.
1152 : // P* > Q* > R* Return from S.
1153 : // P* > Q* Return from R.
1154 : // P* > Q* > T Call T, its bit is not set.
1155 : //
1156 : // The frame cache was populated with [P, Q, R, S] when we captured a
1157 : // SavedFrame stack, but because we returned from frames R and S, their
1158 : // entries in the frame cache are now stale. This fact is unbeknownst to us
1159 : // because we do not observe frame pops. Upon capturing a second stack, we
1160 : // start stack walking at the youngest frame T, which does not have its bit
1161 : // set and must take the hash table lookup slow path rather than the frame
1162 : // cache short circuit. Next we proceed to Q and find that it has its bit
1163 : // set, and it is therefore the youngest live frame with its bit set. We
1164 : // search through the frame cache from oldest to youngest and find the cache
1165 : // entry matching Q. We know that T is the next younger live frame from Q
1166 : // and that T does not have an entry in the frame cache because its bit was
1167 : // not set. Therefore, we have found entry E[j-1] and the subsequent entries
1168 : // are stale and should be purged from the frame cache.
1169 : //
1170 : // We have a LiveSavedFrameCache for each activation to minimize the number of
1171 : // entries that must be scanned through, and to avoid the headaches of
1172 : // maintaining a cache for each compartment and invalidating stale cache entries
1173 : // in the presence of cross-compartment calls.
1174 : class LiveSavedFrameCache
1175 : {
1176 : public:
1177 : using FramePtr = mozilla::Variant<AbstractFramePtr, jit::CommonFrameLayout*>;
1178 :
1179 : private:
1180 3769 : struct Entry
1181 : {
1182 : FramePtr framePtr;
1183 : jsbytecode* pc;
1184 : HeapPtr<SavedFrame*> savedFrame;
1185 :
1186 2641 : Entry(FramePtr& framePtr, jsbytecode* pc, SavedFrame* savedFrame)
1187 2641 : : framePtr(framePtr)
1188 : , pc(pc)
1189 2641 : , savedFrame(savedFrame)
1190 2641 : { }
1191 : };
1192 :
1193 : using EntryVector = Vector<Entry, 0, SystemAllocPolicy>;
1194 : EntryVector* frames;
1195 :
1196 : LiveSavedFrameCache(const LiveSavedFrameCache&) = delete;
1197 : LiveSavedFrameCache& operator=(const LiveSavedFrameCache&) = delete;
1198 :
1199 : public:
1200 18100 : explicit LiveSavedFrameCache() : frames(nullptr) { }
1201 :
1202 18100 : LiveSavedFrameCache(LiveSavedFrameCache&& rhs)
1203 18100 : : frames(rhs.frames)
1204 : {
1205 18100 : MOZ_ASSERT(this != &rhs, "self-move disallowed");
1206 18100 : rhs.frames = nullptr;
1207 18100 : }
1208 :
1209 72384 : ~LiveSavedFrameCache() {
1210 36192 : if (frames) {
1211 645 : js_delete(frames);
1212 645 : frames = nullptr;
1213 : }
1214 36192 : }
1215 :
1216 8422 : bool initialized() const { return !!frames; }
1217 645 : bool init(JSContext* cx) {
1218 645 : frames = js_new<EntryVector>();
1219 645 : if (!frames) {
1220 0 : JS_ReportOutOfMemory(cx);
1221 0 : return false;
1222 : }
1223 645 : return true;
1224 : }
1225 :
1226 : static mozilla::Maybe<FramePtr> getFramePtr(FrameIter& iter);
1227 : void trace(JSTracer* trc);
1228 :
1229 : void find(JSContext* cx, FrameIter& frameIter, MutableHandleSavedFrame frame) const;
1230 : bool insert(JSContext* cx, FramePtr& framePtr, jsbytecode* pc, HandleSavedFrame savedFrame);
1231 : };
1232 :
1233 : static_assert(sizeof(LiveSavedFrameCache) == sizeof(uintptr_t),
1234 : "Every js::Activation has a LiveSavedFrameCache, so we need to be pretty careful "
1235 : "about avoiding bloat. If you're adding members to LiveSavedFrameCache, maybe you "
1236 : "should consider figuring out a way to make js::Activation have a "
1237 : "LiveSavedFrameCache* instead of a Rooted<LiveSavedFrameCache>.");
1238 :
1239 : /*****************************************************************************/
1240 :
1241 : class InterpreterActivation;
1242 : class WasmActivation;
1243 :
1244 : namespace jit {
1245 : class JitActivation;
1246 : } // namespace jit
1247 :
1248 : // This class is separate from Activation, because it calls JSCompartment::wrap()
1249 : // which can GC and walk the stack. It's not safe to do that within the
1250 : // JitActivation constructor.
1251 : class MOZ_RAII ActivationEntryMonitor
1252 : {
1253 : JSContext* cx_;
1254 :
1255 : // The entry point monitor that was set on cx_->runtime() when this
1256 : // ActivationEntryMonitor was created.
1257 : JS::dbg::AutoEntryMonitor* entryMonitor_;
1258 :
1259 : explicit ActivationEntryMonitor(JSContext* cx);
1260 :
1261 : ActivationEntryMonitor(const ActivationEntryMonitor& other) = delete;
1262 : void operator=(const ActivationEntryMonitor& other) = delete;
1263 :
1264 : Value asyncStack(JSContext* cx);
1265 :
1266 : public:
1267 : ActivationEntryMonitor(JSContext* cx, InterpreterFrame* entryFrame);
1268 : ActivationEntryMonitor(JSContext* cx, jit::CalleeToken entryToken);
1269 : inline ~ActivationEntryMonitor();
1270 : };
1271 :
1272 : class Activation
1273 : {
1274 : protected:
1275 : JSContext* cx_;
1276 : JSCompartment* compartment_;
1277 : Activation* prev_;
1278 : Activation* prevProfiling_;
1279 :
1280 : // Counter incremented by JS::HideScriptedCaller and decremented by
1281 : // JS::UnhideScriptedCaller. If > 0 for the top activation,
1282 : // DescribeScriptedCaller will return null instead of querying that
1283 : // activation, which should prompt the caller to consult embedding-specific
1284 : // data structures instead.
1285 : size_t hideScriptedCallerCount_;
1286 :
1287 : // The cache of SavedFrame objects we have already captured when walking
1288 : // this activation's stack.
1289 : Rooted<LiveSavedFrameCache> frameCache_;
1290 :
1291 : // Youngest saved frame of an async stack that will be iterated during stack
1292 : // capture in place of the actual stack of previous activations. Note that
1293 : // the stack of this activation is captured entirely before this is used.
1294 : //
1295 : // Usually this is nullptr, meaning that normal stack capture will occur.
1296 : // When this is set, the stack of any previous activation is ignored.
1297 : Rooted<SavedFrame*> asyncStack_;
1298 :
1299 : // Value of asyncCause to be attached to asyncStack_.
1300 : const char* asyncCause_;
1301 :
1302 : // True if the async call was explicitly requested, e.g. via
1303 : // callFunctionWithAsyncStack.
1304 : bool asyncCallIsExplicit_;
1305 :
1306 : enum Kind { Interpreter, Jit, Wasm };
1307 : Kind kind_;
1308 :
1309 : inline Activation(JSContext* cx, Kind kind);
1310 : inline ~Activation();
1311 :
1312 : public:
1313 31394 : JSContext* cx() const {
1314 31394 : return cx_;
1315 : }
1316 64994 : JSCompartment* compartment() const {
1317 64994 : return compartment_;
1318 : }
1319 14868 : Activation* prev() const {
1320 14868 : return prev_;
1321 : }
1322 0 : Activation* prevProfiling() const { return prevProfiling_; }
1323 : inline Activation* mostRecentProfiling();
1324 :
1325 179542 : bool isInterpreter() const {
1326 179542 : return kind_ == Interpreter;
1327 : }
1328 193164 : bool isJit() const {
1329 193164 : return kind_ == Jit;
1330 : }
1331 45924 : bool isWasm() const {
1332 45924 : return kind_ == Wasm;
1333 : }
1334 :
1335 : inline bool isProfiling() const;
1336 : void registerProfiling();
1337 : void unregisterProfiling();
1338 :
1339 90585 : InterpreterActivation* asInterpreter() const {
1340 90585 : MOZ_ASSERT(isInterpreter());
1341 90585 : return (InterpreterActivation*)this;
1342 : }
1343 65767 : jit::JitActivation* asJit() const {
1344 65767 : MOZ_ASSERT(isJit());
1345 65767 : return (jit::JitActivation*)this;
1346 : }
1347 0 : WasmActivation* asWasm() const {
1348 0 : MOZ_ASSERT(isWasm());
1349 0 : return (WasmActivation*)this;
1350 : }
1351 :
1352 2745 : void hideScriptedCaller() {
1353 2745 : hideScriptedCallerCount_++;
1354 2745 : }
1355 2742 : void unhideScriptedCaller() {
1356 2742 : MOZ_ASSERT(hideScriptedCallerCount_ > 0);
1357 2742 : hideScriptedCallerCount_--;
1358 2742 : }
1359 533 : bool scriptedCallerIsHidden() const {
1360 533 : return hideScriptedCallerCount_ > 0;
1361 : }
1362 :
1363 0 : static size_t offsetOfPrev() {
1364 0 : return offsetof(Activation, prev_);
1365 : }
1366 0 : static size_t offsetOfPrevProfiling() {
1367 0 : return offsetof(Activation, prevProfiling_);
1368 : }
1369 :
1370 12356 : SavedFrame* asyncStack() {
1371 12356 : return asyncStack_;
1372 : }
1373 :
1374 317 : const char* asyncCause() const {
1375 317 : return asyncCause_;
1376 : }
1377 :
1378 59 : bool asyncCallIsExplicit() const {
1379 59 : return asyncCallIsExplicit_;
1380 : }
1381 :
1382 : inline LiveSavedFrameCache* getLiveSavedFrameCache(JSContext* cx);
1383 :
1384 : private:
1385 : Activation(const Activation& other) = delete;
1386 : void operator=(const Activation& other) = delete;
1387 : };
1388 :
1389 : // This variable holds a special opcode value which is greater than all normal
1390 : // opcodes, and is chosen such that the bitwise or of this value with any
1391 : // opcode is this value.
1392 : static const jsbytecode EnableInterruptsPseudoOpcode = -1;
1393 :
1394 : static_assert(EnableInterruptsPseudoOpcode >= JSOP_LIMIT,
1395 : "EnableInterruptsPseudoOpcode must be greater than any opcode");
1396 : static_assert(EnableInterruptsPseudoOpcode == jsbytecode(-1),
1397 : "EnableInterruptsPseudoOpcode must be the maximum jsbytecode value");
1398 :
1399 : class InterpreterFrameIterator;
1400 : class RunState;
1401 :
1402 : class InterpreterActivation : public Activation
1403 : {
1404 : friend class js::InterpreterFrameIterator;
1405 :
1406 : InterpreterRegs regs_;
1407 : InterpreterFrame* entryFrame_;
1408 : size_t opMask_; // For debugger interrupts, see js::Interpret.
1409 :
1410 : #ifdef DEBUG
1411 : size_t oldFrameCount_;
1412 : #endif
1413 :
1414 : public:
1415 : inline InterpreterActivation(RunState& state, JSContext* cx, InterpreterFrame* entryFrame);
1416 : inline ~InterpreterActivation();
1417 :
1418 : inline bool pushInlineFrame(const CallArgs& args, HandleScript script,
1419 : MaybeConstruct constructing);
1420 : inline void popInlineFrame(InterpreterFrame* frame);
1421 :
1422 : inline bool resumeGeneratorFrame(HandleFunction callee, HandleValue newTarget,
1423 : HandleObject envChain);
1424 :
1425 45982 : InterpreterFrame* current() const {
1426 45982 : return regs_.fp();
1427 : }
1428 3039906 : InterpreterRegs& regs() {
1429 3039906 : return regs_;
1430 : }
1431 43550 : InterpreterFrame* entryFrame() const {
1432 43550 : return entryFrame_;
1433 : }
1434 505969 : size_t opMask() const {
1435 505969 : return opMask_;
1436 : }
1437 :
1438 24141 : bool isProfiling() const {
1439 24141 : return false;
1440 : }
1441 :
1442 : // If this js::Interpret frame is running |script|, enable interrupts.
1443 3584 : void enableInterruptsIfRunning(JSScript* script) {
1444 3584 : if (regs_.fp()->script() == script)
1445 129 : enableInterruptsUnconditionally();
1446 3584 : }
1447 563 : void enableInterruptsUnconditionally() {
1448 563 : opMask_ = EnableInterruptsPseudoOpcode;
1449 563 : }
1450 473 : void clearInterruptsMask() {
1451 473 : opMask_ = 0;
1452 473 : }
1453 : };
1454 :
1455 : // Iterates over a thread's activation list.
1456 : class ActivationIterator
1457 : {
1458 : protected:
1459 : Activation* activation_;
1460 :
1461 : private:
1462 : void settle();
1463 :
1464 : public:
1465 : explicit ActivationIterator(JSContext* cx);
1466 :
1467 : // ActivationIterator can be used to iterate over a different thread's
1468 : // activations, for use by the GC, invalidation, and other operations that
1469 : // don't have a user-visible effect on the target thread's JS behavior.
1470 : ActivationIterator(JSContext* cx, const CooperatingContext& target);
1471 :
1472 : ActivationIterator& operator++();
1473 :
1474 61335 : Activation* operator->() const {
1475 61335 : return activation_;
1476 : }
1477 24624 : Activation* activation() const {
1478 24624 : return activation_;
1479 : }
1480 47012 : bool done() const {
1481 47012 : return activation_ == nullptr;
1482 : }
1483 : };
1484 :
1485 : namespace jit {
1486 :
1487 : class BailoutFrameInfo;
1488 :
1489 : // A JitActivation is used for frames running in Baseline or Ion.
1490 : class JitActivation : public Activation
1491 : {
1492 : // If Baseline or Ion code is on the stack, and has called into C++, this
1493 : // will be aligned to an ExitFrame.
1494 : uint8_t* exitFP_;
1495 :
1496 : JitActivation* prevJitActivation_;
1497 : bool active_;
1498 :
1499 : // Rematerialized Ion frames which has info copied out of snapshots. Maps
1500 : // frame pointers (i.e. exitFP_) to a vector of rematerializations of all
1501 : // inline frames associated with that frame.
1502 : //
1503 : // This table is lazily initialized by calling getRematerializedFrame.
1504 : typedef GCVector<RematerializedFrame*> RematerializedFrameVector;
1505 : typedef HashMap<uint8_t*, RematerializedFrameVector> RematerializedFrameTable;
1506 : RematerializedFrameTable* rematerializedFrames_;
1507 :
1508 : // This vector is used to remember the outcome of the evaluation of recover
1509 : // instructions.
1510 : //
1511 : // RInstructionResults are appended into this vector when Snapshot values
1512 : // have to be read, or when the evaluation has to run before some mutating
1513 : // code. Each RInstructionResults belongs to one frame which has to bailout
1514 : // as soon as we get back to it.
1515 : typedef Vector<RInstructionResults, 1> IonRecoveryMap;
1516 : IonRecoveryMap ionRecovery_;
1517 :
1518 : // If we are bailing out from Ion, then this field should be a non-null
1519 : // pointer which references the BailoutFrameInfo used to walk the inner
1520 : // frames. This field is used for all newly constructed JitFrameIterators to
1521 : // read the innermost frame information from this bailout data instead of
1522 : // reading it from the stack.
1523 : BailoutFrameInfo* bailoutData_;
1524 :
1525 : // When profiling is enabled, these fields will be updated to reflect the
1526 : // last pushed frame for this activation, and if that frame has been
1527 : // left for a call, the native code site of the call.
1528 : mozilla::Atomic<void*, mozilla::Relaxed> lastProfilingFrame_;
1529 : mozilla::Atomic<void*, mozilla::Relaxed> lastProfilingCallSite_;
1530 : static_assert(sizeof(mozilla::Atomic<void*, mozilla::Relaxed>) == sizeof(void*),
1531 : "Atomic should have same memory format as underlying type.");
1532 :
1533 : void clearRematerializedFrames();
1534 :
1535 : #ifdef CHECK_OSIPOINT_REGISTERS
1536 : protected:
1537 : // Used to verify that live registers don't change between a VM call and
1538 : // the OsiPoint that follows it. Protected to silence Clang warning.
1539 : uint32_t checkRegs_;
1540 : RegisterDump regs_;
1541 : #endif
1542 :
1543 : public:
1544 : explicit JitActivation(JSContext* cx, bool active = true);
1545 : ~JitActivation();
1546 :
1547 17242 : bool isActive() const {
1548 17242 : return active_;
1549 : }
1550 : void setActive(JSContext* cx, bool active = true);
1551 :
1552 34149 : bool isProfiling() const {
1553 : // All JitActivations can be profiled.
1554 34149 : return true;
1555 : }
1556 :
1557 0 : JitActivation* prevJitActivation() const {
1558 0 : return prevJitActivation_;
1559 : }
1560 0 : static size_t offsetOfPrevJitActivation() {
1561 0 : return offsetof(JitActivation, prevJitActivation_);
1562 : }
1563 :
1564 78 : void setExitFP(uint8_t* fp) {
1565 78 : exitFP_ = fp;
1566 78 : }
1567 9713 : uint8_t* exitFP() const {
1568 9713 : return exitFP_;
1569 : }
1570 1138 : static size_t offsetOfExitFP() {
1571 1138 : return offsetof(JitActivation, exitFP_);
1572 : }
1573 :
1574 0 : static size_t offsetOfActiveUint8() {
1575 : MOZ_ASSERT(sizeof(bool) == 1);
1576 0 : return offsetof(JitActivation, active_);
1577 : }
1578 :
1579 : #ifdef CHECK_OSIPOINT_REGISTERS
1580 0 : void setCheckRegs(bool check) {
1581 0 : checkRegs_ = check;
1582 0 : }
1583 0 : static size_t offsetOfCheckRegs() {
1584 0 : return offsetof(JitActivation, checkRegs_);
1585 : }
1586 0 : static size_t offsetOfRegs() {
1587 0 : return offsetof(JitActivation, regs_);
1588 : }
1589 : #endif
1590 :
1591 : // Look up a rematerialized frame keyed by the fp, rematerializing the
1592 : // frame if one doesn't already exist. A frame can only be rematerialized
1593 : // if an IonFrameIterator pointing to the nearest uninlined frame can be
1594 : // provided, as values need to be read out of snapshots.
1595 : //
1596 : // The inlineDepth must be within bounds of the frame pointed to by iter.
1597 : RematerializedFrame* getRematerializedFrame(JSContext* cx, const JitFrameIterator& iter,
1598 : size_t inlineDepth = 0);
1599 :
1600 : // Look up a rematerialized frame by the fp. If inlineDepth is out of
1601 : // bounds of what has been rematerialized, nullptr is returned.
1602 : RematerializedFrame* lookupRematerializedFrame(uint8_t* top, size_t inlineDepth = 0);
1603 :
1604 : // Remove all rematerialized frames associated with the fp top from the
1605 : // Debugger.
1606 : void removeRematerializedFramesFromDebugger(JSContext* cx, uint8_t* top);
1607 :
1608 0 : bool hasRematerializedFrame(uint8_t* top, size_t inlineDepth = 0) {
1609 0 : return !!lookupRematerializedFrame(top, inlineDepth);
1610 : }
1611 :
1612 : // Remove a previous rematerialization by fp.
1613 : void removeRematerializedFrame(uint8_t* top);
1614 :
1615 : void traceRematerializedFrames(JSTracer* trc);
1616 :
1617 :
1618 : // Register the results of on Ion frame recovery.
1619 : bool registerIonFrameRecovery(RInstructionResults&& results);
1620 :
1621 : // Return the pointer to the Ion frame recovery, if it is already registered.
1622 : RInstructionResults* maybeIonFrameRecovery(JitFrameLayout* fp);
1623 :
1624 : // If an Ion frame recovery exists for the |fp| frame exists, then remove it
1625 : // from the activation.
1626 : void removeIonFrameRecovery(JitFrameLayout* fp);
1627 :
1628 : void traceIonRecovery(JSTracer* trc);
1629 :
1630 : // Return the bailout information if it is registered.
1631 9401 : const BailoutFrameInfo* bailoutData() const { return bailoutData_; }
1632 :
1633 : // Register the bailout data when it is constructed.
1634 : void setBailoutData(BailoutFrameInfo* bailoutData);
1635 :
1636 : // Unregister the bailout data when the frame is reconstructed.
1637 : void cleanBailoutData();
1638 :
1639 690 : static size_t offsetOfLastProfilingFrame() {
1640 690 : return offsetof(JitActivation, lastProfilingFrame_);
1641 : }
1642 0 : void* lastProfilingFrame() {
1643 0 : return lastProfilingFrame_;
1644 : }
1645 0 : void setLastProfilingFrame(void* ptr) {
1646 0 : lastProfilingFrame_ = ptr;
1647 0 : }
1648 :
1649 636 : static size_t offsetOfLastProfilingCallSite() {
1650 636 : return offsetof(JitActivation, lastProfilingCallSite_);
1651 : }
1652 0 : void* lastProfilingCallSite() {
1653 0 : return lastProfilingCallSite_;
1654 : }
1655 0 : void setLastProfilingCallSite(void* ptr) {
1656 0 : lastProfilingCallSite_ = ptr;
1657 0 : }
1658 : };
1659 :
1660 : // A filtering of the ActivationIterator to only stop at JitActivations.
1661 : class JitActivationIterator : public ActivationIterator
1662 : {
1663 4334 : void settle() {
1664 4498 : while (!done() && !activation_->isJit())
1665 164 : ActivationIterator::operator++();
1666 4170 : }
1667 :
1668 : public:
1669 4073 : explicit JitActivationIterator(JSContext* cx)
1670 4073 : : ActivationIterator(cx)
1671 : {
1672 4073 : settle();
1673 4073 : }
1674 :
1675 49 : JitActivationIterator(JSContext* cx, const CooperatingContext& target)
1676 49 : : ActivationIterator(cx, target)
1677 : {
1678 49 : settle();
1679 49 : }
1680 :
1681 48 : JitActivationIterator& operator++() {
1682 48 : ActivationIterator::operator++();
1683 48 : settle();
1684 48 : return *this;
1685 : }
1686 :
1687 0 : uint8_t* exitFP() const {
1688 0 : MOZ_ASSERT(activation_->isJit());
1689 0 : return activation_->asJit()->exitFP();
1690 : }
1691 : };
1692 :
1693 : } // namespace jit
1694 :
1695 : // Iterates over the frames of a single InterpreterActivation.
1696 : class InterpreterFrameIterator
1697 : {
1698 : InterpreterActivation* activation_;
1699 : InterpreterFrame* fp_;
1700 : jsbytecode* pc_;
1701 : Value* sp_;
1702 :
1703 : public:
1704 11018 : explicit InterpreterFrameIterator(InterpreterActivation* activation)
1705 11018 : : activation_(activation),
1706 : fp_(nullptr),
1707 : pc_(nullptr),
1708 11018 : sp_(nullptr)
1709 : {
1710 11018 : if (activation) {
1711 7832 : fp_ = activation->current();
1712 7832 : pc_ = activation->regs().pc;
1713 7832 : sp_ = activation->regs().sp;
1714 : }
1715 11018 : }
1716 :
1717 87330 : InterpreterFrame* frame() const {
1718 87330 : MOZ_ASSERT(!done());
1719 87330 : return fp_;
1720 : }
1721 8027 : jsbytecode* pc() const {
1722 8027 : MOZ_ASSERT(!done());
1723 8027 : return pc_;
1724 : }
1725 109 : Value* sp() const {
1726 109 : MOZ_ASSERT(!done());
1727 109 : return sp_;
1728 : }
1729 :
1730 : InterpreterFrameIterator& operator++();
1731 :
1732 112712 : bool done() const {
1733 112712 : return fp_ == nullptr;
1734 : }
1735 : };
1736 :
1737 : // An eventual goal is to remove WasmActivation and to run asm code in a
1738 : // JitActivation interleaved with Ion/Baseline jit code. This would allow
1739 : // efficient calls back and forth but requires that we can walk the stack for
1740 : // all kinds of jit code.
1741 : class WasmActivation : public Activation
1742 : {
1743 : wasm::Frame* exitFP_;
1744 :
1745 : public:
1746 : explicit WasmActivation(JSContext* cx);
1747 : ~WasmActivation();
1748 :
1749 0 : bool isProfiling() const {
1750 0 : return true;
1751 : }
1752 :
1753 : // Returns null or the final wasm::Frame* when wasm exited this
1754 : // WasmActivation.
1755 0 : wasm::Frame* exitFP() const { return exitFP_; }
1756 :
1757 : // Written by JIT code:
1758 0 : static unsigned offsetOfExitFP() { return offsetof(WasmActivation, exitFP_); }
1759 :
1760 : // Interrupts are started from the interrupt signal handler (or the ARM
1761 : // simulator) and cleared by WasmHandleExecutionInterrupt or WasmHandleThrow
1762 : // when the interrupt is handled.
1763 : void startInterrupt(const JS::ProfilingFrameIterator::RegisterState& state);
1764 : void finishInterrupt();
1765 : bool interrupted() const;
1766 : void* unwindPC() const;
1767 : void* resumePC() const;
1768 :
1769 : // Used by wasm::FrameIterator during stack unwinding.
1770 : void unwindExitFP(wasm::Frame* exitFP);
1771 : };
1772 :
1773 : // A FrameIter walks over a context's stack of JS script activations,
1774 : // abstracting over whether the JS scripts were running in the interpreter or
1775 : // different modes of compiled code.
1776 : //
1777 : // FrameIter is parameterized by what it includes in the stack iteration:
1778 : // - When provided, the optional JSPrincipal argument will cause FrameIter to
1779 : // only show frames in globals whose JSPrincipals are subsumed (via
1780 : // JSSecurityCallbacks::subsume) by the given JSPrincipal.
1781 : //
1782 : // Additionally, there are derived FrameIter types that automatically skip
1783 : // certain frames:
1784 : // - ScriptFrameIter only shows frames that have an associated JSScript
1785 : // (currently everything other than wasm stack frames). When !hasScript(),
1786 : // clients must stick to the portion of the
1787 : // interface marked below.
1788 : // - NonBuiltinScriptFrameIter additionally filters out builtin (self-hosted)
1789 : // scripts.
1790 3186 : class FrameIter
1791 : {
1792 : public:
1793 : enum DebuggerEvalOption { FOLLOW_DEBUGGER_EVAL_PREV_LINK,
1794 : IGNORE_DEBUGGER_EVAL_PREV_LINK };
1795 : enum State { DONE, INTERP, JIT, WASM };
1796 :
1797 : // Unlike ScriptFrameIter itself, ScriptFrameIter::Data can be allocated on
1798 : // the heap, so this structure should not contain any GC things.
1799 : struct Data
1800 : {
1801 : JSContext * cx_;
1802 : DebuggerEvalOption debuggerEvalOption_;
1803 : JSPrincipals * principals_;
1804 :
1805 : State state_;
1806 :
1807 : jsbytecode * pc_;
1808 :
1809 : InterpreterFrameIterator interpFrames_;
1810 : ActivationIterator activations_;
1811 :
1812 : jit::JitFrameIterator jitFrames_;
1813 : unsigned ionInlineFrameNo_;
1814 : wasm::FrameIterator wasmFrames_;
1815 :
1816 : Data(JSContext* cx, DebuggerEvalOption debuggerEvalOption, JSPrincipals* principals);
1817 : Data(const Data& other);
1818 : };
1819 :
1820 : explicit FrameIter(JSContext* cx,
1821 : DebuggerEvalOption = FOLLOW_DEBUGGER_EVAL_PREV_LINK);
1822 : FrameIter(JSContext* cx, DebuggerEvalOption, JSPrincipals*);
1823 : FrameIter(const FrameIter& iter);
1824 : MOZ_IMPLICIT FrameIter(const Data& data);
1825 : MOZ_IMPLICIT FrameIter(AbstractFramePtr frame);
1826 :
1827 125224 : bool done() const { return data_.state_ == DONE; }
1828 :
1829 : // -------------------------------------------------------
1830 : // The following functions can only be called when !done()
1831 : // -------------------------------------------------------
1832 :
1833 : FrameIter& operator++();
1834 :
1835 : JSCompartment* compartment() const;
1836 13455 : Activation* activation() const { return data_.activations_.activation(); }
1837 :
1838 0 : bool isInterp() const { MOZ_ASSERT(!done()); return data_.state_ == INTERP; }
1839 1682 : bool isJit() const { MOZ_ASSERT(!done()); return data_.state_ == JIT; }
1840 30924 : bool isWasm() const { MOZ_ASSERT(!done()); return data_.state_ == WASM; }
1841 : inline bool isIon() const;
1842 : inline bool isBaseline() const;
1843 : inline bool isPhysicalIonFrame() const;
1844 :
1845 : bool isEvalFrame() const;
1846 : bool isFunctionFrame() const;
1847 0 : bool hasArgs() const { return isFunctionFrame(); }
1848 :
1849 : // These two methods may not be called with asm frames.
1850 : inline bool hasCachedSavedFrame() const;
1851 : inline void setHasCachedSavedFrame();
1852 :
1853 : ScriptSource* scriptSource() const;
1854 : const char* filename() const;
1855 : const char16_t* displayURL() const;
1856 : unsigned computeLine(uint32_t* column = nullptr) const;
1857 : JSAtom* functionDisplayAtom() const;
1858 : bool mutedErrors() const;
1859 :
1860 12737 : bool hasScript() const { return !isWasm(); }
1861 :
1862 : // -----------------------------------------------------------
1863 : // The following functions can only be called when isWasm()
1864 : // -----------------------------------------------------------
1865 :
1866 : inline bool wasmDebugEnabled() const;
1867 : inline wasm::Instance* wasmInstance() const;
1868 : inline unsigned wasmBytecodeOffset() const;
1869 : void wasmUpdateBytecodeOffset();
1870 :
1871 : // -----------------------------------------------------------
1872 : // The following functions can only be called when hasScript()
1873 : // -----------------------------------------------------------
1874 :
1875 : inline JSScript* script() const;
1876 :
1877 : bool isConstructing() const;
1878 26473 : jsbytecode* pc() const { MOZ_ASSERT(!done()); return data_.pc_; }
1879 : void updatePcQuadratic();
1880 :
1881 : // The function |calleeTemplate()| returns either the function from which
1882 : // the current |callee| was cloned or the |callee| if it can be read. As
1883 : // long as we do not have to investigate the environment chain or build a
1884 : // new frame, we should prefer to use |calleeTemplate| instead of
1885 : // |callee|, as requesting the |callee| might cause the invalidation of
1886 : // the frame. (see js::Lambda)
1887 : JSFunction* calleeTemplate() const;
1888 : JSFunction* callee(JSContext* cx) const;
1889 :
1890 0 : JSFunction* maybeCallee(JSContext* cx) const {
1891 0 : return isFunctionFrame() ? callee(cx) : nullptr;
1892 : }
1893 :
1894 : bool matchCallee(JSContext* cx, HandleFunction fun) const;
1895 :
1896 : unsigned numActualArgs() const;
1897 : unsigned numFormalArgs() const;
1898 : Value unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const;
1899 : template <class Op> inline void unaliasedForEachActual(JSContext* cx, Op op);
1900 :
1901 : JSObject* environmentChain(JSContext* cx) const;
1902 : CallObject& callObj(JSContext* cx) const;
1903 :
1904 : bool hasArgsObj() const;
1905 : ArgumentsObject& argsObj() const;
1906 :
1907 : // Get the original |this| value passed to this function. May not be the
1908 : // actual this-binding (for instance, derived class constructors will
1909 : // change their this-value later and non-strict functions will box
1910 : // primitives).
1911 : Value thisArgument(JSContext* cx) const;
1912 :
1913 : Value newTarget() const;
1914 :
1915 : Value returnValue() const;
1916 : void setReturnValue(const Value& v);
1917 :
1918 : // These are only valid for the top frame.
1919 : size_t numFrameSlots() const;
1920 : Value frameSlotValue(size_t index) const;
1921 :
1922 : // Ensures that we have rematerialized the top frame and its associated
1923 : // inline frames. Can only be called when isIon().
1924 : bool ensureHasRematerializedFrame(JSContext* cx);
1925 :
1926 : // True when isInterp() or isBaseline(). True when isIon() if it
1927 : // has a rematerialized frame. False otherwise false otherwise.
1928 : bool hasUsableAbstractFramePtr() const;
1929 :
1930 : // -----------------------------------------------------------
1931 : // The following functions can only be called when isInterp(),
1932 : // isBaseline(), isWasm() or isIon(). Further, abstractFramePtr() can
1933 : // only be called when hasUsableAbstractFramePtr().
1934 : // -----------------------------------------------------------
1935 :
1936 : AbstractFramePtr abstractFramePtr() const;
1937 : AbstractFramePtr copyDataAsAbstractFramePtr() const;
1938 : Data* copyData() const;
1939 :
1940 : // This can only be called when isInterp():
1941 : inline InterpreterFrame* interpFrame() const;
1942 :
1943 : // This can only be called when isPhysicalIonFrame():
1944 : inline jit::CommonFrameLayout* physicalIonFrame() const;
1945 :
1946 : // This is used to provide a raw interface for debugging.
1947 : void* rawFramePtr() const;
1948 :
1949 : private:
1950 : Data data_;
1951 : jit::InlineFrameIterator ionInlineFrames_;
1952 :
1953 : void popActivation();
1954 : void popInterpreterFrame();
1955 : void nextJitFrame();
1956 : void popJitFrame();
1957 : void popWasmFrame();
1958 : void settleOnActivation();
1959 : };
1960 :
1961 120 : class ScriptFrameIter : public FrameIter
1962 : {
1963 120 : void settle() {
1964 120 : while (!done() && !hasScript())
1965 0 : FrameIter::operator++();
1966 120 : }
1967 :
1968 : public:
1969 120 : explicit ScriptFrameIter(JSContext* cx,
1970 : DebuggerEvalOption debuggerEvalOption = FOLLOW_DEBUGGER_EVAL_PREV_LINK)
1971 120 : : FrameIter(cx, debuggerEvalOption)
1972 : {
1973 120 : settle();
1974 120 : }
1975 :
1976 : ScriptFrameIter(JSContext* cx,
1977 : DebuggerEvalOption debuggerEvalOption,
1978 : JSPrincipals* prin)
1979 : : FrameIter(cx, debuggerEvalOption, prin)
1980 : {
1981 : settle();
1982 : }
1983 :
1984 : ScriptFrameIter(const ScriptFrameIter& iter) : FrameIter(iter) { settle(); }
1985 : explicit ScriptFrameIter(const FrameIter::Data& data) : FrameIter(data) { settle(); }
1986 : explicit ScriptFrameIter(AbstractFramePtr frame) : FrameIter(frame) { settle(); }
1987 :
1988 0 : ScriptFrameIter& operator++() {
1989 0 : FrameIter::operator++();
1990 0 : settle();
1991 0 : return *this;
1992 : }
1993 : };
1994 :
1995 : #ifdef DEBUG
1996 : bool SelfHostedFramesVisible();
1997 : #else
1998 : static inline bool
1999 : SelfHostedFramesVisible()
2000 : {
2001 : return false;
2002 : }
2003 : #endif
2004 :
2005 : /* A filtering of the FrameIter to only stop at non-self-hosted scripts. */
2006 101 : class NonBuiltinFrameIter : public FrameIter
2007 : {
2008 : void settle();
2009 :
2010 : public:
2011 47 : explicit NonBuiltinFrameIter(JSContext* cx,
2012 : FrameIter::DebuggerEvalOption debuggerEvalOption =
2013 : FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK)
2014 47 : : FrameIter(cx, debuggerEvalOption)
2015 : {
2016 47 : settle();
2017 47 : }
2018 :
2019 0 : NonBuiltinFrameIter(JSContext* cx,
2020 : FrameIter::DebuggerEvalOption debuggerEvalOption,
2021 : JSPrincipals* principals)
2022 0 : : FrameIter(cx, debuggerEvalOption, principals)
2023 : {
2024 0 : settle();
2025 0 : }
2026 :
2027 54 : NonBuiltinFrameIter(JSContext* cx, JSPrincipals* principals)
2028 54 : : FrameIter(cx, FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK, principals)
2029 : {
2030 54 : settle();
2031 54 : }
2032 :
2033 : explicit NonBuiltinFrameIter(const FrameIter::Data& data)
2034 : : FrameIter(data)
2035 : {}
2036 :
2037 : NonBuiltinFrameIter& operator++() {
2038 : FrameIter::operator++();
2039 : settle();
2040 : return *this;
2041 : }
2042 : };
2043 :
2044 : /* A filtering of the ScriptFrameIter to only stop at non-self-hosted scripts. */
2045 0 : class NonBuiltinScriptFrameIter : public ScriptFrameIter
2046 : {
2047 : void settle();
2048 :
2049 : public:
2050 0 : explicit NonBuiltinScriptFrameIter(JSContext* cx,
2051 : ScriptFrameIter::DebuggerEvalOption debuggerEvalOption =
2052 : ScriptFrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK)
2053 0 : : ScriptFrameIter(cx, debuggerEvalOption)
2054 : {
2055 0 : settle();
2056 0 : }
2057 :
2058 : NonBuiltinScriptFrameIter(JSContext* cx,
2059 : ScriptFrameIter::DebuggerEvalOption debuggerEvalOption,
2060 : JSPrincipals* principals)
2061 : : ScriptFrameIter(cx, debuggerEvalOption, principals)
2062 : {
2063 : settle();
2064 : }
2065 :
2066 : explicit NonBuiltinScriptFrameIter(const ScriptFrameIter::Data& data)
2067 : : ScriptFrameIter(data)
2068 : {}
2069 :
2070 0 : NonBuiltinScriptFrameIter& operator++() {
2071 0 : ScriptFrameIter::operator++();
2072 0 : settle();
2073 0 : return *this;
2074 : }
2075 : };
2076 :
2077 : /*
2078 : * Blindly iterate over all frames in the current thread's stack. These frames
2079 : * can be from different contexts and compartments, so beware.
2080 : */
2081 0 : class AllFramesIter : public FrameIter
2082 : {
2083 : public:
2084 0 : explicit AllFramesIter(JSContext* cx)
2085 0 : : FrameIter(cx, ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK)
2086 0 : {}
2087 : };
2088 :
2089 : /* Iterates over all script frame in the current thread's stack.
2090 : * See also AllFramesIter and ScriptFrameIter.
2091 : */
2092 0 : class AllScriptFramesIter : public ScriptFrameIter
2093 : {
2094 : public:
2095 0 : explicit AllScriptFramesIter(JSContext* cx)
2096 0 : : ScriptFrameIter(cx, ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK)
2097 0 : {}
2098 : };
2099 :
2100 : /* Popular inline definitions. */
2101 :
2102 : inline JSScript*
2103 15103 : FrameIter::script() const
2104 : {
2105 15103 : MOZ_ASSERT(!done());
2106 15103 : if (data_.state_ == INTERP)
2107 8331 : return interpFrame()->script();
2108 6772 : MOZ_ASSERT(data_.state_ == JIT);
2109 6772 : if (data_.jitFrames_.isIonJS())
2110 2520 : return ionInlineFrames_.script();
2111 4252 : return data_.jitFrames_.script();
2112 : }
2113 :
2114 : inline bool
2115 0 : FrameIter::wasmDebugEnabled() const
2116 : {
2117 0 : MOZ_ASSERT(!done());
2118 0 : MOZ_ASSERT(data_.state_ == WASM);
2119 0 : return data_.wasmFrames_.debugEnabled();
2120 : }
2121 :
2122 : inline wasm::Instance*
2123 0 : FrameIter::wasmInstance() const
2124 : {
2125 0 : MOZ_ASSERT(!done());
2126 0 : MOZ_ASSERT(data_.state_ == WASM && wasmDebugEnabled());
2127 0 : return data_.wasmFrames_.instance();
2128 : }
2129 :
2130 : inline unsigned
2131 0 : FrameIter::wasmBytecodeOffset() const
2132 : {
2133 0 : MOZ_ASSERT(!done());
2134 0 : MOZ_ASSERT(data_.state_ == WASM);
2135 0 : return data_.wasmFrames_.lineOrBytecode();
2136 : }
2137 :
2138 : inline bool
2139 2 : FrameIter::isIon() const
2140 : {
2141 2 : return isJit() && data_.jitFrames_.isIonJS();
2142 : }
2143 :
2144 : inline bool
2145 0 : FrameIter::isBaseline() const
2146 : {
2147 0 : return isJit() && data_.jitFrames_.isBaselineJS();
2148 : }
2149 :
2150 : inline InterpreterFrame*
2151 72840 : FrameIter::interpFrame() const
2152 : {
2153 72840 : MOZ_ASSERT(data_.state_ == INTERP);
2154 72840 : return data_.interpFrames_.frame();
2155 : }
2156 :
2157 : inline bool
2158 1680 : FrameIter::isPhysicalIonFrame() const
2159 : {
2160 3360 : return isJit() &&
2161 3360 : data_.jitFrames_.isIonScripted() &&
2162 3360 : ionInlineFrames_.frameNo() == 0;
2163 : }
2164 :
2165 : inline jit::CommonFrameLayout*
2166 840 : FrameIter::physicalIonFrame() const
2167 : {
2168 840 : MOZ_ASSERT(isPhysicalIonFrame());
2169 840 : return data_.jitFrames_.current();
2170 : }
2171 :
2172 : } /* namespace js */
2173 : #endif /* vm_Stack_h */
|