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 */
|