LCOV - code coverage report
Current view: top level - js/src/frontend - BytecodeEmitter.h (source / functions) Hit Total Coverage
Test: output.info Lines: 86 87 98.9 %
Date: 2017-07-14 16:53:18 Functions: 65 72 90.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* JS bytecode generation. */
       8             : 
       9             : #ifndef frontend_BytecodeEmitter_h
      10             : #define frontend_BytecodeEmitter_h
      11             : 
      12             : #include "mozilla/Attributes.h"
      13             : 
      14             : #include "jscntxt.h"
      15             : #include "jsiter.h"
      16             : #include "jsopcode.h"
      17             : #include "jsscript.h"
      18             : 
      19             : #include "ds/InlineTable.h"
      20             : #include "frontend/EitherParser.h"
      21             : #include "frontend/SharedContext.h"
      22             : #include "frontend/SourceNotes.h"
      23             : #include "vm/Interpreter.h"
      24             : 
      25             : namespace js {
      26             : namespace frontend {
      27             : 
      28        5674 : class CGConstList {
      29             :     Vector<Value> list;
      30             :   public:
      31        5673 :     explicit CGConstList(JSContext* cx) : list(cx) {}
      32          51 :     MOZ_MUST_USE bool append(const Value& v) {
      33          51 :         MOZ_ASSERT_IF(v.isString(), v.toString()->isAtom());
      34          51 :         return list.append(v);
      35             :     }
      36       11529 :     size_t length() const { return list.length(); }
      37             :     void finish(ConstArray* array);
      38             : };
      39             : 
      40             : struct CGObjectList {
      41             :     uint32_t            length;     /* number of emitted so far objects */
      42             :     ObjectBox*          lastbox;   /* last emitted object */
      43             : 
      44        5673 :     CGObjectList() : length(0), lastbox(nullptr) {}
      45             : 
      46             :     unsigned add(ObjectBox* objbox);
      47             :     unsigned indexOf(JSObject* obj);
      48             :     void finish(ObjectArray* array);
      49             :     ObjectBox* find(uint32_t index);
      50             : };
      51             : 
      52        5674 : struct MOZ_STACK_CLASS CGScopeList {
      53             :     Rooted<GCVector<Scope*>> vector;
      54             : 
      55        5673 :     explicit CGScopeList(JSContext* cx)
      56        5673 :       : vector(cx, GCVector<Scope*>(cx))
      57        5673 :     { }
      58             : 
      59        9108 :     bool append(Scope* scope) { return vector.append(scope); }
      60       52738 :     uint32_t length() const { return vector.length(); }
      61             :     void finish(ScopeArray* array);
      62             : };
      63             : 
      64        5674 : struct CGTryNoteList {
      65             :     Vector<JSTryNote> list;
      66        5673 :     explicit CGTryNoteList(JSContext* cx) : list(cx) {}
      67             : 
      68             :     MOZ_MUST_USE bool append(JSTryNoteKind kind, uint32_t stackDepth, size_t start, size_t end);
      69       16343 :     size_t length() const { return list.length(); }
      70             :     void finish(TryNoteArray* array);
      71             : };
      72             : 
      73             : struct CGScopeNote : public ScopeNote
      74             : {
      75             :     // The end offset. Used to compute the length; may need adjusting first if
      76             :     // in the prologue.
      77             :     uint32_t end;
      78             : 
      79             :     // Is the start offset in the prologue?
      80             :     bool startInPrologue;
      81             : 
      82             :     // Is the end offset in the prologue?
      83             :     bool endInPrologue;
      84             : };
      85             : 
      86        5674 : struct CGScopeNoteList {
      87             :     Vector<CGScopeNote> list;
      88        5673 :     explicit CGScopeNoteList(JSContext* cx) : list(cx) {}
      89             : 
      90             :     MOZ_MUST_USE bool append(uint32_t scopeIndex, uint32_t offset, bool inPrologue,
      91             :                              uint32_t parent);
      92             :     void recordEnd(uint32_t index, uint32_t offset, bool inPrologue);
      93       45554 :     size_t length() const { return list.length(); }
      94             :     void finish(ScopeNoteArray* array, uint32_t prologueLength);
      95             : };
      96             : 
      97        5674 : struct CGYieldAndAwaitOffsetList {
      98             :     Vector<uint32_t> list;
      99             :     uint32_t numYields;
     100             :     uint32_t numAwaits;
     101        5673 :     explicit CGYieldAndAwaitOffsetList(JSContext* cx) : list(cx), numYields(0), numAwaits(0) {}
     102             : 
     103         380 :     MOZ_MUST_USE bool append(uint32_t offset) { return list.append(offset); }
     104       12364 :     size_t length() const { return list.length(); }
     105             :     void finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength);
     106             : };
     107             : 
     108             : // Use zero inline elements because these go on the stack and affect how many
     109             : // nested functions are possible.
     110             : typedef Vector<jsbytecode, 0> BytecodeVector;
     111             : typedef Vector<jssrcnote, 0> SrcNotesVector;
     112             : 
     113             : // Linked list of jump instructions that need to be patched. The linked list is
     114             : // stored in the bytes of the incomplete bytecode that will be patched, so no
     115             : // extra memory is needed, and patching the instructions destroys the list.
     116             : //
     117             : // Example:
     118             : //
     119             : //     JumpList brList;
     120             : //     if (!emitJump(JSOP_IFEQ, &brList))
     121             : //         return false;
     122             : //     ...
     123             : //     JumpTarget label;
     124             : //     if (!emitJumpTarget(&label))
     125             : //         return false;
     126             : //     ...
     127             : //     if (!emitJump(JSOP_GOTO, &brList))
     128             : //         return false;
     129             : //     ...
     130             : //     patchJumpsToTarget(brList, label);
     131             : //
     132             : //                 +-> -1
     133             : //                 |
     134             : //                 |
     135             : //    ifeq ..   <+ +                +-+   ifeq ..
     136             : //    ..         |                  |     ..
     137             : //  label:       |                  +-> label:
     138             : //    jumptarget |                  |     jumptarget
     139             : //    ..         |                  |     ..
     140             : //    goto .. <+ +                  +-+   goto .. <+
     141             : //             |                                   |
     142             : //             |                                   |
     143             : //             +                                   +
     144             : //           brList                              brList
     145             : //
     146             : //       |                                  ^
     147             : //       +------- patchJumpsToTarget -------+
     148             : //
     149             : 
     150             : // Offset of a jump target instruction, used for patching jump instructions.
     151             : struct JumpTarget {
     152             :     ptrdiff_t offset;
     153             : };
     154             : 
     155             : struct JumpList {
     156             :     // -1 is used to mark the end of jump lists.
     157       28492 :     JumpList() : offset(-1) {}
     158             :     ptrdiff_t offset;
     159             : 
     160             :     // Add a jump instruction to the list.
     161             :     void push(jsbytecode* code, ptrdiff_t jumpOffset);
     162             : 
     163             :     // Patch all jump instructions in this list to jump to `target`.  This
     164             :     // clobbers the list.
     165             :     void patchAll(jsbytecode* code, JumpTarget target);
     166             : };
     167             : 
     168             : enum class ValueUsage {
     169             :     WantValue,
     170             :     IgnoreValue
     171             : };
     172             : 
     173        5674 : struct MOZ_STACK_CLASS BytecodeEmitter
     174             : {
     175             :     class TDZCheckCache;
     176             :     class NestableControl;
     177             :     class EmitterScope;
     178             : 
     179             :     SharedContext* const sc;      /* context shared between parsing and bytecode generation */
     180             : 
     181             :     JSContext* const cx;
     182             : 
     183             :     BytecodeEmitter* const parent;  /* enclosing function or global context */
     184             : 
     185             :     Rooted<JSScript*> script;       /* the JSScript we're ultimately producing */
     186             : 
     187             :     Rooted<LazyScript*> lazyScript; /* the lazy script if mode is LazyFunction,
     188             :                                         nullptr otherwise. */
     189             : 
     190       11348 :     struct EmitSection {
     191             :         BytecodeVector code;        /* bytecode */
     192             :         SrcNotesVector notes;       /* source notes, see below */
     193             :         ptrdiff_t   lastNoteOffset; /* code offset for last source note */
     194             : 
     195             :         // Line number for srcnotes.
     196             :         //
     197             :         // WARNING: If this becomes out of sync with already-emitted srcnotes,
     198             :         // we can get undefined behavior.
     199             :         uint32_t    currentLine;
     200             : 
     201             :         // Zero-based column index on currentLine of last SRC_COLSPAN-annotated
     202             :         // opcode.
     203             :         //
     204             :         // WARNING: If this becomes out of sync with already-emitted srcnotes,
     205             :         // we can get undefined behavior.
     206             :         uint32_t    lastColumn;
     207             : 
     208             :         JumpTarget lastTarget;      // Last jump target emitted.
     209             : 
     210       11346 :         EmitSection(JSContext* cx, uint32_t lineNum)
     211       11346 :           : code(cx), notes(cx), lastNoteOffset(0), currentLine(lineNum), lastColumn(0),
     212       11346 :             lastTarget{ -1 - ptrdiff_t(JSOP_JUMPTARGET_LENGTH) }
     213       11346 :         {}
     214             :     };
     215             :     EmitSection prologue, main, *current;
     216             : 
     217             :     EitherParser<FullParseHandler> parser;
     218             : 
     219             :     PooledMapPtr<AtomIndexMap> atomIndices; /* literals indexed for mapping */
     220             :     unsigned        firstLine;      /* first line, for JSScript::initFromEmitter */
     221             : 
     222             :     uint32_t        maxFixedSlots;  /* maximum number of fixed frame slots so far */
     223             :     uint32_t        maxStackDepth;  /* maximum number of expression stack slots so far */
     224             : 
     225             :     int32_t         stackDepth;     /* current stack depth in script frame */
     226             : 
     227             :     uint32_t        arrayCompDepth; /* stack depth of array in comprehension */
     228             : 
     229             :     unsigned        emitLevel;      /* emitTree recursion level */
     230             : 
     231             :     uint32_t        bodyScopeIndex; /* index into scopeList of the body scope */
     232             : 
     233             :     EmitterScope*    varEmitterScope;
     234             :     NestableControl* innermostNestableControl;
     235             :     EmitterScope*    innermostEmitterScope;
     236             :     TDZCheckCache*   innermostTDZCheckCache;
     237             : 
     238             :     CGConstList      constList;      /* constants to be included with the script */
     239             :     CGObjectList     objectList;     /* list of emitted objects */
     240             :     CGScopeList      scopeList;      /* list of emitted scopes */
     241             :     CGTryNoteList    tryNoteList;    /* list of emitted try notes */
     242             :     CGScopeNoteList  scopeNoteList;  /* list of emitted block scope notes */
     243             : 
     244             :     /*
     245             :      * For each yield or await op, map the yield and await index (stored as
     246             :      * bytecode operand) to the offset of the next op.
     247             :      */
     248             :     CGYieldAndAwaitOffsetList yieldAndAwaitOffsetList;
     249             : 
     250             :     uint16_t        typesetCount;   /* Number of JOF_TYPESET opcodes generated */
     251             : 
     252             :     bool            hasSingletons:1;    /* script contains singleton initializer JSOP_OBJECT */
     253             : 
     254             :     bool            hasTryFinally:1;    /* script contains finally block */
     255             : 
     256             :     bool            emittingRunOnceLambda:1; /* true while emitting a lambda which is only
     257             :                                                 expected to run once. */
     258             : 
     259             :     bool isRunOnceLambda();
     260             : 
     261             :     enum EmitterMode {
     262             :         Normal,
     263             : 
     264             :         /*
     265             :          * Emit JSOP_GETINTRINSIC instead of JSOP_GETNAME and assert that
     266             :          * JSOP_GETNAME and JSOP_*GNAME don't ever get emitted. See the comment
     267             :          * for the field |selfHostingMode| in Parser.h for details.
     268             :          */
     269             :         SelfHosting,
     270             : 
     271             :         /*
     272             :          * Check the static scope chain of the root function for resolving free
     273             :          * variable accesses in the script.
     274             :          */
     275             :         LazyFunction
     276             :     };
     277             : 
     278             :     const EmitterMode emitterMode;
     279             : 
     280             :     // The end location of a function body that is being emitted.
     281             :     uint32_t functionBodyEndPos;
     282             :     // Whether functionBodyEndPos was set.
     283             :     bool functionBodyEndPosSet;
     284             : 
     285             :     /*
     286             :      * Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
     287             :      * space above their tempMark points. This means that you cannot alloc from
     288             :      * tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
     289             :      * destruction.
     290             :      */
     291             :     BytecodeEmitter(BytecodeEmitter* parent, const EitherParser<FullParseHandler>& parser,
     292             :                     SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript,
     293             :                     uint32_t lineNum, EmitterMode emitterMode = Normal);
     294             : 
     295             :     template<typename CharT>
     296         284 :     BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler, CharT>* parser,
     297             :                     SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript,
     298             :                     uint32_t lineNum, EmitterMode emitterMode = Normal)
     299             :       : BytecodeEmitter(parent, EitherParser<FullParseHandler>(parser), sc, script, lazyScript,
     300         284 :                         lineNum, emitterMode)
     301         284 :     {}
     302             : 
     303             :     // An alternate constructor that uses a TokenPos for the starting
     304             :     // line and that sets functionBodyEndPos as well.
     305             :     BytecodeEmitter(BytecodeEmitter* parent, const EitherParser<FullParseHandler>& parser,
     306             :                     SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript,
     307             :                     TokenPos bodyPosition, EmitterMode emitterMode = Normal);
     308             : 
     309             :     template<typename CharT>
     310        1407 :     BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler, CharT>* parser,
     311             :                     SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript,
     312             :                     TokenPos bodyPosition, EmitterMode emitterMode = Normal)
     313             :       : BytecodeEmitter(parent, EitherParser<FullParseHandler>(parser), sc, script, lazyScript,
     314        1407 :                         bodyPosition, emitterMode)
     315        1407 :     {}
     316             : 
     317             :     MOZ_MUST_USE bool init();
     318             : 
     319             :     template <typename Predicate /* (NestableControl*) -> bool */>
     320             :     NestableControl* findInnermostNestableControl(Predicate predicate) const;
     321             : 
     322             :     template <typename T>
     323             :     T* findInnermostNestableControl() const;
     324             : 
     325             :     template <typename T, typename Predicate /* (T*) -> bool */>
     326             :     T* findInnermostNestableControl(Predicate predicate) const;
     327             : 
     328             :     NameLocation lookupName(JSAtom* name);
     329             : 
     330             :     // To implement Annex B and the formal parameter defaults scope semantics
     331             :     // requires accessing names that would otherwise be shadowed. This method
     332             :     // returns the access location of a name that is known to be bound in a
     333             :     // target scope.
     334             :     mozilla::Maybe<NameLocation> locationOfNameBoundInScope(JSAtom* name, EmitterScope* target);
     335             : 
     336             :     // Get the location of a name known to be bound in the function scope,
     337             :     // starting at the source scope.
     338             :     mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope(JSAtom* name,
     339             :                                                                     EmitterScope* source);
     340             : 
     341         395 :     mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope(JSAtom* name) {
     342         395 :         return locationOfNameBoundInFunctionScope(name, innermostEmitterScope);
     343             :     }
     344             : 
     345        5672 :     void setVarEmitterScope(EmitterScope* emitterScope) {
     346        5672 :         MOZ_ASSERT(emitterScope);
     347        5672 :         MOZ_ASSERT(!varEmitterScope);
     348        5672 :         varEmitterScope = emitterScope;
     349        5672 :     }
     350             : 
     351             :     Scope* bodyScope() const { return scopeList.vector[bodyScopeIndex]; }
     352        5675 :     Scope* outermostScope() const { return scopeList.vector[0]; }
     353             :     Scope* innermostScope() const;
     354             : 
     355             :     MOZ_ALWAYS_INLINE
     356       75215 :     MOZ_MUST_USE bool makeAtomIndex(JSAtom* atom, uint32_t* indexp) {
     357       75215 :         MOZ_ASSERT(atomIndices);
     358       75215 :         AtomIndexMap::AddPtr p = atomIndices->lookupForAdd(atom);
     359       75215 :         if (p) {
     360       23463 :             *indexp = p->value();
     361       23463 :             return true;
     362             :         }
     363             : 
     364       51752 :         uint32_t index = atomIndices->count();
     365       51752 :         if (!atomIndices->add(p, atom, index))
     366           0 :             return false;
     367             : 
     368       51752 :         *indexp = index;
     369       51752 :         return true;
     370             :     }
     371             : 
     372             :     bool isInLoop();
     373             :     MOZ_MUST_USE bool checkSingletonContext();
     374             : 
     375             :     // Check whether our function is in a run-once context (a toplevel
     376             :     // run-one script or a run-once lambda).
     377             :     MOZ_MUST_USE bool checkRunOnceContext();
     378             : 
     379             :     bool needsImplicitThis();
     380             : 
     381             :     MOZ_MUST_USE bool maybeSetDisplayURL();
     382             :     MOZ_MUST_USE bool maybeSetSourceMap();
     383             :     void tellDebuggerAboutCompiledScript(JSContext* cx);
     384             : 
     385             :     inline TokenStreamAnyChars& tokenStream();
     386             : 
     387     1175629 :     BytecodeVector& code() const { return current->code; }
     388      893838 :     jsbytecode* code(ptrdiff_t offset) const { return current->code.begin() + offset; }
     389      376327 :     ptrdiff_t offset() const { return current->code.end() - current->code.begin(); }
     390       11255 :     ptrdiff_t prologueOffset() const { return prologue.code.end() - prologue.code.begin(); }
     391        7345 :     void switchToMain() { current = &main; }
     392        7345 :     void switchToPrologue() { current = &prologue; }
     393       10201 :     bool inPrologue() const { return current == &prologue; }
     394             : 
     395      340165 :     SrcNotesVector& notes() const { return current->notes; }
     396      248558 :     ptrdiff_t lastNoteOffset() const { return current->lastNoteOffset; }
     397      379583 :     unsigned currentLine() const { return current->currentLine; }
     398             :     unsigned lastColumn() const { return current->lastColumn; }
     399             : 
     400             :     // Check if the last emitted opcode is a jump target.
     401         210 :     bool lastOpcodeIsJumpTarget() const {
     402         210 :         return offset() - current->lastTarget.offset == ptrdiff_t(JSOP_JUMPTARGET_LENGTH);
     403             :     }
     404             : 
     405             :     // JumpTarget should not be part of the emitted statement, as they can be
     406             :     // aliased by multiple statements. If we included the jump target as part of
     407             :     // the statement we might have issues where the enclosing statement might
     408             :     // not contain all the opcodes of the enclosed statements.
     409         210 :     ptrdiff_t lastNonJumpTargetOffset() const {
     410         210 :         return lastOpcodeIsJumpTarget() ? current->lastTarget.offset : offset();
     411             :     }
     412             : 
     413       11061 :     void setFunctionBodyEndPos(TokenPos pos) {
     414       11061 :         functionBodyEndPos = pos.end;
     415       11061 :         functionBodyEndPosSet = true;
     416       11061 :     }
     417             : 
     418             :     void reportError(ParseNode* pn, unsigned errorNumber, ...);
     419             :     bool reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...);
     420             :     bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...);
     421             : 
     422             :     // If pn contains a useful expression, return true with *answer set to true.
     423             :     // If pn contains a useless expression, return true with *answer set to
     424             :     // false. Return false on error.
     425             :     //
     426             :     // The caller should initialize *answer to false and invoke this function on
     427             :     // an expression statement or similar subtree to decide whether the tree
     428             :     // could produce code that has any side effects.  For an expression
     429             :     // statement, we define useless code as code with no side effects, because
     430             :     // the main effect, the value left on the stack after the code executes,
     431             :     // will be discarded by a pop bytecode.
     432             :     MOZ_MUST_USE bool checkSideEffects(ParseNode* pn, bool* answer);
     433             : 
     434             : #ifdef DEBUG
     435             :     MOZ_MUST_USE bool checkStrictOrSloppy(JSOp op);
     436             : #endif
     437             : 
     438             :     // Append a new source note of the given type (and therefore size) to the
     439             :     // notes dynamic array, updating noteCount. Return the new note's index
     440             :     // within the array pointed at by current->notes as outparam.
     441             :     MOZ_MUST_USE bool newSrcNote(SrcNoteType type, unsigned* indexp = nullptr);
     442             :     MOZ_MUST_USE bool newSrcNote2(SrcNoteType type, ptrdiff_t offset, unsigned* indexp = nullptr);
     443             :     MOZ_MUST_USE bool newSrcNote3(SrcNoteType type, ptrdiff_t offset1, ptrdiff_t offset2,
     444             :                                   unsigned* indexp = nullptr);
     445             : 
     446             :     void copySrcNotes(jssrcnote* destination, uint32_t nsrcnotes);
     447             :     MOZ_MUST_USE bool setSrcNoteOffset(unsigned index, unsigned which, ptrdiff_t offset);
     448             : 
     449             :     // NB: this function can add at most one extra extended delta note.
     450             :     MOZ_MUST_USE bool addToSrcNoteDelta(jssrcnote* sn, ptrdiff_t delta);
     451             : 
     452             :     // Finish taking source notes in cx's notePool. If successful, the final
     453             :     // source note count is stored in the out outparam.
     454             :     MOZ_MUST_USE bool finishTakingSrcNotes(uint32_t* out);
     455             : 
     456             :     // Control whether emitTree emits a line number note.
     457             :     enum EmitLineNumberNote {
     458             :         EMIT_LINENOTE,
     459             :         SUPPRESS_LINENOTE
     460             :     };
     461             : 
     462             :     // Emit code for the tree rooted at pn.
     463             :     MOZ_MUST_USE bool emitTree(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue,
     464             :                                EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
     465             : 
     466             :     // Emit code for the tree rooted at pn with its own TDZ cache.
     467             :     MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn,
     468             :                                        ValueUsage valueUsage = ValueUsage::WantValue);
     469             : 
     470             :     // Emit global, eval, or module code for tree rooted at body. Always
     471             :     // encompasses the entire source.
     472             :     MOZ_MUST_USE bool emitScript(ParseNode* body);
     473             : 
     474             :     // Emit function code for the tree rooted at body.
     475             :     MOZ_MUST_USE bool emitFunctionScript(ParseNode* body);
     476             : 
     477             :     // If op is JOF_TYPESET (see the type barriers comment in TypeInference.h),
     478             :     // reserve a type set to store its result.
     479             :     void checkTypeSet(JSOp op);
     480             : 
     481             :     void updateDepth(ptrdiff_t target);
     482             :     MOZ_MUST_USE bool updateLineNumberNotes(uint32_t offset);
     483             :     MOZ_MUST_USE bool updateSourceCoordNotes(uint32_t offset);
     484             : 
     485             :     JSOp strictifySetNameOp(JSOp op);
     486             : 
     487             :     MOZ_MUST_USE bool emitCheck(ptrdiff_t delta, ptrdiff_t* offset);
     488             : 
     489             :     // Emit one bytecode.
     490             :     MOZ_MUST_USE bool emit1(JSOp op);
     491             : 
     492             :     // Emit two bytecodes, an opcode (op) with a byte of immediate operand
     493             :     // (op1).
     494             :     MOZ_MUST_USE bool emit2(JSOp op, uint8_t op1);
     495             : 
     496             :     // Emit three bytecodes, an opcode with two bytes of immediate operands.
     497             :     MOZ_MUST_USE bool emit3(JSOp op, jsbytecode op1, jsbytecode op2);
     498             : 
     499             :     // Helper to emit JSOP_DUPAT. The argument is the value's depth on the
     500             :     // JS stack, as measured from the top.
     501             :     MOZ_MUST_USE bool emitDupAt(unsigned slotFromTop);
     502             : 
     503             :     // Helper to emit JSOP_POP or JSOP_POPN.
     504             :     MOZ_MUST_USE bool emitPopN(unsigned n);
     505             : 
     506             :     // Helper to emit JSOP_CHECKISOBJ.
     507             :     MOZ_MUST_USE bool emitCheckIsObj(CheckIsObjectKind kind);
     508             : 
     509             :     // Helper to emit JSOP_CHECKISCALLABLE.
     510             :     MOZ_MUST_USE bool emitCheckIsCallable(CheckIsCallableKind kind);
     511             : 
     512             :     // Emit a bytecode followed by an uint16 immediate operand stored in
     513             :     // big-endian order.
     514             :     MOZ_MUST_USE bool emitUint16Operand(JSOp op, uint32_t operand);
     515             : 
     516             :     // Emit a bytecode followed by an uint32 immediate operand.
     517             :     MOZ_MUST_USE bool emitUint32Operand(JSOp op, uint32_t operand);
     518             : 
     519             :     // Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand.
     520             :     MOZ_MUST_USE bool emitN(JSOp op, size_t extra, ptrdiff_t* offset = nullptr);
     521             : 
     522             :     MOZ_MUST_USE bool emitNumberOp(double dval);
     523             : 
     524             :     MOZ_MUST_USE bool emitThisLiteral(ParseNode* pn);
     525             :     MOZ_MUST_USE bool emitGetFunctionThis(ParseNode* pn);
     526             :     MOZ_MUST_USE bool emitGetThisForSuperBase(ParseNode* pn);
     527             :     MOZ_MUST_USE bool emitSetThis(ParseNode* pn);
     528             :     MOZ_MUST_USE bool emitCheckDerivedClassConstructorReturn();
     529             : 
     530             :     // Handle jump opcodes and jump targets.
     531             :     MOZ_MUST_USE bool emitJumpTarget(JumpTarget* target);
     532             :     MOZ_MUST_USE bool emitJumpNoFallthrough(JSOp op, JumpList* jump);
     533             :     MOZ_MUST_USE bool emitJump(JSOp op, JumpList* jump);
     534             :     MOZ_MUST_USE bool emitBackwardJump(JSOp op, JumpTarget target, JumpList* jump,
     535             :                                        JumpTarget* fallthrough);
     536             :     void patchJumpsToTarget(JumpList jump, JumpTarget target);
     537             :     MOZ_MUST_USE bool emitJumpTargetAndPatch(JumpList jump);
     538             : 
     539             :     MOZ_MUST_USE bool emitCall(JSOp op, uint16_t argc, ParseNode* pn = nullptr);
     540             :     MOZ_MUST_USE bool emitCallIncDec(ParseNode* incDec);
     541             : 
     542             :     MOZ_MUST_USE bool emitLoopHead(ParseNode* nextpn, JumpTarget* top);
     543             :     MOZ_MUST_USE bool emitLoopEntry(ParseNode* nextpn, JumpList entryJump);
     544             : 
     545             :     MOZ_MUST_USE bool emitGoto(NestableControl* target, JumpList* jumplist,
     546             :                                SrcNoteType noteType = SRC_NULL);
     547             : 
     548             :     MOZ_MUST_USE bool emitIndex32(JSOp op, uint32_t index);
     549             :     MOZ_MUST_USE bool emitIndexOp(JSOp op, uint32_t index);
     550             : 
     551             :     MOZ_MUST_USE bool emitAtomOp(JSAtom* atom, JSOp op);
     552             :     MOZ_MUST_USE bool emitAtomOp(ParseNode* pn, JSOp op);
     553             : 
     554             :     MOZ_MUST_USE bool emitArrayLiteral(ParseNode* pn);
     555             :     MOZ_MUST_USE bool emitArray(ParseNode* pn, uint32_t count, JSOp op);
     556             :     MOZ_MUST_USE bool emitArrayComp(ParseNode* pn);
     557             : 
     558             :     MOZ_MUST_USE bool emitInternedScopeOp(uint32_t index, JSOp op);
     559             :     MOZ_MUST_USE bool emitInternedObjectOp(uint32_t index, JSOp op);
     560             :     MOZ_MUST_USE bool emitObjectOp(ObjectBox* objbox, JSOp op);
     561             :     MOZ_MUST_USE bool emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2, JSOp op);
     562             :     MOZ_MUST_USE bool emitRegExp(uint32_t index);
     563             : 
     564             :     MOZ_NEVER_INLINE MOZ_MUST_USE bool emitFunction(ParseNode* pn, bool needsProto = false);
     565             :     MOZ_NEVER_INLINE MOZ_MUST_USE bool emitObject(ParseNode* pn);
     566             : 
     567             :     MOZ_MUST_USE bool replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset);
     568             : 
     569             :     MOZ_MUST_USE bool emitHoistedFunctionsInList(ParseNode* pn);
     570             : 
     571             :     MOZ_MUST_USE bool emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp,
     572             :                                        PropListType type);
     573             : 
     574             :     // To catch accidental misuse, emitUint16Operand/emit3 assert that they are
     575             :     // not used to unconditionally emit JSOP_GETLOCAL. Variable access should
     576             :     // instead be emitted using EmitVarOp. In special cases, when the caller
     577             :     // definitely knows that a given local slot is unaliased, this function may be
     578             :     // used as a non-asserting version of emitUint16Operand.
     579             :     MOZ_MUST_USE bool emitLocalOp(JSOp op, uint32_t slot);
     580             : 
     581             :     MOZ_MUST_USE bool emitArgOp(JSOp op, uint16_t slot);
     582             :     MOZ_MUST_USE bool emitEnvCoordOp(JSOp op, EnvironmentCoordinate ec);
     583             : 
     584             :     MOZ_MUST_USE bool emitGetNameAtLocation(JSAtom* name, const NameLocation& loc,
     585             :                                             bool callContext = false);
     586             :     MOZ_MUST_USE bool emitGetNameAtLocationForCompoundAssignment(JSAtom* name,
     587             :                                                                  const NameLocation& loc);
     588       69176 :     MOZ_MUST_USE bool emitGetName(JSAtom* name, bool callContext = false) {
     589       69176 :         return emitGetNameAtLocation(name, lookupName(name), callContext);
     590             :     }
     591             :     MOZ_MUST_USE bool emitGetName(ParseNode* pn, bool callContext = false);
     592             : 
     593             :     template <typename RHSEmitter>
     594             :     MOZ_MUST_USE bool emitSetOrInitializeNameAtLocation(HandleAtom name, const NameLocation& loc,
     595             :                                                         RHSEmitter emitRhs, bool initialize);
     596             :     template <typename RHSEmitter>
     597       16490 :     MOZ_MUST_USE bool emitSetOrInitializeName(HandleAtom name, RHSEmitter emitRhs,
     598             :                                               bool initialize)
     599             :     {
     600       16490 :         return emitSetOrInitializeNameAtLocation(name, lookupName(name), emitRhs, initialize);
     601             :     }
     602             :     template <typename RHSEmitter>
     603        3328 :     MOZ_MUST_USE bool emitSetName(ParseNode* pn, RHSEmitter emitRhs) {
     604        6656 :         RootedAtom name(cx, pn->name());
     605        6656 :         return emitSetName(name, emitRhs);
     606             :     }
     607             :     template <typename RHSEmitter>
     608        3337 :     MOZ_MUST_USE bool emitSetName(HandleAtom name, RHSEmitter emitRhs) {
     609        3337 :         return emitSetOrInitializeName(name, emitRhs, false);
     610             :     }
     611             :     template <typename RHSEmitter>
     612       10071 :     MOZ_MUST_USE bool emitInitializeName(ParseNode* pn, RHSEmitter emitRhs) {
     613       20143 :         RootedAtom name(cx, pn->name());
     614       20143 :         return emitInitializeName(name, emitRhs);
     615             :     }
     616             :     template <typename RHSEmitter>
     617       13153 :     MOZ_MUST_USE bool emitInitializeName(HandleAtom name, RHSEmitter emitRhs) {
     618       13153 :         return emitSetOrInitializeName(name, emitRhs, true);
     619             :     }
     620             : 
     621             :     MOZ_MUST_USE bool emitTDZCheckIfNeeded(JSAtom* name, const NameLocation& loc);
     622             : 
     623             :     MOZ_MUST_USE bool emitNameIncDec(ParseNode* pn);
     624             : 
     625             :     MOZ_MUST_USE bool emitDeclarationList(ParseNode* decls);
     626             :     MOZ_MUST_USE bool emitSingleDeclaration(ParseNode* decls, ParseNode* decl,
     627             :                                             ParseNode* initializer);
     628             : 
     629             :     MOZ_MUST_USE bool emitNewInit(JSProtoKey key);
     630             :     MOZ_MUST_USE bool emitSingletonInitialiser(ParseNode* pn);
     631             : 
     632             :     MOZ_MUST_USE bool emitPrepareIteratorResult();
     633             :     MOZ_MUST_USE bool emitFinishIteratorResult(bool done);
     634             :     MOZ_MUST_USE bool iteratorResultShape(unsigned* shape);
     635             :     MOZ_MUST_USE bool emitToIteratorResult(bool done);
     636             : 
     637             :     MOZ_MUST_USE bool emitGetDotGenerator();
     638             : 
     639             :     MOZ_MUST_USE bool emitInitialYield(ParseNode* pn);
     640             :     MOZ_MUST_USE bool emitYield(ParseNode* pn);
     641             :     MOZ_MUST_USE bool emitYieldOp(JSOp op);
     642             :     MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
     643             :     MOZ_MUST_USE bool emitAwait();
     644             :     MOZ_MUST_USE bool emitAwait(ParseNode* pn);
     645             : 
     646             :     MOZ_MUST_USE bool emitPropLHS(ParseNode* pn);
     647             :     MOZ_MUST_USE bool emitPropOp(ParseNode* pn, JSOp op);
     648             :     MOZ_MUST_USE bool emitPropIncDec(ParseNode* pn);
     649             : 
     650             :     MOZ_MUST_USE bool emitAsyncWrapperLambda(unsigned index, bool isArrow);
     651             :     MOZ_MUST_USE bool emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow,
     652             :                                        bool isStarGenerator);
     653             : 
     654             :     MOZ_MUST_USE bool emitComputedPropertyName(ParseNode* computedPropName);
     655             : 
     656             :     // Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM
     657             :     // opcode onto the stack in the right order. In the case of SETELEM, the
     658             :     // value to be assigned must already be pushed.
     659             :     enum class EmitElemOption { Get, Set, Call, IncDec, CompoundAssign, Ref };
     660             :     MOZ_MUST_USE bool emitElemOperands(ParseNode* pn, EmitElemOption opts);
     661             : 
     662             :     MOZ_MUST_USE bool emitElemOpBase(JSOp op);
     663             :     MOZ_MUST_USE bool emitElemOp(ParseNode* pn, JSOp op);
     664             :     MOZ_MUST_USE bool emitElemIncDec(ParseNode* pn);
     665             : 
     666             :     MOZ_MUST_USE bool emitCatch(ParseNode* pn);
     667             :     MOZ_MUST_USE bool emitIf(ParseNode* pn);
     668             :     MOZ_MUST_USE bool emitWith(ParseNode* pn);
     669             : 
     670             :     MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLabeledStatement(const LabeledStatement* pn);
     671             :     MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLexicalScope(ParseNode* pn);
     672             :     MOZ_MUST_USE bool emitLexicalScopeBody(ParseNode* body,
     673             :                                            EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
     674             :     MOZ_NEVER_INLINE MOZ_MUST_USE bool emitSwitch(ParseNode* pn);
     675             :     MOZ_NEVER_INLINE MOZ_MUST_USE bool emitTry(ParseNode* pn);
     676             : 
     677             :     enum DestructuringFlavor {
     678             :         // Destructuring into a declaration.
     679             :         DestructuringDeclaration,
     680             : 
     681             :         // Destructuring into a formal parameter, when the formal parameters
     682             :         // contain an expression that might be evaluated, and thus require
     683             :         // this destructuring to assign not into the innermost scope that
     684             :         // contains the function body's vars, but into its enclosing scope for
     685             :         // parameter expressions.
     686             :         DestructuringFormalParameterInVarScope,
     687             : 
     688             :         // Destructuring as part of an AssignmentExpression.
     689             :         DestructuringAssignment
     690             :     };
     691             : 
     692             :     // emitDestructuringLHSRef emits the lhs expression's reference.
     693             :     // If the lhs expression is object property |OBJ.prop|, it emits |OBJ|.
     694             :     // If it's object element |OBJ[ELEM]|, it emits |OBJ| and |ELEM|.
     695             :     // If there's nothing to evaluate for the reference, it emits nothing.
     696             :     // |emitted| parameter receives the number of values pushed onto the stack.
     697             :     MOZ_MUST_USE bool emitDestructuringLHSRef(ParseNode* target, size_t* emitted);
     698             : 
     699             :     // emitSetOrInitializeDestructuring assumes the lhs expression's reference
     700             :     // and the to-be-destructured value has been pushed on the stack.  It emits
     701             :     // code to destructure a single lhs expression (either a name or a compound
     702             :     // []/{} expression).
     703             :     MOZ_MUST_USE bool emitSetOrInitializeDestructuring(ParseNode* target, DestructuringFlavor flav);
     704             : 
     705             :     // emitDestructuringObjRestExclusionSet emits the property exclusion set
     706             :     // for the rest-property in an object pattern.
     707             :     MOZ_MUST_USE bool emitDestructuringObjRestExclusionSet(ParseNode* pattern);
     708             : 
     709             :     // emitDestructuringOps assumes the to-be-destructured value has been
     710             :     // pushed on the stack and emits code to destructure each part of a [] or
     711             :     // {} lhs expression.
     712             :     MOZ_MUST_USE bool emitDestructuringOps(ParseNode* pattern, DestructuringFlavor flav);
     713             :     MOZ_MUST_USE bool emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlavor flav);
     714             :     MOZ_MUST_USE bool emitDestructuringOpsObject(ParseNode* pattern, DestructuringFlavor flav);
     715             : 
     716             :     typedef bool
     717             :     (*DestructuringDeclEmitter)(BytecodeEmitter* bce, ParseNode* pn);
     718             : 
     719             :     template <typename NameEmitter>
     720             :     MOZ_MUST_USE bool emitDestructuringDeclsWithEmitter(ParseNode* pattern, NameEmitter emitName);
     721             : 
     722             :     enum class CopyOption {
     723             :         Filtered, Unfiltered
     724             :     };
     725             : 
     726             :     // Calls either the |CopyDataProperties| or the
     727             :     // |CopyDataPropertiesUnfiltered| intrinsic function, consumes three (or
     728             :     // two in the latter case) elements from the stack.
     729             :     MOZ_MUST_USE bool emitCopyDataProperties(CopyOption option);
     730             : 
     731             :     // emitIterator expects the iterable to already be on the stack.
     732             :     // It will replace that stack value with the corresponding iterator
     733             :     MOZ_MUST_USE bool emitIterator();
     734             : 
     735             :     MOZ_MUST_USE bool emitAsyncIterator();
     736             : 
     737             :     // Pops iterator from the top of the stack. Pushes the result of |.next()|
     738             :     // onto the stack.
     739             :     MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, IteratorKind kind = IteratorKind::Sync,
     740             :                                        bool allowSelfHosted = false);
     741             :     MOZ_MUST_USE bool emitIteratorClose(IteratorKind iterKind = IteratorKind::Sync,
     742             :                                         CompletionKind completionKind = CompletionKind::Normal,
     743             :                                         bool allowSelfHosted = false);
     744             : 
     745             :     template <typename InnerEmitter>
     746             :     MOZ_MUST_USE bool wrapWithDestructuringIteratorCloseTryNote(int32_t iterDepth,
     747             :                                                                 InnerEmitter emitter);
     748             : 
     749             :     // Check if the value on top of the stack is "undefined". If so, replace
     750             :     // that value on the stack with the value defined by |defaultExpr|.
     751             :     // |pattern| is a lhs node of the default expression.  If it's an
     752             :     // identifier and |defaultExpr| is an anonymous function, |SetFunctionName|
     753             :     // is called at compile time.
     754             :     MOZ_MUST_USE bool emitDefault(ParseNode* defaultExpr, ParseNode* pattern);
     755             : 
     756             :     MOZ_MUST_USE bool setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name,
     757             :                                           FunctionPrefixKind prefixKind);
     758             : 
     759             :     MOZ_MUST_USE bool emitInitializer(ParseNode* initializer, ParseNode* pattern);
     760             :     MOZ_MUST_USE bool emitInitializerInBranch(ParseNode* initializer, ParseNode* pattern);
     761             : 
     762             :     MOZ_MUST_USE bool emitCallSiteObject(ParseNode* pn);
     763             :     MOZ_MUST_USE bool emitTemplateString(ParseNode* pn);
     764             :     MOZ_MUST_USE bool emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs);
     765             : 
     766             :     MOZ_MUST_USE bool emitReturn(ParseNode* pn);
     767             :     MOZ_MUST_USE bool emitStatement(ParseNode* pn);
     768             :     MOZ_MUST_USE bool emitStatementList(ParseNode* pn);
     769             : 
     770             :     MOZ_MUST_USE bool emitDeleteName(ParseNode* pn);
     771             :     MOZ_MUST_USE bool emitDeleteProperty(ParseNode* pn);
     772             :     MOZ_MUST_USE bool emitDeleteElement(ParseNode* pn);
     773             :     MOZ_MUST_USE bool emitDeleteExpression(ParseNode* pn);
     774             : 
     775             :     // |op| must be JSOP_TYPEOF or JSOP_TYPEOFEXPR.
     776             :     MOZ_MUST_USE bool emitTypeof(ParseNode* node, JSOp op);
     777             : 
     778             :     MOZ_MUST_USE bool emitUnary(ParseNode* pn);
     779             :     MOZ_MUST_USE bool emitRightAssociative(ParseNode* pn);
     780             :     MOZ_MUST_USE bool emitLeftAssociative(ParseNode* pn);
     781             :     MOZ_MUST_USE bool emitLogical(ParseNode* pn);
     782             :     MOZ_MUST_USE bool emitSequenceExpr(ParseNode* pn,
     783             :                                        ValueUsage valueUsage = ValueUsage::WantValue);
     784             : 
     785             :     MOZ_NEVER_INLINE MOZ_MUST_USE bool emitIncOrDec(ParseNode* pn);
     786             : 
     787             :     MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional,
     788             :                                                 ValueUsage valueUsage = ValueUsage::WantValue);
     789             : 
     790             :     bool isRestParameter(ParseNode* pn);
     791             : 
     792             :     MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue);
     793             :     MOZ_MUST_USE bool emitSelfHostedCallFunction(ParseNode* pn);
     794             :     MOZ_MUST_USE bool emitSelfHostedResumeGenerator(ParseNode* pn);
     795             :     MOZ_MUST_USE bool emitSelfHostedForceInterpreter(ParseNode* pn);
     796             :     MOZ_MUST_USE bool emitSelfHostedAllowContentIter(ParseNode* pn);
     797             :     MOZ_MUST_USE bool emitSelfHostedDefineDataProperty(ParseNode* pn);
     798             :     MOZ_MUST_USE bool emitSelfHostedHasOwn(ParseNode* pn);
     799             : 
     800             :     MOZ_MUST_USE bool emitComprehensionFor(ParseNode* compFor);
     801             :     MOZ_MUST_USE bool emitComprehensionForIn(ParseNode* pn);
     802             :     MOZ_MUST_USE bool emitComprehensionForInOrOfVariables(ParseNode* pn, bool* lexicalScope);
     803             :     MOZ_MUST_USE bool emitComprehensionForOf(ParseNode* pn);
     804             : 
     805             :     MOZ_MUST_USE bool emitDo(ParseNode* pn);
     806             :     MOZ_MUST_USE bool emitWhile(ParseNode* pn);
     807             : 
     808             :     MOZ_MUST_USE bool emitFor(ParseNode* pn, EmitterScope* headLexicalEmitterScope = nullptr);
     809             :     MOZ_MUST_USE bool emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterScope);
     810             :     MOZ_MUST_USE bool emitForIn(ParseNode* pn, EmitterScope* headLexicalEmitterScope);
     811             :     MOZ_MUST_USE bool emitForOf(ParseNode* pn, EmitterScope* headLexicalEmitterScope);
     812             : 
     813             :     MOZ_MUST_USE bool emitInitializeForInOrOfTarget(ParseNode* forHead);
     814             : 
     815             :     MOZ_MUST_USE bool emitBreak(PropertyName* label);
     816             :     MOZ_MUST_USE bool emitContinue(PropertyName* label);
     817             : 
     818             :     MOZ_MUST_USE bool emitFunctionFormalParametersAndBody(ParseNode* pn);
     819             :     MOZ_MUST_USE bool emitFunctionFormalParameters(ParseNode* pn);
     820             :     MOZ_MUST_USE bool emitInitializeFunctionSpecialNames();
     821             :     MOZ_MUST_USE bool emitFunctionBody(ParseNode* pn);
     822             :     MOZ_MUST_USE bool emitLexicalInitialization(ParseNode* pn);
     823             : 
     824             :     // Emit bytecode for the spread operator.
     825             :     //
     826             :     // emitSpread expects the current index (I) of the array, the array itself
     827             :     // and the iterator to be on the stack in that order (iterator on the bottom).
     828             :     // It will pop the iterator and I, then iterate over the iterator by calling
     829             :     // |.next()| and put the results into the I-th element of array with
     830             :     // incrementing I, then push the result I (it will be original I +
     831             :     // iteration count). The stack after iteration will look like |ARRAY INDEX|.
     832             :     MOZ_MUST_USE bool emitSpread(bool allowSelfHosted = false);
     833             : 
     834             :     MOZ_MUST_USE bool emitClass(ParseNode* pn);
     835             :     MOZ_MUST_USE bool emitSuperPropLHS(ParseNode* superBase, bool isCall = false);
     836             :     MOZ_MUST_USE bool emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall = false);
     837             :     MOZ_MUST_USE bool emitSuperElemOperands(ParseNode* pn,
     838             :                                             EmitElemOption opts = EmitElemOption::Get);
     839             :     MOZ_MUST_USE bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
     840             : };
     841             : 
     842             : } /* namespace frontend */
     843             : } /* namespace js */
     844             : 
     845             : #endif /* frontend_BytecodeEmitter_h */

Generated by: LCOV version 1.13