Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/js/src/vm/Stack.h
Line
Count
Source (jump to first uncovered line)
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/HashFunctions.h"
12
#include "mozilla/Maybe.h"
13
#include "mozilla/MaybeOneOf.h"
14
#include "mozilla/MemoryReporting.h"
15
#include "mozilla/Variant.h"
16
17
#include "jsutil.h"
18
19
#include "gc/Rooting.h"
20
#ifdef CHECK_OSIPOINT_REGISTERS
21
#include "jit/Registers.h" // for RegisterDump
22
#endif
23
#include "jit/JSJitFrameIter.h"
24
#include "js/RootingAPI.h"
25
#include "js/TypeDecls.h"
26
#include "js/UniquePtr.h"
27
#include "vm/ArgumentsObject.h"
28
#include "vm/JSFunction.h"
29
#include "vm/JSScript.h"
30
#include "vm/SavedFrame.h"
31
#include "wasm/WasmFrameIter.h"
32
#include "wasm/WasmSignalHandlers.h"
33
#include "wasm/WasmTypes.h"
34
35
namespace JS {
36
namespace dbg {
37
#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING
38
#pragma GCC diagnostic push
39
#pragma GCC diagnostic ignored "-Wattributes"
40
#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING
41
42
class JS_PUBLIC_API(AutoEntryMonitor);
43
44
#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING
45
#pragma GCC diagnostic pop
46
#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING
47
} // namespace dbg
48
} // namespace JS
49
50
namespace js {
51
52
class InterpreterRegs;
53
class CallObject;
54
class FrameIter;
55
class EnvironmentObject;
56
class ScriptFrameIter;
57
class GeckoProfilerRuntime;
58
class InterpreterFrame;
59
class LexicalEnvironmentObject;
60
class EnvironmentIter;
61
class EnvironmentCoordinate;
62
63
class SavedFrame;
64
65
namespace jit {
66
class CommonFrameLayout;
67
}
68
namespace wasm {
69
class DebugFrame;
70
class Instance;
71
}
72
73
// [SMDOC] VM stack layout
74
//
75
// A JSRuntime's stack consists of a linked list of activations. Every activation
76
// contains a number of scripted frames that are either running in the interpreter
77
// (InterpreterActivation) or JIT code (JitActivation). The frames inside a single
78
// activation are contiguous: whenever C++ calls back into JS, a new activation is
79
// pushed.
80
//
81
// Every activation is tied to a single JSContext and JS::Compartment. This means we
82
// can reconstruct a given context's stack by skipping activations belonging to other
83
// contexts. This happens whenever an embedding enters the JS engine on cx1 and
84
// then, from a native called by the JS engine, reenters the VM on cx2.
85
86
// Interpreter frames (InterpreterFrame)
87
//
88
// Each interpreter script activation (global or function code) is given a
89
// fixed-size header (js::InterpreterFrame). The frame contains bookkeeping
90
// information about the activation and links to the previous frame.
91
//
92
// The values after an InterpreterFrame in memory are its locals followed by its
93
// expression stack. InterpreterFrame::argv_ points to the frame's arguments.
94
// Missing formal arguments are padded with |undefined|, so the number of
95
// arguments is always >= the number of formals.
96
//
97
// The top of an activation's current frame's expression stack is pointed to by
98
// the activation's "current regs", which contains the stack pointer 'sp'. In
99
// the interpreter, sp is adjusted as individual values are pushed and popped
100
// from the stack and the InterpreterRegs struct (pointed to by the
101
// InterpreterActivation) is a local var of js::Interpret.
102
103
enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false };
104
enum MaybeCheckTDZ { CheckTDZ = true, DontCheckTDZ = false };
105
106
} // namespace js
107
108
namespace mozilla {
109
template <>
110
struct IsPod<js::MaybeCheckTDZ> : TrueType {};
111
} // namespace mozilla
112
113
/*****************************************************************************/
114
115
namespace js {
116
117
namespace jit {
118
    class BaselineFrame;
119
    class RematerializedFrame;
120
} // namespace jit
121
122
/**
123
 * Pointer to a live JS or WASM stack frame.
124
 */
125
class AbstractFramePtr
126
{
127
    friend class FrameIter;
128
129
    uintptr_t ptr_;
130
131
    enum {
132
        Tag_InterpreterFrame = 0x1,
133
        Tag_BaselineFrame = 0x2,
134
        Tag_RematerializedFrame = 0x3,
135
        Tag_WasmDebugFrame = 0x4,
136
        TagMask = 0x7
137
    };
138
139
  public:
140
    AbstractFramePtr()
141
      : ptr_(0)
142
162
    {}
143
144
    MOZ_IMPLICIT AbstractFramePtr(InterpreterFrame* fp)
145
      : ptr_(fp ? uintptr_t(fp) | Tag_InterpreterFrame : 0)
146
618
    {
147
618
        MOZ_ASSERT_IF(fp, asInterpreterFrame() == fp);
148
618
    }
149
150
    MOZ_IMPLICIT AbstractFramePtr(jit::BaselineFrame* fp)
151
      : ptr_(fp ? uintptr_t(fp) | Tag_BaselineFrame : 0)
152
222
    {
153
222
        MOZ_ASSERT_IF(fp, asBaselineFrame() == fp);
154
222
    }
155
156
    MOZ_IMPLICIT AbstractFramePtr(jit::RematerializedFrame* fp)
157
      : ptr_(fp ? uintptr_t(fp) | Tag_RematerializedFrame : 0)
158
0
    {
159
0
        MOZ_ASSERT_IF(fp, asRematerializedFrame() == fp);
160
0
    }
161
162
    MOZ_IMPLICIT AbstractFramePtr(wasm::DebugFrame* fp)
163
      : ptr_(fp ? uintptr_t(fp) | Tag_WasmDebugFrame : 0)
164
0
    {
165
0
        static_assert(wasm::DebugFrame::Alignment >= TagMask, "aligned");
166
0
        MOZ_ASSERT_IF(fp, asWasmDebugFrame() == fp);
167
0
    }
168
169
0
    static AbstractFramePtr FromRaw(void* raw) {
170
0
        AbstractFramePtr frame;
171
0
        frame.ptr_ = uintptr_t(raw);
172
0
        return frame;
173
0
    }
174
175
2.70k
    bool isInterpreterFrame() const {
176
2.70k
        return (ptr_ & TagMask) == Tag_InterpreterFrame;
177
2.70k
    }
178
1.97k
    InterpreterFrame* asInterpreterFrame() const {
179
1.97k
        MOZ_ASSERT(isInterpreterFrame());
180
1.97k
        InterpreterFrame* res = (InterpreterFrame*)(ptr_ & ~TagMask);
181
1.97k
        MOZ_ASSERT(res);
182
1.97k
        return res;
183
1.97k
    }
184
728
    bool isBaselineFrame() const {
185
728
        return (ptr_ & TagMask) == Tag_BaselineFrame;
186
728
    }
187
728
    jit::BaselineFrame* asBaselineFrame() const {
188
728
        MOZ_ASSERT(isBaselineFrame());
189
728
        jit::BaselineFrame* res = (jit::BaselineFrame*)(ptr_ & ~TagMask);
190
728
        MOZ_ASSERT(res);
191
728
        return res;
192
728
    }
193
0
    bool isRematerializedFrame() const {
194
0
        return (ptr_ & TagMask) == Tag_RematerializedFrame;
195
0
    }
196
0
    jit::RematerializedFrame* asRematerializedFrame() const {
197
0
        MOZ_ASSERT(isRematerializedFrame());
198
0
        jit::RematerializedFrame* res = (jit::RematerializedFrame*)(ptr_ & ~TagMask);
199
0
        MOZ_ASSERT(res);
200
0
        return res;
201
0
    }
202
867
    bool isWasmDebugFrame() const {
203
867
        return (ptr_ & TagMask) == Tag_WasmDebugFrame;
204
867
    }
205
0
    wasm::DebugFrame* asWasmDebugFrame() const {
206
0
        MOZ_ASSERT(isWasmDebugFrame());
207
0
        wasm::DebugFrame* res = (wasm::DebugFrame*)(ptr_ & ~TagMask);
208
0
        MOZ_ASSERT(res);
209
0
        return res;
210
0
    }
211
212
0
    void* raw() const { return reinterpret_cast<void*>(ptr_); }
213
214
0
    bool operator ==(const AbstractFramePtr& other) const { return ptr_ == other.ptr_; }
215
0
    bool operator !=(const AbstractFramePtr& other) const { return ptr_ != other.ptr_; }
216
217
1.29k
    explicit operator bool() const { return !!ptr_; }
218
219
    inline JSObject* environmentChain() const;
220
    inline CallObject& callObj() const;
221
    inline bool initFunctionEnvironmentObjects(JSContext* cx);
222
    inline bool pushVarEnvironment(JSContext* cx, HandleScope scope);
223
    template <typename SpecificEnvironment>
224
    inline void pushOnEnvironmentChain(SpecificEnvironment& env);
225
    template <typename SpecificEnvironment>
226
    inline void popOffEnvironmentChain();
227
228
    inline JS::Realm* realm() const;
229
230
    inline bool hasInitialEnvironment() const;
231
    inline bool isGlobalFrame() const;
232
    inline bool isModuleFrame() const;
233
    inline bool isEvalFrame() const;
234
    inline bool isDebuggerEvalFrame() const;
235
236
    inline bool hasScript() const;
237
    inline JSScript* script() const;
238
    inline wasm::Instance* wasmInstance() const;
239
    inline GlobalObject* global() const;
240
    inline JSFunction* callee() const;
241
    inline Value calleev() const;
242
    inline Value& thisArgument() const;
243
244
    inline bool isConstructing() const;
245
    inline Value newTarget() const;
246
247
    inline bool debuggerNeedsCheckPrimitiveReturn() const;
248
249
    inline bool isFunctionFrame() const;
250
    inline bool isNonStrictDirectEvalFrame() const;
251
    inline bool isStrictEvalFrame() const;
252
253
    inline unsigned numActualArgs() const;
254
    inline unsigned numFormalArgs() const;
255
256
    inline Value* argv() const;
257
258
    inline bool hasArgs() const;
259
    inline bool hasArgsObj() const;
260
    inline ArgumentsObject& argsObj() const;
261
    inline void initArgsObj(ArgumentsObject& argsobj) const;
262
263
    inline Value& unaliasedLocal(uint32_t i);
264
    inline Value& unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
265
    inline Value& unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
266
    template <class Op> inline void unaliasedForEachActual(JSContext* cx, Op op);
267
268
    inline bool prevUpToDate() const;
269
    inline void setPrevUpToDate() const;
270
    inline void unsetPrevUpToDate() const;
271
272
    inline bool isDebuggee() const;
273
    inline void setIsDebuggee();
274
    inline void unsetIsDebuggee();
275
276
    inline HandleValue returnValue() const;
277
    inline void setReturnValue(const Value& rval) const;
278
279
    friend void GDBTestInitAbstractFramePtr(AbstractFramePtr&, InterpreterFrame*);
280
    friend void GDBTestInitAbstractFramePtr(AbstractFramePtr&, jit::BaselineFrame*);
281
    friend void GDBTestInitAbstractFramePtr(AbstractFramePtr&, jit::RematerializedFrame*);
282
    friend void GDBTestInitAbstractFramePtr(AbstractFramePtr& frame, wasm::DebugFrame* ptr);
283
};
284
285
class NullFramePtr : public AbstractFramePtr
286
{
287
  public:
288
    NullFramePtr()
289
      : AbstractFramePtr()
290
162
    { }
291
};
292
293
enum MaybeConstruct { NO_CONSTRUCT = false, CONSTRUCT = true };
294
295
/*****************************************************************************/
296
297
class InterpreterFrame
298
{
299
    enum Flags : uint32_t {
300
        CONSTRUCTING           =        0x1,  /* frame is for a constructor invocation */
301
302
        RESUMED_GENERATOR      =        0x2,  /* frame is for a resumed generator invocation */
303
304
        /* Function prologue state */
305
        HAS_INITIAL_ENV        =        0x4,  /* callobj created for function or var env for eval */
306
        HAS_ARGS_OBJ           =        0x8,  /* ArgumentsObject created for needsArgsObj script */
307
308
        /* Lazy frame initialization */
309
        HAS_RVAL               =       0x10,  /* frame has rval_ set */
310
311
        /* Debugger state */
312
        PREV_UP_TO_DATE        =       0x20,  /* see DebugScopes::updateLiveScopes */
313
314
        /*
315
         * See comment above 'isDebuggee' in Realm.h for explanation of
316
         * invariants of debuggee compartments, scripts, and frames.
317
         */
318
        DEBUGGEE               =       0x40,  /* Execution is being observed by Debugger */
319
320
        /* Used in tracking calls and profiling (see vm/GeckoProfiler.cpp) */
321
        HAS_PUSHED_PROF_FRAME  =       0x80,  /* Gecko Profiler was notified of entry */
322
323
        /*
324
         * If set, we entered one of the JITs and ScriptFrameIter should skip
325
         * this frame.
326
         */
327
        RUNNING_IN_JIT         =      0x100,
328
329
        /*
330
         * If set, this frame has been on the stack when
331
         * |js::SavedStacks::saveCurrentStack| was called, and so there is a
332
         * |js::SavedFrame| object cached for this frame.
333
         */
334
        HAS_CACHED_SAVED_FRAME =      0x200,
335
    };
336
337
    mutable uint32_t    flags_;         /* bits described by Flags */
338
    uint32_t            nactual_;       /* number of actual arguments, for function frames */
339
    JSScript*           script_;        /* the script we're executing */
340
    JSObject*           envChain_;      /* current environment chain */
341
    Value               rval_;          /* if HAS_RVAL, return value of the frame */
342
    ArgumentsObject*    argsObj_;       /* if HAS_ARGS_OBJ, the call's arguments object */
343
344
    /*
345
     * Previous frame and its pc and sp. Always nullptr for
346
     * InterpreterActivation's entry frame, always non-nullptr for inline
347
     * frames.
348
     */
349
    InterpreterFrame*   prev_;
350
    jsbytecode*         prevpc_;
351
    Value*              prevsp_;
352
353
    void*               unused;
354
355
    /*
356
     * For an eval-in-frame DEBUGGER_EVAL frame, the frame in whose scope
357
     * we're evaluating code. Iteration treats this as our previous frame.
358
     */
359
    AbstractFramePtr    evalInFramePrev_;
360
361
    Value*              argv_;         /* If hasArgs(), points to frame's arguments. */
362
    LifoAlloc::Mark     mark_;          /* Used to release memory for this frame. */
363
364
0
    static void staticAsserts() {
365
0
        JS_STATIC_ASSERT(offsetof(InterpreterFrame, rval_) % sizeof(Value) == 0);
366
0
        JS_STATIC_ASSERT(sizeof(InterpreterFrame) % sizeof(Value) == 0);
367
0
    }
368
369
    /*
370
     * The utilities are private since they are not able to assert that only
371
     * unaliased vars/formals are accessed. Normal code should prefer the
372
     * InterpreterFrame::unaliased* members (or InterpreterRegs::stackDepth for
373
     * the usual "depth is at least" assertions).
374
     */
375
1.13k
    Value* slots() const { return (Value*)(this + 1); }
376
1
    Value* base() const { return slots() + script()->nfixed(); }
377
378
    friend class FrameIter;
379
    friend class InterpreterRegs;
380
    friend class InterpreterStack;
381
    friend class jit::BaselineFrame;
382
383
    /*
384
     * Frame initialization, called by InterpreterStack operations after acquiring
385
     * the raw memory for the frame:
386
     */
387
388
    /* Used for Invoke and Interpret. */
389
    void initCallFrame(InterpreterFrame* prev, jsbytecode* prevpc, Value* prevsp,
390
                       JSFunction& callee, JSScript* script, Value* argv, uint32_t nactual,
391
                       MaybeConstruct constructing);
392
393
    /* Used for global and eval frames. */
394
    void initExecuteFrame(JSContext* cx, HandleScript script, AbstractFramePtr prev,
395
                          const Value& newTargetValue, HandleObject envChain);
396
397
  public:
398
    /*
399
     * Frame prologue/epilogue
400
     *
401
     * Every stack frame must have 'prologue' called before executing the
402
     * first op and 'epilogue' called after executing the last op and before
403
     * popping the frame (whether the exit is exceptional or not).
404
     *
405
     * For inline JS calls/returns, it is easy to call the prologue/epilogue
406
     * exactly once. When calling JS from C++, Invoke/Execute push the stack
407
     * frame but do *not* call the prologue/epilogue. That means Interpret
408
     * must call the prologue/epilogue for the entry frame. This scheme
409
     * simplifies jit compilation.
410
     *
411
     * An important corner case is what happens when an error occurs (OOM,
412
     * over-recursed) after pushing the stack frame but before 'prologue' is
413
     * called or completes fully. To simplify usage, 'epilogue' does not assume
414
     * 'prologue' has completed and handles all the intermediate state details.
415
     */
416
417
    bool prologue(JSContext* cx);
418
    void epilogue(JSContext* cx, jsbytecode* pc);
419
420
    bool checkReturn(JSContext* cx, HandleValue thisv);
421
422
    bool initFunctionEnvironmentObjects(JSContext* cx);
423
424
    /*
425
     * Initialize locals of newly-pushed frame to undefined.
426
     */
427
    void initLocals();
428
429
    /*
430
     * Stack frame type
431
     *
432
     * A stack frame may have one of four types, which determines which
433
     * members of the frame may be accessed and other invariants:
434
     *
435
     *  global frame:   execution of global code
436
     *  function frame: execution of function code
437
     *  module frame:   execution of a module
438
     *  eval frame:     execution of eval code
439
     */
440
441
155
    bool isGlobalFrame() const {
442
155
        return script_->isGlobalCode();
443
155
    }
444
445
147
    bool isModuleFrame() const {
446
147
        return script_->module();
447
147
    }
448
449
333
    bool isEvalFrame() const {
450
333
        return script_->isForEval();
451
333
    }
452
453
167
    bool isFunctionFrame() const {
454
167
        return script_->functionNonDelazifying();
455
167
    }
456
457
0
    inline bool isStrictEvalFrame() const {
458
0
        return isEvalFrame() && script()->strict();
459
0
    }
460
461
0
    bool isNonStrictEvalFrame() const {
462
0
        return isEvalFrame() && !script()->strict();
463
0
    }
464
465
    bool isNonGlobalEvalFrame() const;
466
467
0
    bool isNonStrictDirectEvalFrame() const {
468
0
        return isNonStrictEvalFrame() && isNonGlobalEvalFrame();
469
0
    }
470
471
    /*
472
     * Previous frame
473
     *
474
     * A frame's 'prev' frame is either null or the previous frame pointed to
475
     * by cx->regs->fp when this frame was pushed. Often, given two prev-linked
476
     * frames, the next-frame is a function or eval that was called by the
477
     * prev-frame, but not always: the prev-frame may have called a native that
478
     * reentered the VM through JS_CallFunctionValue on the same context
479
     * (without calling JS_SaveFrameChain) which pushed the next-frame. Thus,
480
     * 'prev' has little semantic meaning and basically just tells the VM what
481
     * to set cx->regs->fp to when this frame is popped.
482
     */
483
484
94
    InterpreterFrame* prev() const {
485
94
        return prev_;
486
94
    }
487
488
0
    AbstractFramePtr evalInFramePrev() const {
489
0
        MOZ_ASSERT(isEvalFrame());
490
0
        return evalInFramePrev_;
491
0
    }
492
493
    /*
494
     * (Unaliased) locals and arguments
495
     *
496
     * Only non-eval function frames have arguments. The arguments pushed by
497
     * the caller are the 'actual' arguments. The declared arguments of the
498
     * callee are the 'formal' arguments. When the caller passes less actual
499
     * arguments, missing formal arguments are padded with |undefined|.
500
     *
501
     * When a local/formal variable is aliased (accessed by nested closures,
502
     * environment operations, or 'arguments'), the canonical location for
503
     * that value is the slot of an environment object.  Aliased locals don't
504
     * have stack slots assigned to them.  These functions assert that
505
     * accesses to stack values are unaliased.
506
     */
507
508
    inline Value& unaliasedLocal(uint32_t i);
509
510
0
    bool hasArgs() const { return isFunctionFrame(); }
511
    inline Value& unaliasedFormal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
512
    inline Value& unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
513
    template <class Op> inline void unaliasedForEachActual(Op op);
514
515
1
    unsigned numFormalArgs() const { MOZ_ASSERT(hasArgs()); return callee().nargs(); }
516
108
    unsigned numActualArgs() const { MOZ_ASSERT(hasArgs()); return nactual_; }
517
518
    /* Watch out, this exposes a pointer to the unaliased formal arg array. */
519
1.09k
    Value* argv() const { MOZ_ASSERT(hasArgs()); return argv_; }
520
521
    /*
522
     * Arguments object
523
     *
524
     * If a non-eval function has script->needsArgsObj, an arguments object is
525
     * created in the prologue and stored in the local variable for the
526
     * 'arguments' binding (script->argumentsLocal). Since this local is
527
     * mutable, the arguments object can be overwritten and we can "lose" the
528
     * arguments object. Thus, InterpreterFrame keeps an explicit argsObj_ field so
529
     * that the original arguments object is always available.
530
     */
531
532
    ArgumentsObject& argsObj() const;
533
    void initArgsObj(ArgumentsObject& argsobj);
534
535
    ArrayObject* createRestParameter(JSContext* cx);
536
537
    /*
538
     * Environment chain
539
     *
540
     * In theory, the environment chain would contain an object for every
541
     * lexical scope. However, only objects that are required for dynamic
542
     * lookup are actually created.
543
     *
544
     * Given that an InterpreterFrame corresponds roughly to a ES Execution
545
     * Context (ES 10.3), InterpreterFrame::varObj corresponds to the
546
     * VariableEnvironment component of a Exection Context. Intuitively, the
547
     * variables object is where new bindings (variables and functions) are
548
     * stored. One might expect that this is either the Call object or
549
     * envChain.globalObj for function or global code, respectively, however
550
     * the JSAPI allows calls of Execute to specify a variables object on the
551
     * environment chain other than the call/global object. This allows
552
     * embeddings to run multiple scripts under the same global, each time
553
     * using a new variables object to collect and discard the script's global
554
     * variables.
555
     */
556
557
    inline HandleObject environmentChain() const;
558
559
    inline EnvironmentObject& aliasedEnvironment(EnvironmentCoordinate ec) const;
560
    inline GlobalObject& global() const;
561
    inline CallObject& callObj() const;
562
    inline JSObject& varObj() const;
563
    inline LexicalEnvironmentObject& extensibleLexicalEnvironment() const;
564
565
    template <typename SpecificEnvironment>
566
    inline void pushOnEnvironmentChain(SpecificEnvironment& env);
567
    template <typename SpecificEnvironment>
568
    inline void popOffEnvironmentChain();
569
    inline void replaceInnermostEnvironment(EnvironmentObject& env);
570
571
    // Push a VarEnvironmentObject for function frames of functions that have
572
    // parameter expressions with closed over var bindings.
573
    bool pushVarEnvironment(JSContext* cx, HandleScope scope);
574
575
    /*
576
     * For lexical envs with aliased locals, these interfaces push and pop
577
     * entries on the environment chain.  The "freshen" operation replaces the
578
     * current lexical env with a fresh copy of it, to implement semantics
579
     * providing distinct bindings per iteration of a for(;;) loop whose head
580
     * has a lexical declaration.  The "recreate" operation replaces the
581
     * current lexical env with a copy of it containing uninitialized
582
     * bindings, to implement semantics providing distinct bindings per
583
     * iteration of a for-in/of loop.
584
     */
585
586
    bool pushLexicalEnvironment(JSContext* cx, Handle<LexicalScope*> scope);
587
    bool freshenLexicalEnvironment(JSContext* cx);
588
    bool recreateLexicalEnvironment(JSContext* cx);
589
590
    /*
591
     * Script
592
     *
593
     * All frames have an associated JSScript which holds the bytecode being
594
     * executed for the frame.
595
     */
596
597
1.81k
    JSScript* script() const {
598
1.81k
        return script_;
599
1.81k
    }
600
601
    /* Return the previous frame's pc. */
602
94
    jsbytecode* prevpc() {
603
94
        MOZ_ASSERT(prev_);
604
94
        return prevpc_;
605
94
    }
606
607
    /* Return the previous frame's sp. */
608
94
    Value* prevsp() {
609
94
        MOZ_ASSERT(prev_);
610
94
        return prevsp_;
611
94
    }
612
613
    /*
614
     * Return the 'this' argument passed to a non-eval function frame. This is
615
     * not necessarily the frame's this-binding, for instance non-strict
616
     * functions will box primitive 'this' values and thisArgument() will
617
     * return the original, unboxed Value.
618
     */
619
77
    Value& thisArgument() const {
620
77
        MOZ_ASSERT(isFunctionFrame());
621
77
        return argv()[-1];
622
77
    }
623
624
    /*
625
     * Callee
626
     *
627
     * Only function frames have a callee. An eval frame in a function has the
628
     * same callee as its containing function frame.
629
     */
630
631
488
    JSFunction& callee() const {
632
488
        MOZ_ASSERT(isFunctionFrame());
633
488
        return calleev().toObject().as<JSFunction>();
634
488
    }
635
636
488
    const Value& calleev() const {
637
488
        MOZ_ASSERT(isFunctionFrame());
638
488
        return argv()[-2];
639
488
    }
640
641
    /*
642
     * New Target
643
     *
644
     * Only function frames have a meaningful newTarget. An eval frame in a
645
     * function will have a copy of the newTarget of the enclosing function
646
     * frame.
647
     */
648
3
    Value newTarget() const {
649
3
        if (isEvalFrame()) {
650
0
            return ((Value*)this)[-1];
651
0
        }
652
3
653
3
        MOZ_ASSERT(isFunctionFrame());
654
3
655
3
        if (callee().isArrow()) {
656
0
            return callee().getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
657
0
        }
658
3
659
3
        if (isConstructing()) {
660
0
            unsigned pushedArgs = Max(numFormalArgs(), numActualArgs());
661
0
            return argv()[pushedArgs];
662
0
        }
663
3
        return UndefinedValue();
664
3
    }
665
666
    /* Profiler flags */
667
668
760
    bool hasPushedGeckoProfilerFrame() {
669
760
        return !!(flags_ & HAS_PUSHED_PROF_FRAME);
670
760
    }
671
672
0
    void setPushedGeckoProfilerFrame() {
673
0
        flags_ |= HAS_PUSHED_PROF_FRAME;
674
0
    }
675
676
0
    void unsetPushedGeckoProfilerFrame() {
677
0
        flags_ &= ~HAS_PUSHED_PROF_FRAME;
678
0
    }
679
680
    /* Return value */
681
682
166
    bool hasReturnValue() const {
683
166
        return flags_ & HAS_RVAL;
684
166
    }
685
686
165
    MutableHandleValue returnValue() {
687
165
        if (!hasReturnValue()) {
688
28
            rval_.setUndefined();
689
28
        }
690
165
        return MutableHandleValue::fromMarkedLocation(&rval_);
691
165
    }
692
693
194
    void markReturnValue() {
694
194
        flags_ |= HAS_RVAL;
695
194
    }
696
697
194
    void setReturnValue(const Value& v) {
698
194
        rval_ = v;
699
194
        markReturnValue();
700
194
    }
701
702
0
    void clearReturnValue() {
703
0
        rval_.setUndefined();
704
0
        markReturnValue();
705
0
    }
706
707
0
    void resumeGeneratorFrame(JSObject* envChain) {
708
0
        MOZ_ASSERT(script()->isGenerator() || script()->isAsync());
709
0
        MOZ_ASSERT(isFunctionFrame());
710
0
        flags_ |= HAS_INITIAL_ENV;
711
0
        envChain_ = envChain;
712
0
    }
713
714
    /*
715
     * Other flags
716
     */
717
718
244
    bool isConstructing() const {
719
244
        return !!(flags_ & CONSTRUCTING);
720
244
    }
721
722
0
    void setResumedGenerator() {
723
0
        flags_ |= RESUMED_GENERATOR;
724
0
    }
725
94
    bool isResumedGenerator() const {
726
94
        return !!(flags_ & RESUMED_GENERATOR);
727
94
    }
728
729
    /*
730
     * These two queries should not be used in general: the presence/absence of
731
     * the call/args object is determined by the static(ish) properties of the
732
     * JSFunction/JSScript. These queries should only be performed when probing
733
     * a stack frame that may be in the middle of the prologue (during which
734
     * time the call/args object are created).
735
     */
736
737
    inline bool hasInitialEnvironment() const;
738
739
1
    bool hasInitialEnvironmentUnchecked() const {
740
1
        return flags_ & HAS_INITIAL_ENV;
741
1
    }
742
743
0
    bool hasArgsObj() const {
744
0
        MOZ_ASSERT(script()->needsArgsObj());
745
0
        return flags_ & HAS_ARGS_OBJ;
746
0
    }
747
748
    /*
749
     * Debugger eval frames.
750
     *
751
     * - If evalInFramePrev_ is non-null, frame was created for an "eval in
752
     *   frame" call, which can push a successor to any live frame; so its
753
     *   logical "prev" frame is not necessarily the previous frame in memory.
754
     *   Iteration should treat evalInFramePrev_ as this frame's previous frame.
755
     *
756
     * - Don't bother to JIT it, because it's probably short-lived.
757
     *
758
     * - It is required to have a environment chain object outside the
759
     *   js::EnvironmentObject hierarchy: either a global object, or a
760
     *   DebugEnvironmentProxy.
761
     */
762
12
    bool isDebuggerEvalFrame() const {
763
12
        return isEvalFrame() && !!evalInFramePrev_;
764
12
    }
765
766
0
    bool prevUpToDate() const {
767
0
        return !!(flags_ & PREV_UP_TO_DATE);
768
0
    }
769
770
0
    void setPrevUpToDate() {
771
0
        flags_ |= PREV_UP_TO_DATE;
772
0
    }
773
774
0
    void unsetPrevUpToDate() {
775
0
        flags_ &= ~PREV_UP_TO_DATE;
776
0
    }
777
778
324
    bool isDebuggee() const {
779
324
        return !!(flags_ & DEBUGGEE);
780
324
    }
781
782
0
    void setIsDebuggee() {
783
0
        flags_ |= DEBUGGEE;
784
0
    }
785
786
    inline void unsetIsDebuggee();
787
788
0
    bool hasCachedSavedFrame() const {
789
0
        return flags_ & HAS_CACHED_SAVED_FRAME;
790
0
    }
791
0
    void setHasCachedSavedFrame() {
792
0
        flags_ |= HAS_CACHED_SAVED_FRAME;
793
0
    }
794
0
    void clearHasCachedSavedFrame() {
795
0
        flags_ &= ~HAS_CACHED_SAVED_FRAME;
796
0
    }
797
798
  public:
799
    void trace(JSTracer* trc, Value* sp, jsbytecode* pc);
800
    void traceValues(JSTracer* trc, unsigned start, unsigned end);
801
802
    // Entered Baseline/Ion from the interpreter.
803
8
    bool runningInJit() const {
804
8
        return !!(flags_ & RUNNING_IN_JIT);
805
8
    }
806
1
    void setRunningInJit() {
807
1
        flags_ |= RUNNING_IN_JIT;
808
1
    }
809
1
    void clearRunningInJit() {
810
1
        flags_ &= ~RUNNING_IN_JIT;
811
1
    }
812
};
813
814
/*****************************************************************************/
815
816
class InterpreterRegs
817
{
818
  public:
819
    Value* sp;
820
    jsbytecode* pc;
821
  private:
822
    InterpreterFrame* fp_;
823
  public:
824
6.93k
    InterpreterFrame* fp() const { return fp_; }
825
826
1
    unsigned stackDepth() const {
827
1
        MOZ_ASSERT(sp >= fp_->base());
828
1
        return sp - fp_->base();
829
1
    }
830
831
0
    Value* spForStackDepth(unsigned depth) const {
832
0
        MOZ_ASSERT(fp_->script()->nfixed() + depth <= fp_->script()->nslots());
833
0
        return fp_->base() + depth;
834
0
    }
835
836
    /* For generators. */
837
0
    void rebaseFromTo(const InterpreterRegs& from, InterpreterFrame& to) {
838
0
        fp_ = &to;
839
0
        sp = to.slots() + (from.sp - from.fp_->slots());
840
0
        pc = from.pc;
841
0
        MOZ_ASSERT(fp_);
842
0
    }
843
844
94
    void popInlineFrame() {
845
94
        pc = fp_->prevpc();
846
94
        unsigned spForNewTarget = fp_->isResumedGenerator() ? 0 : fp_->isConstructing();
847
94
        sp = fp_->prevsp() - fp_->numActualArgs() - 1 - spForNewTarget;
848
94
        fp_ = fp_->prev();
849
94
        MOZ_ASSERT(fp_);
850
94
    }
851
155
    void prepareToRun(InterpreterFrame& fp, JSScript* script) {
852
155
        pc = script->code();
853
155
        sp = fp.slots() + script->nfixed();
854
155
        fp_ = &fp;
855
155
    }
856
857
    void setToEndOfScript();
858
859
1.65k
    MutableHandleValue stackHandleAt(int i) {
860
1.65k
        return MutableHandleValue::fromMarkedLocation(&sp[i]);
861
1.65k
    }
862
863
0
    HandleValue stackHandleAt(int i) const {
864
0
        return HandleValue::fromMarkedLocation(&sp[i]);
865
0
    }
866
867
    friend void GDBTestInitInterpreterRegs(InterpreterRegs&, js::InterpreterFrame*,
868
                                           JS::Value*, uint8_t*);
869
};
870
871
/*****************************************************************************/
872
873
class InterpreterStack
874
{
875
    friend class InterpreterActivation;
876
877
    static const size_t DEFAULT_CHUNK_SIZE = 4 * 1024;
878
    LifoAlloc allocator_;
879
880
    // Number of interpreter frames on the stack, for over-recursion checks.
881
    static const size_t MAX_FRAMES = 50 * 1000;
882
    static const size_t MAX_FRAMES_TRUSTED = MAX_FRAMES + 1000;
883
    size_t frameCount_;
884
885
    inline uint8_t* allocateFrame(JSContext* cx, size_t size);
886
887
    inline InterpreterFrame*
888
    getCallFrame(JSContext* cx, const CallArgs& args, HandleScript script,
889
                 MaybeConstruct constructing, Value** pargv);
890
891
155
    void releaseFrame(InterpreterFrame* fp) {
892
155
        frameCount_--;
893
155
        allocator_.release(fp->mark_);
894
155
    }
895
896
  public:
897
    InterpreterStack()
898
      : allocator_(DEFAULT_CHUNK_SIZE),
899
        frameCount_(0)
900
27
    { }
901
902
0
    ~InterpreterStack() {
903
0
        MOZ_ASSERT(frameCount_ == 0);
904
0
    }
905
906
    // For execution of eval or global code.
907
    InterpreterFrame* pushExecuteFrame(JSContext* cx, HandleScript script,
908
                                       const Value& newTargetValue, HandleObject envChain,
909
                                       AbstractFramePtr evalInFrame);
910
911
    // Called to invoke a function.
912
    InterpreterFrame* pushInvokeFrame(JSContext* cx, const CallArgs& args,
913
                                      MaybeConstruct constructing);
914
915
    // The interpreter can push light-weight, "inline" frames without entering a
916
    // new InterpreterActivation or recursively calling Interpret.
917
    bool pushInlineFrame(JSContext* cx, InterpreterRegs& regs, const CallArgs& args,
918
                         HandleScript script, MaybeConstruct constructing);
919
920
    void popInlineFrame(InterpreterRegs& regs);
921
922
    bool resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs,
923
                                  HandleFunction callee, HandleObject envChain);
924
925
    inline void purge(JSRuntime* rt);
926
927
0
    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
928
0
        return allocator_.sizeOfExcludingThis(mallocSizeOf);
929
0
    }
930
};
931
932
void TraceInterpreterActivations(JSContext* cx, JSTracer* trc);
933
934
/*****************************************************************************/
935
936
/** Base class for all function call args. */
937
class AnyInvokeArgs : public JS::CallArgs
938
{
939
};
940
941
/** Base class for all function construction args. */
942
class AnyConstructArgs : public JS::CallArgs
943
{
944
    // Only js::Construct (or internal methods that call the qualified CallArgs
945
    // versions) should do these things!
946
    void setCallee(const Value& v) = delete;
947
    void setThis(const Value& v) = delete;
948
    MutableHandleValue newTarget() const = delete;
949
    MutableHandleValue rval() const = delete;
950
};
951
952
namespace detail {
953
954
/** Function call/construct args of statically-unknown count. */
955
template <MaybeConstruct Construct>
956
class GenericArgsBase
957
  : public mozilla::Conditional<Construct, AnyConstructArgs, AnyInvokeArgs>::Type
958
{
959
  protected:
960
    AutoValueVector v_;
961
962
6.45M
    explicit GenericArgsBase(JSContext* cx) : v_(cx) {}
js::detail::GenericArgsBase<(js::MaybeConstruct)0>::GenericArgsBase(JSContext*)
Line
Count
Source
962
6.45M
    explicit GenericArgsBase(JSContext* cx) : v_(cx) {}
Unexecuted instantiation: js::detail::GenericArgsBase<(js::MaybeConstruct)1>::GenericArgsBase(JSContext*)
963
964
  public:
965
6.45M
    bool init(JSContext* cx, unsigned argc) {
966
6.45M
        if (argc > ARGS_LENGTH_MAX) {
967
0
            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TOO_MANY_ARGUMENTS);
968
0
            return false;
969
0
        }
970
6.45M
971
6.45M
        // callee, this, arguments[, new.target iff constructing]
972
6.45M
        size_t len = 2 + argc + uint32_t(Construct);
973
6.45M
        MOZ_ASSERT(len > argc);  // no overflow
974
6.45M
        if (!v_.resize(len)) {
975
0
            return false;
976
0
        }
977
6.45M
978
6.45M
        *static_cast<JS::CallArgs*>(this) = CallArgsFromVp(argc, v_.begin());
979
6.45M
        this->constructing_ = Construct;
980
6.45M
        if (Construct) {
981
0
            this->CallArgs::setThis(MagicValue(JS_IS_CONSTRUCTING));
982
0
        }
983
6.45M
        return true;
984
6.45M
    }
js::detail::GenericArgsBase<(js::MaybeConstruct)0>::init(JSContext*, unsigned int)
Line
Count
Source
965
6.45M
    bool init(JSContext* cx, unsigned argc) {
966
6.45M
        if (argc > ARGS_LENGTH_MAX) {
967
0
            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TOO_MANY_ARGUMENTS);
968
0
            return false;
969
0
        }
970
6.45M
971
6.45M
        // callee, this, arguments[, new.target iff constructing]
972
6.45M
        size_t len = 2 + argc + uint32_t(Construct);
973
6.45M
        MOZ_ASSERT(len > argc);  // no overflow
974
6.45M
        if (!v_.resize(len)) {
975
0
            return false;
976
0
        }
977
6.45M
978
6.45M
        *static_cast<JS::CallArgs*>(this) = CallArgsFromVp(argc, v_.begin());
979
6.45M
        this->constructing_ = Construct;
980
6.45M
        if (Construct) {
981
0
            this->CallArgs::setThis(MagicValue(JS_IS_CONSTRUCTING));
982
0
        }
983
6.45M
        return true;
984
6.45M
    }
Unexecuted instantiation: js::detail::GenericArgsBase<(js::MaybeConstruct)1>::init(JSContext*, unsigned int)
985
};
986
987
/** Function call/construct args of statically-known count. */
988
template <MaybeConstruct Construct, size_t N>
989
class FixedArgsBase
990
  : public mozilla::Conditional<Construct, AnyConstructArgs, AnyInvokeArgs>::Type
991
{
992
    static_assert(N <= ARGS_LENGTH_MAX, "o/~ too many args o/~");
993
994
  protected:
995
    JS::AutoValueArray<2 + N + uint32_t(Construct)> v_;
996
997
4
    explicit FixedArgsBase(JSContext* cx) : v_(cx) {
998
4
        *static_cast<JS::CallArgs*>(this) = CallArgsFromVp(N, v_.begin());
999
4
        this->constructing_ = Construct;
1000
4
        if (Construct) {
1001
0
            this->CallArgs::setThis(MagicValue(JS_IS_CONSTRUCTING));
1002
0
        }
1003
4
    }
Unexecuted instantiation: js::detail::FixedArgsBase<(js::MaybeConstruct)0, 2ul>::FixedArgsBase(JSContext*)
Unexecuted instantiation: js::detail::FixedArgsBase<(js::MaybeConstruct)1, 1ul>::FixedArgsBase(JSContext*)
js::detail::FixedArgsBase<(js::MaybeConstruct)0, 1ul>::FixedArgsBase(JSContext*)
Line
Count
Source
997
1
    explicit FixedArgsBase(JSContext* cx) : v_(cx) {
998
1
        *static_cast<JS::CallArgs*>(this) = CallArgsFromVp(N, v_.begin());
999
1
        this->constructing_ = Construct;
1000
1
        if (Construct) {
1001
0
            this->CallArgs::setThis(MagicValue(JS_IS_CONSTRUCTING));
1002
0
        }
1003
1
    }
Unexecuted instantiation: js::detail::FixedArgsBase<(js::MaybeConstruct)1, 3ul>::FixedArgsBase(JSContext*)
js::detail::FixedArgsBase<(js::MaybeConstruct)0, 0ul>::FixedArgsBase(JSContext*)
Line
Count
Source
997
3
    explicit FixedArgsBase(JSContext* cx) : v_(cx) {
998
3
        *static_cast<JS::CallArgs*>(this) = CallArgsFromVp(N, v_.begin());
999
3
        this->constructing_ = Construct;
1000
3
        if (Construct) {
1001
0
            this->CallArgs::setThis(MagicValue(JS_IS_CONSTRUCTING));
1002
0
        }
1003
3
    }
Unexecuted instantiation: js::detail::FixedArgsBase<(js::MaybeConstruct)0, 3ul>::FixedArgsBase(JSContext*)
Unexecuted instantiation: js::detail::FixedArgsBase<(js::MaybeConstruct)0, 5ul>::FixedArgsBase(JSContext*)
Unexecuted instantiation: js::detail::FixedArgsBase<(js::MaybeConstruct)0, 4ul>::FixedArgsBase(JSContext*)
1004
};
1005
1006
} // namespace detail
1007
1008
/** Function call args of statically-unknown count. */
1009
class InvokeArgs : public detail::GenericArgsBase<NO_CONSTRUCT>
1010
{
1011
    using Base = detail::GenericArgsBase<NO_CONSTRUCT>;
1012
1013
  public:
1014
1.62M
    explicit InvokeArgs(JSContext* cx) : Base(cx) {}
1015
};
1016
1017
/** Function call args of statically-unknown count. */
1018
class InvokeArgsMaybeIgnoresReturnValue : public detail::GenericArgsBase<NO_CONSTRUCT>
1019
{
1020
    using Base = detail::GenericArgsBase<NO_CONSTRUCT>;
1021
1022
  public:
1023
4.82M
    explicit InvokeArgsMaybeIgnoresReturnValue(JSContext* cx, bool ignoresReturnValue) : Base(cx) {
1024
4.82M
        this->ignoresReturnValue_ = ignoresReturnValue;
1025
4.82M
    }
1026
};
1027
1028
/** Function call args of statically-known count. */
1029
template <size_t N>
1030
class FixedInvokeArgs : public detail::FixedArgsBase<NO_CONSTRUCT, N>
1031
{
1032
    using Base = detail::FixedArgsBase<NO_CONSTRUCT, N>;
1033
1034
  public:
1035
4
    explicit FixedInvokeArgs(JSContext* cx) : Base(cx) {}
Unexecuted instantiation: js::FixedInvokeArgs<2ul>::FixedInvokeArgs(JSContext*)
js::FixedInvokeArgs<1ul>::FixedInvokeArgs(JSContext*)
Line
Count
Source
1035
1
    explicit FixedInvokeArgs(JSContext* cx) : Base(cx) {}
js::FixedInvokeArgs<0ul>::FixedInvokeArgs(JSContext*)
Line
Count
Source
1035
3
    explicit FixedInvokeArgs(JSContext* cx) : Base(cx) {}
Unexecuted instantiation: js::FixedInvokeArgs<3ul>::FixedInvokeArgs(JSContext*)
Unexecuted instantiation: js::FixedInvokeArgs<5ul>::FixedInvokeArgs(JSContext*)
Unexecuted instantiation: js::FixedInvokeArgs<4ul>::FixedInvokeArgs(JSContext*)
1036
};
1037
1038
/** Function construct args of statically-unknown count. */
1039
class ConstructArgs : public detail::GenericArgsBase<CONSTRUCT>
1040
{
1041
    using Base = detail::GenericArgsBase<CONSTRUCT>;
1042
1043
  public:
1044
0
    explicit ConstructArgs(JSContext* cx) : Base(cx) {}
1045
};
1046
1047
/** Function call args of statically-known count. */
1048
template <size_t N>
1049
class FixedConstructArgs : public detail::FixedArgsBase<CONSTRUCT, N>
1050
{
1051
    using Base = detail::FixedArgsBase<CONSTRUCT, N>;
1052
1053
  public:
1054
0
    explicit FixedConstructArgs(JSContext* cx) : Base(cx) {}
Unexecuted instantiation: js::FixedConstructArgs<1ul>::FixedConstructArgs(JSContext*)
Unexecuted instantiation: js::FixedConstructArgs<3ul>::FixedConstructArgs(JSContext*)
1055
};
1056
1057
template <class Args, class Arraylike>
1058
inline bool
1059
FillArgumentsFromArraylike(JSContext* cx, Args& args, const Arraylike& arraylike)
1060
1.62M
{
1061
1.62M
    uint32_t len = arraylike.length();
1062
1.62M
    if (!args.init(cx, len)) {
1063
0
        return false;
1064
0
    }
1065
1.62M
1066
6.49M
    for (uint32_t i = 0; i < len; i++) {
1067
4.87M
        args[i].set(arraylike[i]);
1068
4.87M
    }
1069
1.62M
1070
1.62M
    return true;
1071
1.62M
}
bool js::FillArgumentsFromArraylike<js::InvokeArgs, JS::HandleValueArray>(JSContext*, js::InvokeArgs&, JS::HandleValueArray const&)
Line
Count
Source
1060
1.62M
{
1061
1.62M
    uint32_t len = arraylike.length();
1062
1.62M
    if (!args.init(cx, len)) {
1063
0
        return false;
1064
0
    }
1065
1.62M
1066
6.49M
    for (uint32_t i = 0; i < len; i++) {
1067
4.87M
        args[i].set(arraylike[i]);
1068
4.87M
    }
1069
1.62M
1070
1.62M
    return true;
1071
1.62M
}
Unexecuted instantiation: bool js::FillArgumentsFromArraylike<js::ConstructArgs, JS::HandleValueArray>(JSContext*, js::ConstructArgs&, JS::HandleValueArray const&)
Unexecuted instantiation: bool js::FillArgumentsFromArraylike<js::InvokeArgs, JS::CallArgs>(JSContext*, js::InvokeArgs&, JS::CallArgs const&)
Unexecuted instantiation: bool js::FillArgumentsFromArraylike<js::ConstructArgs, JS::CallArgs>(JSContext*, js::ConstructArgs&, JS::CallArgs const&)
1072
1073
} // namespace js
1074
1075
namespace mozilla {
1076
1077
template <>
1078
struct DefaultHasher<js::AbstractFramePtr> {
1079
    typedef js::AbstractFramePtr Lookup;
1080
1081
0
    static js::HashNumber hash(const Lookup& key) {
1082
0
        return mozilla::HashGeneric(key.raw());
1083
0
    }
1084
1085
0
    static bool match(const js::AbstractFramePtr& k, const Lookup& l) {
1086
0
        return k == l;
1087
0
    }
1088
};
1089
1090
} // namespace mozilla
1091
1092
namespace js {
1093
1094
/*****************************************************************************/
1095
1096
// SavedFrame caching to minimize stack walking.
1097
//
1098
// Since each SavedFrame object includes a 'parent' pointer to the SavedFrame
1099
// for its caller, if we could easily find the right SavedFrame for a given
1100
// stack frame, we wouldn't need to walk the rest of the stack. Traversing deep
1101
// stacks can be expensive, and when we're profiling or instrumenting code, we
1102
// may want to capture JavaScript stacks frequently, so such cases would benefit
1103
// if we could avoid walking the entire stack.
1104
//
1105
// We could have a cache mapping frame addresses to their SavedFrame objects,
1106
// but invalidating its entries would be a challenge. Popping a stack frame is
1107
// extremely performance-sensitive, and SpiderMonkey stack frames can be OSR'd,
1108
// thrown, rematerialized, and perhaps meet other fates; we would rather our
1109
// cache not depend on handling so many tricky cases.
1110
//
1111
// It turns out that we can keep the cache accurate by reserving a single bit in
1112
// the stack frame, which must be clear on any newly pushed frame. When we
1113
// insert an entry into the cache mapping a given frame address to its
1114
// SavedFrame, we set the bit in the frame. Then, we take care to probe the
1115
// cache only for frames whose bit is set; the bit tells us that the frame has
1116
// never left the stack, so its cache entry must be accurate, at least about
1117
// which function the frame is executing (the line may have changed; more about
1118
// that below). The code refers to this bit as the 'hasCachedSavedFrame' flag.
1119
//
1120
// We could manage such a cache replacing least-recently used entries, but we
1121
// can do better than that: the cache can be a stack, of which we need examine
1122
// only entries from the top.
1123
//
1124
// First, observe that stacks are walked from the youngest frame to the oldest,
1125
// but SavedFrame chains are built from oldest to youngest, to ensure common
1126
// tails are shared. This means that capturing a stack is necessarily a
1127
// two-phase process: walk the stack, and then build the SavedFrames.
1128
//
1129
// Naturally, the first time we capture the stack, the cache is empty, and we
1130
// must traverse the entire stack. As we build each SavedFrame, we push an entry
1131
// associating the frame's address to its SavedFrame on the cache, and set the
1132
// frame's bit. At the end, every frame has its bit set and an entry in the
1133
// cache.
1134
//
1135
// Then the program runs some more. Some, none, or all of the frames are popped.
1136
// Any new frames are pushed with their bit clear. Any frame with its bit set
1137
// has never left the stack. The cache is left untouched.
1138
//
1139
// For the next capture, we walk the stack up to the first frame with its bit
1140
// set, if there is one. Call it F; it must have a cache entry. We pop entries
1141
// from the cache - all invalid, because they are above F's entry, and hence
1142
// younger - until we find the entry matching F's address. Since F's bit is set,
1143
// we know it never left the stack, and hence that no younger frame could have
1144
// had a colliding address. And since the frame's bit was set when we pushed the
1145
// cache entry, we know the entry is still valid.
1146
//
1147
// F's cache entry's SavedFrame covers the rest of the stack, so we don't need
1148
// to walk the stack any further. Now we begin building SavedFrame objects for
1149
// the new frames, pushing cache entries, and setting bits on the frames. By the
1150
// end, the cache again covers the full stack, and every frame's bit is set.
1151
//
1152
// If we walk the stack to the end, and find no frame with its bit set, then the
1153
// entire cache is invalid. At this point, it must be emptied, so that the new
1154
// entries we are about to push are the only frames in the cache.
1155
//
1156
// For example, suppose we have the following stack (let 'A > B' mean "A called
1157
// B", so the frames are listed oldest first):
1158
//
1159
//     P  > Q  > R  > S          Initial stack, bits not set.
1160
//     P* > Q* > R* > S*         Capture a SavedFrame stack, set bits.
1161
//                               The cache now holds: P > Q > R > S.
1162
//     P* > Q* > R*              Return from S.
1163
//     P* > Q*                   Return from R.
1164
//     P* > Q* > T  > U          Call T and U. New frames have clear bits.
1165
//
1166
// If we capture the stack now, the cache still holds:
1167
//
1168
//     P  > Q  > R  > S
1169
//
1170
// As we traverse the stack, we'll cross U and T, and then find Q with its bit
1171
// set. We pop entries from the cache until we find the entry for Q; this
1172
// removes entries R and S, which were indeed invalid. In Q's cache entry, we
1173
// find the SavedFrame representing the stack P > Q. Now we build SavedFrames
1174
// for the new portion of the stack, pushing an entry for T and setting the bit
1175
// on the frame, and then doing the same for U. In the end, the call stack again
1176
// has bits set on all its frames:
1177
//
1178
//     P* > Q* > T* > U*         All frames are now in the cache.
1179
//
1180
// And the cache again holds entries for the entire stack:
1181
//
1182
//     P  > Q  > T  > U
1183
//
1184
// Some details:
1185
//
1186
// - When we find a cache entry whose frame address matches our frame F, we know
1187
//   that F has never left the stack, but it may certainly be the case that
1188
//   execution took place in that frame, and that the current source position
1189
//   within F's function has changed. This means that the entry's SavedFrame,
1190
//   which records the source line and column as well as the function, is not
1191
//   correct. To detect this case, when we push a cache entry, we record the
1192
//   frame's pc. When consulting the cache, if a frame's address matches but its
1193
//   pc does not, then we pop the cache entry and continue walking the stack.
1194
//   The next stack frame will definitely hit: since its callee frame never left
1195
//   the stack, the calling frame never got the chance to execute.
1196
//
1197
// - Generators, at least conceptually, have long-lived stack frames that
1198
//   disappear from the stack when the generator yields, and reappear on the
1199
//   stack when the generator's 'next' method is called. When a generator's
1200
//   frame is placed again atop the stack, its bit must be cleared - for the
1201
//   purposes of the cache, treating the frame as a new frame - to respect the
1202
//   invariants we used to justify the algorithm above. Async function
1203
//   activations usually appear atop empty stacks, since they are invoked as a
1204
//   promise callback, but the same rule applies.
1205
//
1206
// - SpiderMonkey has many types of stack frames, and not all have a place to
1207
//   store a bit indicating a cached SavedFrame. But as long as we don't create
1208
//   cache entries for frames we can't mark, simply omitting them from the cache
1209
//   is harmless. Uncacheable frame types include inlined Ion frames and
1210
//   non-Debug wasm frames. The LiveSavedFrameCache::FramePtr type represents
1211
//   only pointers to frames that can be cached, so if you have a FramePtr, you
1212
//   don't need to further check the frame for cachability. FramePtr provides
1213
//   access to the hasCachedSavedFrame bit.
1214
//
1215
// - We actually break up the cache into one cache per Activation. Popping an
1216
//   activation invalidates all its cache entries, simply by freeing the cache
1217
//   altogether.
1218
//
1219
// - The entire chain of SavedFrames for a given stack capture is created in the
1220
//   compartment of the code that requested the capture, *not* in that of the
1221
//   frames it represents, so in general, different compartments may have
1222
//   different SavedFrame objects representing the same actual stack frame. The
1223
//   LiveSavedFrameCache simply records whichever SavedFrames were created most
1224
//   recently. When we find a cache hit, we check the entry's SavedFrame's
1225
//   compartment against the current compartment; if they do not match, we flush
1226
//   the entire cache. This means that it is not always true that, if a frame's
1227
//   bit is set, it must have an entry in the cache. But we can still assert
1228
//   that, if a frame's bit is set and the cache is not completely empty, the
1229
//   frame will have an entry. When the cache is flushed, it will be repopulated
1230
//   immediately with the new capture's frames.
1231
//
1232
// - When the Debugger API evaluates an expression in some frame (the 'target
1233
//   frame'), it's SpiderMonkey's convention that the target frame be treated as
1234
//   the parent of the eval frame. In reality, of course, the eval frame is
1235
//   pushed on the top of the stack like any other frame, but stack captures
1236
//   simply jump straight over the intervening frames, so that the '.parent'
1237
//   property of a SavedFrame for the eval is the SavedFrame for the target.
1238
//   This is arranged by giving the eval frame an 'evalInFramePrev` link
1239
//   pointing to the target, which an ordinary FrameIter will notice and
1240
//   respect.
1241
//
1242
//   If the LiveSavedFrameCache were presented with stack traversals that
1243
//   skipped frames in this way, it would cause havoc. First, with no debugger
1244
//   eval frames present, capture the stack, populating the cache. Then push a
1245
//   debugger eval frame and capture again; the skipped frames to appear to be
1246
//   absent from the stack. Now pop the debugger eval frame, and capture a third
1247
//   time: the no-longer-skipped frames seem to reappear on the stack, with
1248
//   their cached bits still set.
1249
//
1250
//   The LiveSavedFrameCache assumes that the stack it sees is used in a
1251
//   stack-like fashion: if a frame has its bit set, it has never left the
1252
//   stack. To support this assumption, when the cache is in use, we do not skip
1253
//   the frames between a debugger eval frame an its target; we always traverse
1254
//   the entire stack, invalidating and populating the cache in the usual way.
1255
//   Instead, when we construct a SavedFrame for a debugger eval frame, we
1256
//   select the appropriate parent at that point: rather than the next-older
1257
//   frame, we find the SavedFrame for the eval's target frame. The skip appears
1258
//   in the SavedFrame chains, even as the traversal covers all the frames.
1259
class LiveSavedFrameCache
1260
{
1261
  public:
1262
    // The address of a live frame for which we can cache SavedFrames: it has a
1263
    // 'hasCachedSavedFrame' bit we can examine and set, and can be converted to
1264
    // a Key to index the cache.
1265
    class FramePtr {
1266
        // We use jit::CommonFrameLayout for both Baseline frames and Ion
1267
        // physical frames.
1268
        using Ptr = mozilla::Variant<InterpreterFrame*,
1269
                                     jit::CommonFrameLayout*,
1270
                                     jit::RematerializedFrame*,
1271
                                     wasm::DebugFrame*>;
1272
1273
        Ptr ptr;
1274
1275
        template<typename Frame>
1276
0
        explicit FramePtr(Frame ptr) : ptr(ptr) { }
Unexecuted instantiation: js::LiveSavedFrameCache::FramePtr::FramePtr<js::jit::CommonFrameLayout*>(js::jit::CommonFrameLayout*)
Unexecuted instantiation: js::LiveSavedFrameCache::FramePtr::FramePtr<js::InterpreterFrame*>(js::InterpreterFrame*)
Unexecuted instantiation: js::LiveSavedFrameCache::FramePtr::FramePtr<js::wasm::DebugFrame*>(js::wasm::DebugFrame*)
Unexecuted instantiation: js::LiveSavedFrameCache::FramePtr::FramePtr<js::jit::RematerializedFrame*>(js::jit::RematerializedFrame*)
1277
1278
        struct HasCachedMatcher;
1279
        struct SetHasCachedMatcher;
1280
        struct ClearHasCachedMatcher;
1281
1282
      public:
1283
        // If iter's frame is of a type that can be cached, construct a FramePtr
1284
        // for its frame. Otherwise, return Nothing.
1285
        static inline mozilla::Maybe<FramePtr> create(const FrameIter& iter);
1286
1287
        // Construct a FramePtr from an AbstractFramePtr. This always succeeds.
1288
        static inline FramePtr create(AbstractFramePtr abstractFramePtr);
1289
1290
        inline bool hasCachedSavedFrame() const;
1291
        inline void setHasCachedSavedFrame();
1292
        inline void clearHasCachedSavedFrame();
1293
1294
        // Return true if this FramePtr refers to an interpreter frame.
1295
0
        inline bool isInterpreterFrame() const { return ptr.is<InterpreterFrame*>(); }
1296
1297
        // If this FramePtr is an interpreter frame, return a pointer to it.
1298
0
        inline InterpreterFrame& asInterpreterFrame() const { return *ptr.as<InterpreterFrame*>(); }
1299
1300
0
        bool operator==(const FramePtr& rhs) const { return rhs.ptr == this->ptr; }
1301
0
        bool operator!=(const FramePtr& rhs) const { return !(rhs == *this); }
1302
    };
1303
1304
  private:
1305
    // A key in the cache: the address of a frame, live or dead, for which we
1306
    // can cache SavedFrames. Since the pointer may not be live, the only
1307
    // operation this type permits is comparison.
1308
    class Key {
1309
        FramePtr framePtr;
1310
1311
      public:
1312
0
        MOZ_IMPLICIT Key(const FramePtr& framePtr) : framePtr(framePtr) { }
1313
1314
0
        bool operator==(const Key& rhs) const { return rhs.framePtr == this->framePtr; }
1315
0
        bool operator!=(const Key& rhs) const { return !(rhs == *this); }
1316
    };
1317
1318
    struct Entry
1319
    {
1320
        const Key            key;
1321
        const jsbytecode*    pc;
1322
        HeapPtr<SavedFrame*> savedFrame;
1323
1324
        Entry(const Key& key, const jsbytecode* pc, SavedFrame* savedFrame)
1325
          : key(key)
1326
          , pc(pc)
1327
          , savedFrame(savedFrame)
1328
0
        { }
1329
    };
1330
1331
    using EntryVector = Vector<Entry, 0, SystemAllocPolicy>;
1332
    EntryVector* frames;
1333
1334
    LiveSavedFrameCache(const LiveSavedFrameCache&) = delete;
1335
    LiveSavedFrameCache& operator=(const LiveSavedFrameCache&) = delete;
1336
1337
  public:
1338
1.62M
    explicit LiveSavedFrameCache() : frames(nullptr) { }
1339
1340
    LiveSavedFrameCache(LiveSavedFrameCache&& rhs)
1341
        : frames(rhs.frames)
1342
1.62M
    {
1343
1.62M
        MOZ_ASSERT(this != &rhs, "self-move disallowed");
1344
1.62M
        rhs.frames = nullptr;
1345
1.62M
    }
1346
1347
3.24M
    ~LiveSavedFrameCache() {
1348
3.24M
        if (frames) {
1349
0
            js_delete(frames);
1350
0
            frames = nullptr;
1351
0
        }
1352
3.24M
    }
1353
1354
14
    bool initialized() const { return !!frames; }
1355
0
    bool init(JSContext* cx) {
1356
0
        frames = js_new<EntryVector>();
1357
0
        if (!frames) {
1358
0
            JS_ReportOutOfMemory(cx);
1359
0
            return false;
1360
0
        }
1361
0
        return true;
1362
0
    }
1363
1364
    void trace(JSTracer* trc);
1365
1366
    // Set |frame| to the cached SavedFrame corresponding to |framePtr| at |pc|.
1367
    // |framePtr|'s hasCachedSavedFrame bit must be set. Remove all cache
1368
    // entries for frames younger than that one.
1369
    //
1370
    // This may set |frame| to nullptr if |pc| is different from the pc supplied
1371
    // when the cache entry was inserted. In this case, the cached SavedFrame
1372
    // (probably) has the wrong source position. Entries for younger frames are
1373
    // still removed. The next frame, if any, will be a cache hit.
1374
    //
1375
    // This may also set |frame| to nullptr if the cache was populated with
1376
    // SavedFrame objects for a different compartment than cx's current
1377
    // compartment. In this case, the entire cache is flushed.
1378
    void find(JSContext* cx, FramePtr& framePtr, const jsbytecode* pc,
1379
              MutableHandleSavedFrame frame) const;
1380
1381
    // Search the cache for a frame matching |framePtr|, without removing any
1382
    // entries. Return the matching saved frame, or nullptr if none is found.
1383
    // This is used for resolving |evalInFramePrev| links.
1384
    void findWithoutInvalidation(const FramePtr& framePtr, MutableHandleSavedFrame frame) const;
1385
1386
    // Push a cache entry mapping |framePtr| and |pc| to |savedFrame| on the top
1387
    // of the cache's stack. You must insert entries for frames from oldest to
1388
    // youngest. They must all be younger than the frame that the |find| method
1389
    // found a hit for; or you must have cleared the entire cache with the
1390
    // |clear| method.
1391
    bool insert(JSContext* cx, FramePtr& framePtr, const jsbytecode* pc,
1392
                HandleSavedFrame savedFrame);
1393
1394
    // Remove all entries from the cache.
1395
0
    void clear() { if (frames) frames->clear(); }
1396
};
1397
1398
static_assert(sizeof(LiveSavedFrameCache) == sizeof(uintptr_t),
1399
              "Every js::Activation has a LiveSavedFrameCache, so we need to be pretty careful "
1400
              "about avoiding bloat. If you're adding members to LiveSavedFrameCache, maybe you "
1401
              "should consider figuring out a way to make js::Activation have a "
1402
              "LiveSavedFrameCache* instead of a Rooted<LiveSavedFrameCache>.");
1403
1404
/*****************************************************************************/
1405
1406
class InterpreterActivation;
1407
1408
namespace jit {
1409
    class JitActivation;
1410
} // namespace jit
1411
1412
// This class is separate from Activation, because it calls Compartment::wrap()
1413
// which can GC and walk the stack. It's not safe to do that within the
1414
// JitActivation constructor.
1415
class MOZ_RAII ActivationEntryMonitor
1416
{
1417
    JSContext* cx_;
1418
1419
    // The entry point monitor that was set on cx_->runtime() when this
1420
    // ActivationEntryMonitor was created.
1421
    JS::dbg::AutoEntryMonitor* entryMonitor_;
1422
1423
    explicit ActivationEntryMonitor(JSContext* cx);
1424
1425
    ActivationEntryMonitor(const ActivationEntryMonitor& other) = delete;
1426
    void operator=(const ActivationEntryMonitor& other) = delete;
1427
1428
    Value asyncStack(JSContext* cx);
1429
1430
  public:
1431
    ActivationEntryMonitor(JSContext* cx, InterpreterFrame* entryFrame);
1432
    ActivationEntryMonitor(JSContext* cx, jit::CalleeToken entryToken);
1433
    inline ~ActivationEntryMonitor();
1434
};
1435
1436
class Activation
1437
{
1438
  protected:
1439
    JSContext* cx_;
1440
    JS::Compartment* compartment_;
1441
    Activation* prev_;
1442
    Activation* prevProfiling_;
1443
1444
    // Counter incremented by JS::HideScriptedCaller and decremented by
1445
    // JS::UnhideScriptedCaller. If > 0 for the top activation,
1446
    // DescribeScriptedCaller will return null instead of querying that
1447
    // activation, which should prompt the caller to consult embedding-specific
1448
    // data structures instead.
1449
    size_t hideScriptedCallerCount_;
1450
1451
    // The cache of SavedFrame objects we have already captured when walking
1452
    // this activation's stack.
1453
    Rooted<LiveSavedFrameCache> frameCache_;
1454
1455
    // Youngest saved frame of an async stack that will be iterated during stack
1456
    // capture in place of the actual stack of previous activations. Note that
1457
    // the stack of this activation is captured entirely before this is used.
1458
    //
1459
    // Usually this is nullptr, meaning that normal stack capture will occur.
1460
    // When this is set, the stack of any previous activation is ignored.
1461
    Rooted<SavedFrame*> asyncStack_;
1462
1463
    // Value of asyncCause to be attached to asyncStack_.
1464
    const char* asyncCause_;
1465
1466
    // True if the async call was explicitly requested, e.g. via
1467
    // callFunctionWithAsyncStack.
1468
    bool asyncCallIsExplicit_;
1469
1470
    enum Kind { Interpreter, Jit };
1471
    Kind kind_;
1472
1473
    inline Activation(JSContext* cx, Kind kind);
1474
    inline ~Activation();
1475
1476
  public:
1477
0
    JSContext* cx() const {
1478
0
        return cx_;
1479
0
    }
1480
34
    JS::Compartment* compartment() const {
1481
34
        return compartment_;
1482
34
    }
1483
66
    Activation* prev() const {
1484
66
        return prev_;
1485
66
    }
1486
0
    Activation* prevProfiling() const { return prevProfiling_; }
1487
    inline Activation* mostRecentProfiling();
1488
1489
78
    bool isInterpreter() const {
1490
78
        return kind_ == Interpreter;
1491
78
    }
1492
68
    bool isJit() const {
1493
68
        return kind_ == Jit;
1494
68
    }
1495
    inline bool hasWasmExitFP() const;
1496
1497
    inline bool isProfiling() const;
1498
    void registerProfiling();
1499
    void unregisterProfiling();
1500
1501
78
    InterpreterActivation* asInterpreter() const {
1502
78
        MOZ_ASSERT(isInterpreter());
1503
78
        return (InterpreterActivation*)this;
1504
78
    }
1505
93
    jit::JitActivation* asJit() const {
1506
93
        MOZ_ASSERT(isJit());
1507
93
        return (jit::JitActivation*)this;
1508
93
    }
1509
1510
4
    void hideScriptedCaller() {
1511
4
        hideScriptedCallerCount_++;
1512
4
    }
1513
4
    void unhideScriptedCaller() {
1514
4
        MOZ_ASSERT(hideScriptedCallerCount_ > 0);
1515
4
        hideScriptedCallerCount_--;
1516
4
    }
1517
0
    bool scriptedCallerIsHidden() const {
1518
0
        return hideScriptedCallerCount_ > 0;
1519
0
    }
1520
1521
0
    static size_t offsetOfPrev() {
1522
0
        return offsetof(Activation, prev_);
1523
0
    }
1524
0
    static size_t offsetOfPrevProfiling() {
1525
0
        return offsetof(Activation, prevProfiling_);
1526
0
    }
1527
1528
0
    SavedFrame* asyncStack() {
1529
0
        return asyncStack_;
1530
0
    }
1531
1532
0
    const char* asyncCause() const {
1533
0
        return asyncCause_;
1534
0
    }
1535
1536
0
    bool asyncCallIsExplicit() const {
1537
0
        return asyncCallIsExplicit_;
1538
0
    }
1539
1540
    inline LiveSavedFrameCache* getLiveSavedFrameCache(JSContext* cx);
1541
0
    void clearLiveSavedFrameCache() { frameCache_.get().clear(); }
1542
1543
  private:
1544
    Activation(const Activation& other) = delete;
1545
    void operator=(const Activation& other) = delete;
1546
};
1547
1548
// This variable holds a special opcode value which is greater than all normal
1549
// opcodes, and is chosen such that the bitwise or of this value with any
1550
// opcode is this value.
1551
static const jsbytecode EnableInterruptsPseudoOpcode = -1;
1552
1553
static_assert(EnableInterruptsPseudoOpcode >= JSOP_LIMIT,
1554
              "EnableInterruptsPseudoOpcode must be greater than any opcode");
1555
static_assert(EnableInterruptsPseudoOpcode == jsbytecode(-1),
1556
              "EnableInterruptsPseudoOpcode must be the maximum jsbytecode value");
1557
1558
class InterpreterFrameIterator;
1559
class RunState;
1560
1561
class InterpreterActivation : public Activation
1562
{
1563
    friend class js::InterpreterFrameIterator;
1564
1565
    InterpreterRegs regs_;
1566
    InterpreterFrame* entryFrame_;
1567
    size_t opMask_; // For debugger interrupts, see js::Interpret.
1568
1569
#ifdef DEBUG
1570
    size_t oldFrameCount_;
1571
#endif
1572
1573
  public:
1574
    inline InterpreterActivation(RunState& state, JSContext* cx, InterpreterFrame* entryFrame);
1575
    inline ~InterpreterActivation();
1576
1577
    inline bool pushInlineFrame(const CallArgs& args, HandleScript script,
1578
                                MaybeConstruct constructing);
1579
    inline void popInlineFrame(InterpreterFrame* frame);
1580
1581
    inline bool resumeGeneratorFrame(HandleFunction callee, HandleObject envChain);
1582
1583
20
    InterpreterFrame* current() const {
1584
20
        return regs_.fp();
1585
20
    }
1586
57.7k
    InterpreterRegs& regs() {
1587
57.7k
        return regs_;
1588
57.7k
    }
1589
338
    InterpreterFrame* entryFrame() const {
1590
338
        return entryFrame_;
1591
338
    }
1592
10.6k
    size_t opMask() const {
1593
10.6k
        return opMask_;
1594
10.6k
    }
1595
1596
27
    bool isProfiling() const {
1597
27
        return false;
1598
27
    }
1599
1600
    // If this js::Interpret frame is running |script|, enable interrupts.
1601
18
    void enableInterruptsIfRunning(JSScript* script) {
1602
18
        if (regs_.fp()->script() == script) {
1603
1
            enableInterruptsUnconditionally();
1604
1
        }
1605
18
    }
1606
41
    void enableInterruptsUnconditionally() {
1607
41
        opMask_ = EnableInterruptsPseudoOpcode;
1608
41
    }
1609
41
    void clearInterruptsMask() {
1610
41
        opMask_ = 0;
1611
41
    }
1612
};
1613
1614
// Iterates over a thread's activation list.
1615
class ActivationIterator
1616
{
1617
  protected:
1618
    Activation* activation_;
1619
1620
  public:
1621
    explicit ActivationIterator(JSContext* cx);
1622
1623
    ActivationIterator& operator++();
1624
1625
108
    Activation* operator->() const {
1626
108
        return activation_;
1627
108
    }
1628
22
    Activation* activation() const {
1629
22
        return activation_;
1630
22
    }
1631
253
    bool done() const {
1632
253
        return activation_ == nullptr;
1633
253
    }
1634
};
1635
1636
namespace jit {
1637
1638
class BailoutFrameInfo;
1639
1640
// A JitActivation is used for frames running in Baseline or Ion.
1641
class JitActivation : public Activation
1642
{
1643
    // If Baseline, Ion or Wasm code is on the stack, and has called into C++,
1644
    // this will be aligned to an ExitFrame. The last bit indicates if it's a
1645
    // wasm frame (bit set to wasm::ExitOrJitEntryFPTag) or not
1646
    // (bit set to ~wasm::ExitOrJitEntryFPTag).
1647
    uint8_t* packedExitFP_;
1648
1649
    // When hasWasmExitFP(), encodedWasmExitReason_ holds ExitReason.
1650
    uint32_t encodedWasmExitReason_;
1651
1652
    JitActivation* prevJitActivation_;
1653
1654
    // Rematerialized Ion frames which has info copied out of snapshots. Maps
1655
    // frame pointers (i.e. packedExitFP_) to a vector of rematerializations of all
1656
    // inline frames associated with that frame.
1657
    //
1658
    // This table is lazily initialized by calling getRematerializedFrame.
1659
    typedef GCVector<RematerializedFrame*> RematerializedFrameVector;
1660
    typedef HashMap<uint8_t*, RematerializedFrameVector> RematerializedFrameTable;
1661
    js::UniquePtr<RematerializedFrameTable> rematerializedFrames_;
1662
1663
    // This vector is used to remember the outcome of the evaluation of recover
1664
    // instructions.
1665
    //
1666
    // RInstructionResults are appended into this vector when Snapshot values
1667
    // have to be read, or when the evaluation has to run before some mutating
1668
    // code.  Each RInstructionResults belongs to one frame which has to bailout
1669
    // as soon as we get back to it.
1670
    typedef Vector<RInstructionResults, 1> IonRecoveryMap;
1671
    IonRecoveryMap ionRecovery_;
1672
1673
    // If we are bailing out from Ion, then this field should be a non-null
1674
    // pointer which references the BailoutFrameInfo used to walk the inner
1675
    // frames. This field is used for all newly constructed JSJitFrameIters to
1676
    // read the innermost frame information from this bailout data instead of
1677
    // reading it from the stack.
1678
    BailoutFrameInfo* bailoutData_;
1679
1680
    // When profiling is enabled, these fields will be updated to reflect the
1681
    // last pushed frame for this activation, and if that frame has been
1682
    // left for a call, the native code site of the call.
1683
    mozilla::Atomic<void*, mozilla::Relaxed> lastProfilingFrame_;
1684
    mozilla::Atomic<void*, mozilla::Relaxed> lastProfilingCallSite_;
1685
    static_assert(sizeof(mozilla::Atomic<void*, mozilla::Relaxed>) == sizeof(void*),
1686
                  "Atomic should have same memory format as underlying type.");
1687
1688
    // When wasm traps, the signal handler records some data for unwinding
1689
    // purposes. Wasm code can't trap reentrantly.
1690
    mozilla::Maybe<wasm::TrapData> wasmTrapData_;
1691
1692
    void clearRematerializedFrames();
1693
1694
#ifdef CHECK_OSIPOINT_REGISTERS
1695
  protected:
1696
    // Used to verify that live registers don't change between a VM call and
1697
    // the OsiPoint that follows it. Protected to silence Clang warning.
1698
    uint32_t checkRegs_ = 0;
1699
    RegisterDump regs_;
1700
#endif
1701
1702
  public:
1703
    explicit JitActivation(JSContext* cx);
1704
    ~JitActivation();
1705
1706
1.62M
    bool isProfiling() const {
1707
1.62M
        // All JitActivations can be profiled.
1708
1.62M
        return true;
1709
1.62M
    }
1710
1711
0
    JitActivation* prevJitActivation() const {
1712
0
        return prevJitActivation_;
1713
0
    }
1714
0
    static size_t offsetOfPrevJitActivation() {
1715
0
        return offsetof(JitActivation, prevJitActivation_);
1716
0
    }
1717
1718
0
    bool hasExitFP() const {
1719
0
        return !!packedExitFP_;
1720
0
    }
1721
0
    uint8_t* jsOrWasmExitFP() const {
1722
0
        return (uint8_t*)(uintptr_t(packedExitFP_) & ~wasm::ExitOrJitEntryFPTag);
1723
0
    }
1724
720
    static size_t offsetOfPackedExitFP() {
1725
720
        return offsetof(JitActivation, packedExitFP_);
1726
720
    }
1727
1728
26
    bool hasJSExitFP() const {
1729
26
        return !(uintptr_t(packedExitFP_) & wasm::ExitOrJitEntryFPTag);
1730
26
    }
1731
50
    uint8_t* jsExitFP() const {
1732
50
        MOZ_ASSERT(hasJSExitFP());
1733
50
        return packedExitFP_;
1734
50
    }
1735
8
    void setJSExitFP(uint8_t* fp) {
1736
8
        packedExitFP_ = fp;
1737
8
    }
1738
1739
#ifdef CHECK_OSIPOINT_REGISTERS
1740
    void setCheckRegs(bool check) {
1741
        checkRegs_ = check;
1742
    }
1743
    static size_t offsetOfCheckRegs() {
1744
        return offsetof(JitActivation, checkRegs_);
1745
    }
1746
    static size_t offsetOfRegs() {
1747
        return offsetof(JitActivation, regs_);
1748
    }
1749
#endif
1750
1751
    // Look up a rematerialized frame keyed by the fp, rematerializing the
1752
    // frame if one doesn't already exist. A frame can only be rematerialized
1753
    // if an IonFrameIterator pointing to the nearest uninlined frame can be
1754
    // provided, as values need to be read out of snapshots.
1755
    //
1756
    // The inlineDepth must be within bounds of the frame pointed to by iter.
1757
    RematerializedFrame* getRematerializedFrame(JSContext* cx, const JSJitFrameIter& iter,
1758
                                                size_t inlineDepth = 0);
1759
1760
    // Look up a rematerialized frame by the fp. If inlineDepth is out of
1761
    // bounds of what has been rematerialized, nullptr is returned.
1762
    RematerializedFrame* lookupRematerializedFrame(uint8_t* top, size_t inlineDepth = 0);
1763
1764
    // Remove all rematerialized frames associated with the fp top from the
1765
    // Debugger.
1766
    void removeRematerializedFramesFromDebugger(JSContext* cx, uint8_t* top);
1767
1768
8
    bool hasRematerializedFrame(uint8_t* top, size_t inlineDepth = 0) {
1769
8
        return !!lookupRematerializedFrame(top, inlineDepth);
1770
8
    }
1771
1772
    // Remove a previous rematerialization by fp.
1773
    void removeRematerializedFrame(uint8_t* top);
1774
1775
    void traceRematerializedFrames(JSTracer* trc);
1776
1777
    // Register the results of on Ion frame recovery.
1778
    bool registerIonFrameRecovery(RInstructionResults&& results);
1779
1780
    // Return the pointer to the Ion frame recovery, if it is already registered.
1781
    RInstructionResults* maybeIonFrameRecovery(JitFrameLayout* fp);
1782
1783
    // If an Ion frame recovery exists for the |fp| frame exists, then remove it
1784
    // from the activation.
1785
    void removeIonFrameRecovery(JitFrameLayout* fp);
1786
1787
    void traceIonRecovery(JSTracer* trc);
1788
1789
    // Return the bailout information if it is registered.
1790
162
    const BailoutFrameInfo* bailoutData() const { return bailoutData_; }
1791
1792
    // Register the bailout data when it is constructed.
1793
    void setBailoutData(BailoutFrameInfo* bailoutData);
1794
1795
    // Unregister the bailout data when the frame is reconstructed.
1796
    void cleanBailoutData();
1797
1798
20
    static size_t offsetOfLastProfilingFrame() {
1799
20
        return offsetof(JitActivation, lastProfilingFrame_);
1800
20
    }
1801
0
    void* lastProfilingFrame() {
1802
0
        return lastProfilingFrame_;
1803
0
    }
1804
0
    void setLastProfilingFrame(void* ptr) {
1805
0
        lastProfilingFrame_ = ptr;
1806
0
    }
1807
1808
20
    static size_t offsetOfLastProfilingCallSite() {
1809
20
        return offsetof(JitActivation, lastProfilingCallSite_);
1810
20
    }
1811
0
    void* lastProfilingCallSite() {
1812
0
        return lastProfilingCallSite_;
1813
0
    }
1814
0
    void setLastProfilingCallSite(void* ptr) {
1815
0
        lastProfilingCallSite_ = ptr;
1816
0
    }
1817
1818
    // WebAssembly specific attributes.
1819
0
    bool hasWasmExitFP() const {
1820
0
        return uintptr_t(packedExitFP_) & wasm::ExitOrJitEntryFPTag;
1821
0
    }
1822
0
    wasm::Frame* wasmExitFP() const {
1823
0
        MOZ_ASSERT(hasWasmExitFP());
1824
0
        return (wasm::Frame*)(uintptr_t(packedExitFP_) & ~wasm::ExitOrJitEntryFPTag);
1825
0
    }
1826
0
    void setWasmExitFP(const wasm::Frame* fp) {
1827
0
        if (fp) {
1828
0
            MOZ_ASSERT(!(uintptr_t(fp) & wasm::ExitOrJitEntryFPTag));
1829
0
            packedExitFP_ = (uint8_t*)(uintptr_t(fp) | wasm::ExitOrJitEntryFPTag);
1830
0
            MOZ_ASSERT(hasWasmExitFP());
1831
0
        } else {
1832
0
            packedExitFP_ = nullptr;
1833
0
        }
1834
0
    }
1835
0
    wasm::ExitReason wasmExitReason() const {
1836
0
        MOZ_ASSERT(hasWasmExitFP());
1837
0
        return wasm::ExitReason::Decode(encodedWasmExitReason_);
1838
0
    }
1839
0
    static size_t offsetOfEncodedWasmExitReason() {
1840
0
        return offsetof(JitActivation, encodedWasmExitReason_);
1841
0
    }
1842
1843
    void startWasmTrap(wasm::Trap trap, uint32_t bytecodeOffset, const wasm::RegisterState& state);
1844
    void finishWasmTrap();
1845
0
    bool isWasmTrapping() const { return !!wasmTrapData_; }
1846
0
    const wasm::TrapData& wasmTrapData() { return *wasmTrapData_; }
1847
};
1848
1849
// A filtering of the ActivationIterator to only stop at JitActivations.
1850
class JitActivationIterator : public ActivationIterator
1851
{
1852
92
    void settle() {
1853
92
        while (!done() && !activation_->isJit()) {
1854
0
            ActivationIterator::operator++();
1855
0
        }
1856
92
    }
1857
1858
  public:
1859
    explicit JitActivationIterator(JSContext* cx)
1860
      : ActivationIterator(cx)
1861
66
    {
1862
66
        settle();
1863
66
    }
1864
1865
26
    JitActivationIterator& operator++() {
1866
26
        ActivationIterator::operator++();
1867
26
        settle();
1868
26
        return *this;
1869
26
    }
1870
};
1871
1872
} // namespace jit
1873
1874
inline bool
1875
Activation::hasWasmExitFP() const
1876
0
{
1877
0
    return isJit() && asJit()->hasWasmExitFP();
1878
0
}
1879
1880
// Iterates over the frames of a single InterpreterActivation.
1881
class InterpreterFrameIterator
1882
{
1883
    InterpreterActivation* activation_;
1884
    InterpreterFrame* fp_;
1885
    jsbytecode* pc_;
1886
    Value* sp_;
1887
1888
  public:
1889
    explicit InterpreterFrameIterator(InterpreterActivation* activation)
1890
      : activation_(activation),
1891
        fp_(nullptr),
1892
        pc_(nullptr),
1893
        sp_(nullptr)
1894
16
    {
1895
16
        if (activation) {
1896
8
            fp_ = activation->current();
1897
8
            pc_ = activation->regs().pc;
1898
8
            sp_ = activation->regs().sp;
1899
8
        }
1900
16
    }
1901
1902
16
    InterpreterFrame* frame() const {
1903
16
        MOZ_ASSERT(!done());
1904
16
        return fp_;
1905
16
    }
1906
8
    jsbytecode* pc() const {
1907
8
        MOZ_ASSERT(!done());
1908
8
        return pc_;
1909
8
    }
1910
0
    Value* sp() const {
1911
0
        MOZ_ASSERT(!done());
1912
0
        return sp_;
1913
0
    }
1914
1915
    InterpreterFrameIterator& operator++();
1916
1917
0
    bool done() const {
1918
0
        return fp_ == nullptr;
1919
0
    }
1920
};
1921
1922
// A JitFrameIter can iterate over all kind of frames emitted by our code
1923
// generators, be they composed of JS jit frames or wasm frames, interleaved or
1924
// not, in any order.
1925
//
1926
// In the following class:
1927
// - code generated for JS is referred to as JSJit.
1928
// - code generated for wasm is referred to as Wasm.
1929
// Also, Jit refers to any one of them.
1930
//
1931
// JitFrameIter uses JSJitFrameIter to iterate over JSJit code or a
1932
// WasmFrameIter to iterate over wasm code; only one of them is active at the
1933
// time. When a sub-iterator is done, the JitFrameIter knows how to stop, move
1934
// onto the next activation or move onto another kind of Jit code.
1935
//
1936
// For ease of use, there is also OnlyJSJitFrameIter, which skips all the
1937
// non-JSJit frames.
1938
//
1939
// Note it is allowed to get a handle to the internal frame iterator via
1940
// asJSJit() and asWasm(), but the user has to be careful not to have those be
1941
// used after JitFrameIter leaves the scope or the operator++ is called.
1942
//
1943
// In particular, this can handle the transition from wasm to jit and from jit
1944
// to wasm, since these can be interleaved in the same JitActivation.
1945
class JitFrameIter
1946
{
1947
  protected:
1948
    jit::JitActivation* act_;
1949
    mozilla::MaybeOneOf<jit::JSJitFrameIter, wasm::WasmFrameIter> iter_;
1950
    bool mustUnwindActivation_;
1951
1952
    void settle();
1953
1954
  public:
1955
8
    JitFrameIter() : act_(nullptr), iter_(), mustUnwindActivation_(false) {}
1956
    explicit JitFrameIter(jit::JitActivation* activation, bool mustUnwindActivation = false);
1957
1958
    explicit JitFrameIter(const JitFrameIter& another);
1959
    JitFrameIter& operator=(const JitFrameIter& another);
1960
1961
410
    bool isSome() const { return !iter_.empty(); }
1962
0
    void reset() { MOZ_ASSERT(isSome()); iter_.destroy(); }
1963
1964
296
    bool isJSJit() const { return isSome() && iter_.constructed<jit::JSJitFrameIter>(); }
1965
210
    jit::JSJitFrameIter& asJSJit() { return iter_.ref<jit::JSJitFrameIter>(); }
1966
138
    const jit::JSJitFrameIter& asJSJit() const { return iter_.ref<jit::JSJitFrameIter>(); }
1967
1968
0
    bool isWasm() const { return isSome() && iter_.constructed<wasm::WasmFrameIter>(); }
1969
0
    wasm::WasmFrameIter& asWasm() { return iter_.ref<wasm::WasmFrameIter>(); }
1970
0
    const wasm::WasmFrameIter& asWasm() const { return iter_.ref<wasm::WasmFrameIter>(); }
1971
1972
    // Operations common to all frame iterators.
1973
0
    const jit::JitActivation* activation() const { return act_; }
1974
    bool done() const;
1975
    void operator++();
1976
1977
    JS::Realm* realm() const;
1978
1979
    // Operations which have an effect only on JIT frames.
1980
    void skipNonScriptedJSFrames();
1981
1982
    // Returns true iff this is a JIT frame with a self-hosted script. Note: be
1983
    // careful, JitFrameIter does not consider functions inlined by Ion.
1984
    bool isSelfHostedIgnoringInlining() const;
1985
};
1986
1987
// A JitFrameIter that skips all the non-JSJit frames, skipping interleaved
1988
// frames of any another kind.
1989
1990
class OnlyJSJitFrameIter : public JitFrameIter
1991
{
1992
36
    void settle() {
1993
36
        while (!done() && !isJSJit()) {
1994
0
            JitFrameIter::operator++();
1995
0
        }
1996
36
    }
1997
1998
  public:
1999
    explicit OnlyJSJitFrameIter(jit::JitActivation* act);
2000
    explicit OnlyJSJitFrameIter(JSContext* cx);
2001
    explicit OnlyJSJitFrameIter(const ActivationIterator& cx);
2002
2003
24
    void operator++() {
2004
24
        JitFrameIter::operator++();
2005
24
        settle();
2006
24
    }
2007
2008
24
    const jit::JSJitFrameIter& frame() const {
2009
24
        return asJSJit();
2010
24
    }
2011
};
2012
2013
// A FrameIter walks over a context's stack of JS script activations,
2014
// abstracting over whether the JS scripts were running in the interpreter or
2015
// different modes of compiled code.
2016
//
2017
// FrameIter is parameterized by what it includes in the stack iteration:
2018
//  - When provided, the optional JSPrincipal argument will cause FrameIter to
2019
//    only show frames in globals whose JSPrincipals are subsumed (via
2020
//    JSSecurityCallbacks::subsume) by the given JSPrincipal.
2021
//
2022
// Additionally, there are derived FrameIter types that automatically skip
2023
// certain frames:
2024
//  - ScriptFrameIter only shows frames that have an associated JSScript
2025
//    (currently everything other than wasm stack frames). When !hasScript(),
2026
//    clients must stick to the portion of the
2027
//    interface marked below.
2028
//  - NonBuiltinScriptFrameIter additionally filters out builtin (self-hosted)
2029
//    scripts.
2030
class FrameIter
2031
{
2032
  public:
2033
    enum DebuggerEvalOption { FOLLOW_DEBUGGER_EVAL_PREV_LINK,
2034
                              IGNORE_DEBUGGER_EVAL_PREV_LINK };
2035
2036
    enum State {
2037
        DONE,      // when there are no more frames nor activations to unwind.
2038
        INTERP,    // interpreter activation on the stack
2039
        JIT        // jit or wasm activations on the stack
2040
    };
2041
2042
    // Unlike ScriptFrameIter itself, ScriptFrameIter::Data can be allocated on
2043
    // the heap, so this structure should not contain any GC things.
2044
    struct Data
2045
    {
2046
        JSContext* cx_;
2047
        DebuggerEvalOption  debuggerEvalOption_;
2048
        JSPrincipals*       principals_;
2049
2050
        State               state_;
2051
2052
        jsbytecode*         pc_;
2053
2054
        InterpreterFrameIterator interpFrames_;
2055
        ActivationIterator activations_;
2056
2057
        JitFrameIter jitFrames_;
2058
        unsigned ionInlineFrameNo_;
2059
2060
        Data(JSContext* cx, DebuggerEvalOption debuggerEvalOption, JSPrincipals* principals);
2061
        Data(const Data& other);
2062
    };
2063
2064
    explicit FrameIter(JSContext* cx,
2065
                       DebuggerEvalOption = FOLLOW_DEBUGGER_EVAL_PREV_LINK);
2066
    FrameIter(JSContext* cx, DebuggerEvalOption, JSPrincipals*);
2067
    FrameIter(const FrameIter& iter);
2068
    MOZ_IMPLICIT FrameIter(const Data& data);
2069
    MOZ_IMPLICIT FrameIter(AbstractFramePtr frame);
2070
2071
8
    bool done() const { return data_.state_ == DONE; }
2072
2073
    // -------------------------------------------------------
2074
    // The following functions can only be called when !done()
2075
    // -------------------------------------------------------
2076
2077
    FrameIter& operator++();
2078
2079
    JS::Realm* realm() const;
2080
    JS::Compartment* compartment() const;
2081
0
    Activation* activation() const { return data_.activations_.activation(); }
2082
2083
0
    bool isInterp() const {
2084
0
        MOZ_ASSERT(!done());
2085
0
        return data_.state_ == INTERP;
2086
0
    }
2087
0
    bool isJSJit() const {
2088
0
        MOZ_ASSERT(!done());
2089
0
        return data_.state_ == JIT && data_.jitFrames_.isJSJit();
2090
0
    }
2091
8
    bool isWasm() const {
2092
8
        MOZ_ASSERT(!done());
2093
8
        return data_.state_ == JIT && data_.jitFrames_.isWasm();
2094
8
    }
2095
2096
    inline bool isIon() const;
2097
    inline bool isBaseline() const;
2098
    inline bool isPhysicalJitFrame() const;
2099
2100
    bool isEvalFrame() const;
2101
    bool isFunctionFrame() const;
2102
0
    bool hasArgs() const { return isFunctionFrame(); }
2103
2104
    ScriptSource* scriptSource() const;
2105
    const char* filename() const;
2106
    const char16_t* displayURL() const;
2107
    unsigned computeLine(uint32_t* column = nullptr) const;
2108
    JSAtom* maybeFunctionDisplayAtom() const;
2109
    bool mutedErrors() const;
2110
2111
0
    bool hasScript() const { return !isWasm(); }
2112
2113
    // -----------------------------------------------------------
2114
    //  The following functions can only be called when isWasm()
2115
    // -----------------------------------------------------------
2116
2117
    inline bool wasmDebugEnabled() const;
2118
    inline wasm::Instance* wasmInstance() const;
2119
    inline uint32_t wasmFuncIndex() const;
2120
    inline unsigned wasmBytecodeOffset() const;
2121
    void wasmUpdateBytecodeOffset();
2122
2123
    // -----------------------------------------------------------
2124
    // The following functions can only be called when hasScript()
2125
    // -----------------------------------------------------------
2126
2127
    inline JSScript* script() const;
2128
2129
    bool        isConstructing() const;
2130
0
    jsbytecode* pc() const { MOZ_ASSERT(!done()); return data_.pc_; }
2131
    void        updatePcQuadratic();
2132
2133
    // The function |calleeTemplate()| returns either the function from which
2134
    // the current |callee| was cloned or the |callee| if it can be read. As
2135
    // long as we do not have to investigate the environment chain or build a
2136
    // new frame, we should prefer to use |calleeTemplate| instead of
2137
    // |callee|, as requesting the |callee| might cause the invalidation of
2138
    // the frame. (see js::Lambda)
2139
    JSFunction* calleeTemplate() const;
2140
    JSFunction* callee(JSContext* cx) const;
2141
2142
0
    JSFunction* maybeCallee(JSContext* cx) const {
2143
0
        return isFunctionFrame() ? callee(cx) : nullptr;
2144
0
    }
2145
2146
    bool        matchCallee(JSContext* cx, HandleFunction fun) const;
2147
2148
    unsigned    numActualArgs() const;
2149
    unsigned    numFormalArgs() const;
2150
    Value       unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const;
2151
    template <class Op> inline void unaliasedForEachActual(JSContext* cx, Op op);
2152
2153
    JSObject*  environmentChain(JSContext* cx) const;
2154
    CallObject& callObj(JSContext* cx) const;
2155
2156
    bool        hasArgsObj() const;
2157
    ArgumentsObject& argsObj() const;
2158
2159
    // Get the original |this| value passed to this function. May not be the
2160
    // actual this-binding (for instance, derived class constructors will
2161
    // change their this-value later and non-strict functions will box
2162
    // primitives).
2163
    Value       thisArgument(JSContext* cx) const;
2164
2165
    Value       newTarget() const;
2166
2167
    Value       returnValue() const;
2168
    void        setReturnValue(const Value& v);
2169
2170
    // These are only valid for the top frame.
2171
    size_t      numFrameSlots() const;
2172
    Value       frameSlotValue(size_t index) const;
2173
2174
    // Ensures that we have rematerialized the top frame and its associated
2175
    // inline frames. Can only be called when isIon().
2176
    bool ensureHasRematerializedFrame(JSContext* cx);
2177
2178
    // True when isInterp() or isBaseline(). True when isIon() if it
2179
    // has a rematerialized frame. False otherwise.
2180
    bool hasUsableAbstractFramePtr() const;
2181
2182
    // -----------------------------------------------------------
2183
    // The following functions can only be called when isInterp(),
2184
    // isBaseline(), isWasm() or isIon(). Further, abstractFramePtr() can
2185
    // only be called when hasUsableAbstractFramePtr().
2186
    // -----------------------------------------------------------
2187
2188
    AbstractFramePtr abstractFramePtr() const;
2189
    Data* copyData() const;
2190
2191
    // This can only be called when isInterp():
2192
    inline InterpreterFrame* interpFrame() const;
2193
2194
    // This can only be called when isPhysicalJitFrame():
2195
    inline jit::CommonFrameLayout* physicalJitFrame() const;
2196
2197
    // This is used to provide a raw interface for debugging.
2198
    void* rawFramePtr() const;
2199
2200
  private:
2201
    Data data_;
2202
    jit::InlineFrameIterator ionInlineFrames_;
2203
2204
0
    const jit::JSJitFrameIter& jsJitFrame() const { return data_.jitFrames_.asJSJit(); }
2205
0
    const wasm::WasmFrameIter& wasmFrame() const { return data_.jitFrames_.asWasm(); }
2206
2207
0
    jit::JSJitFrameIter& jsJitFrame() { return data_.jitFrames_.asJSJit(); }
2208
0
    wasm::WasmFrameIter& wasmFrame() { return data_.jitFrames_.asWasm(); }
2209
2210
0
    bool isIonScripted() const { return isJSJit() && jsJitFrame().isIonScripted(); }
2211
2212
    bool principalsSubsumeFrame() const;
2213
2214
    void popActivation();
2215
    void popInterpreterFrame();
2216
    void nextJitFrame();
2217
    void popJitFrame();
2218
    void settleOnActivation();
2219
};
2220
2221
class ScriptFrameIter : public FrameIter
2222
{
2223
0
    void settle() {
2224
0
        while (!done() && !hasScript()) {
2225
0
            FrameIter::operator++();
2226
0
        }
2227
0
    }
2228
2229
  public:
2230
    explicit ScriptFrameIter(JSContext* cx,
2231
                             DebuggerEvalOption debuggerEvalOption = FOLLOW_DEBUGGER_EVAL_PREV_LINK)
2232
      : FrameIter(cx, debuggerEvalOption)
2233
0
    {
2234
0
        settle();
2235
0
    }
2236
2237
    ScriptFrameIter(JSContext* cx,
2238
                    DebuggerEvalOption debuggerEvalOption,
2239
                    JSPrincipals* prin)
2240
      : FrameIter(cx, debuggerEvalOption, prin)
2241
0
    {
2242
0
        settle();
2243
0
    }
2244
2245
0
    ScriptFrameIter(const ScriptFrameIter& iter) : FrameIter(iter) { settle(); }
2246
0
    explicit ScriptFrameIter(const FrameIter::Data& data) : FrameIter(data) { settle(); }
2247
0
    explicit ScriptFrameIter(AbstractFramePtr frame) : FrameIter(frame) { settle(); }
2248
2249
0
    ScriptFrameIter& operator++() {
2250
0
        FrameIter::operator++();
2251
0
        settle();
2252
0
        return *this;
2253
0
    }
2254
};
2255
2256
#ifdef DEBUG
2257
bool SelfHostedFramesVisible();
2258
#else
2259
static inline bool
2260
SelfHostedFramesVisible()
2261
0
{
2262
0
    return false;
2263
0
}
Unexecuted instantiation: CTypes.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: StoreBuffer.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: jsutil.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: StructuredClone.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src0.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src1.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src10.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src11.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src12.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src14.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src15.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src17.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src18.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src19.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src2.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src20.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src21.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src22.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src23.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src24.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src25.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src26.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src27.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src28.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src29.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src3.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src30.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src31.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src32.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src33.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src34.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src35.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src36.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src37.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src38.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src39.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src4.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src40.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src41.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src42.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src43.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src44.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src45.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src5.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src6.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src7.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src8.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src9.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: RegExp.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: BinSource-auto.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: BinSource.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: BinToken.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: BinTokenReaderBase.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: BinTokenReaderMultipart.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: BinTokenReaderTester.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Parser.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Disassembler-x86-shared.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: jsmath.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Interpreter.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: VTuneWrapper.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src13.cpp:js::SelfHostedFramesVisible()
Unexecuted instantiation: Unified_cpp_js_src16.cpp:js::SelfHostedFramesVisible()
2264
#endif
2265
2266
/* A filtering of the FrameIter to only stop at non-self-hosted scripts. */
2267
class NonBuiltinFrameIter : public FrameIter
2268
{
2269
    void settle();
2270
2271
  public:
2272
    explicit NonBuiltinFrameIter(JSContext* cx,
2273
                                 FrameIter::DebuggerEvalOption debuggerEvalOption =
2274
                                 FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK)
2275
      : FrameIter(cx, debuggerEvalOption)
2276
0
    {
2277
0
        settle();
2278
0
    }
2279
2280
    NonBuiltinFrameIter(JSContext* cx,
2281
                        FrameIter::DebuggerEvalOption debuggerEvalOption,
2282
                        JSPrincipals* principals)
2283
      : FrameIter(cx, debuggerEvalOption, principals)
2284
0
    {
2285
0
        settle();
2286
0
    }
2287
2288
    NonBuiltinFrameIter(JSContext* cx, JSPrincipals* principals)
2289
      : FrameIter(cx, FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK, principals)
2290
0
    {
2291
0
        settle();
2292
0
    }
2293
2294
    explicit NonBuiltinFrameIter(const FrameIter::Data& data)
2295
      : FrameIter(data)
2296
0
    {}
2297
2298
0
    NonBuiltinFrameIter& operator++() {
2299
0
        FrameIter::operator++();
2300
0
        settle();
2301
0
        return *this;
2302
0
    }
2303
};
2304
2305
/* A filtering of the ScriptFrameIter to only stop at non-self-hosted scripts. */
2306
class NonBuiltinScriptFrameIter : public ScriptFrameIter
2307
{
2308
    void settle();
2309
2310
  public:
2311
    explicit NonBuiltinScriptFrameIter(JSContext* cx,
2312
                                       ScriptFrameIter::DebuggerEvalOption debuggerEvalOption =
2313
                                       ScriptFrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK)
2314
      : ScriptFrameIter(cx, debuggerEvalOption)
2315
0
    {
2316
0
        settle();
2317
0
    }
2318
2319
    NonBuiltinScriptFrameIter(JSContext* cx,
2320
                              ScriptFrameIter::DebuggerEvalOption debuggerEvalOption,
2321
                              JSPrincipals* principals)
2322
      : ScriptFrameIter(cx, debuggerEvalOption, principals)
2323
0
    {
2324
0
        settle();
2325
0
    }
2326
2327
    explicit NonBuiltinScriptFrameIter(const ScriptFrameIter::Data& data)
2328
      : ScriptFrameIter(data)
2329
0
    {}
2330
2331
0
    NonBuiltinScriptFrameIter& operator++() {
2332
0
        ScriptFrameIter::operator++();
2333
0
        settle();
2334
0
        return *this;
2335
0
    }
2336
};
2337
2338
/*
2339
 * Blindly iterate over all frames in the current thread's stack. These frames
2340
 * can be from different contexts and compartments, so beware.
2341
 */
2342
class AllFramesIter : public FrameIter
2343
{
2344
  public:
2345
    explicit AllFramesIter(JSContext* cx)
2346
      : FrameIter(cx, ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK)
2347
0
    {}
2348
};
2349
2350
/* Iterates over all script frame in the current thread's stack.
2351
 * See also AllFramesIter and ScriptFrameIter.
2352
 */
2353
class AllScriptFramesIter : public ScriptFrameIter
2354
{
2355
  public:
2356
    explicit AllScriptFramesIter(JSContext* cx)
2357
      : ScriptFrameIter(cx, ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK)
2358
0
    {}
2359
};
2360
2361
/* Popular inline definitions. */
2362
2363
inline JSScript*
2364
FrameIter::script() const
2365
0
{
2366
0
    MOZ_ASSERT(!done());
2367
0
    MOZ_ASSERT(hasScript());
2368
0
    if (data_.state_ == INTERP) {
2369
0
        return interpFrame()->script();
2370
0
    }
2371
0
    if (jsJitFrame().isIonJS()) {
2372
0
        return ionInlineFrames_.script();
2373
0
    }
2374
0
    return jsJitFrame().script();
2375
0
}
2376
2377
inline bool
2378
FrameIter::wasmDebugEnabled() const
2379
0
{
2380
0
    MOZ_ASSERT(!done());
2381
0
    MOZ_ASSERT(isWasm());
2382
0
    return wasmFrame().debugEnabled();
2383
0
}
2384
2385
inline wasm::Instance*
2386
FrameIter::wasmInstance() const
2387
0
{
2388
0
    MOZ_ASSERT(!done());
2389
0
    MOZ_ASSERT(isWasm());
2390
0
    return wasmFrame().instance();
2391
0
}
2392
2393
inline unsigned
2394
FrameIter::wasmBytecodeOffset() const
2395
0
{
2396
0
    MOZ_ASSERT(!done());
2397
0
    MOZ_ASSERT(isWasm());
2398
0
    return wasmFrame().lineOrBytecode();
2399
0
}
2400
2401
inline uint32_t
2402
FrameIter::wasmFuncIndex() const
2403
0
{
2404
0
    MOZ_ASSERT(!done());
2405
0
    MOZ_ASSERT(isWasm());
2406
0
    return wasmFrame().funcIndex();
2407
0
}
2408
2409
inline bool
2410
FrameIter::isIon() const
2411
0
{
2412
0
    return isJSJit() && jsJitFrame().isIonJS();
2413
0
}
2414
2415
inline bool
2416
FrameIter::isBaseline() const
2417
0
{
2418
0
    return isJSJit() && jsJitFrame().isBaselineJS();
2419
0
}
2420
2421
inline InterpreterFrame*
2422
FrameIter::interpFrame() const
2423
8
{
2424
8
    MOZ_ASSERT(data_.state_ == INTERP);
2425
8
    return data_.interpFrames_.frame();
2426
8
}
2427
2428
inline bool
2429
FrameIter::isPhysicalJitFrame() const
2430
0
{
2431
0
    if (!isJSJit()) {
2432
0
        return false;
2433
0
    }
2434
0
2435
0
    auto& jitFrame = jsJitFrame();
2436
0
2437
0
    if (jitFrame.isBaselineJS()) {
2438
0
        return true;
2439
0
    }
2440
0
2441
0
    if (jitFrame.isIonScripted()) {
2442
0
        // Only the bottom of a group of inlined Ion frames is a physical frame.
2443
0
        return ionInlineFrames_.frameNo() == 0;
2444
0
    }
2445
0
2446
0
    return false;
2447
0
}
2448
2449
inline jit::CommonFrameLayout*
2450
FrameIter::physicalJitFrame() const
2451
0
{
2452
0
    MOZ_ASSERT(isPhysicalJitFrame());
2453
0
    return jsJitFrame().current();
2454
0
}
2455
2456
}  /* namespace js */
2457
2458
#endif /* vm_Stack_h */