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