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