Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / js / src / frontend / BytecodeEmitter.cpp
blobfbbd79cc9724f8ea05fc88c1ea9b06519ea09972
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/. */
7 /*
8 * JS bytecode generation.
9 */
11 #include "frontend/BytecodeEmitter.h"
13 #include "mozilla/Casting.h" // mozilla::AssertedCast
14 #include "mozilla/DebugOnly.h" // mozilla::DebugOnly
15 #include "mozilla/FloatingPoint.h" // mozilla::NumberEqualsInt32, mozilla::NumberIsInt32
16 #include "mozilla/HashTable.h" // mozilla::HashSet
17 #include "mozilla/Maybe.h" // mozilla::{Maybe,Nothing,Some}
18 #include "mozilla/PodOperations.h" // mozilla::PodCopy
19 #include "mozilla/Saturate.h"
20 #include "mozilla/Variant.h" // mozilla::AsVariant
22 #include <algorithm>
23 #include <iterator>
24 #include <string.h>
26 #include "jstypes.h" // JS_BIT
28 #include "frontend/AbstractScopePtr.h" // ScopeIndex
29 #include "frontend/BytecodeControlStructures.h" // NestableControl, BreakableControl, LabelControl, LoopControl, TryFinallyControl
30 #include "frontend/CallOrNewEmitter.h" // CallOrNewEmitter
31 #include "frontend/CForEmitter.h" // CForEmitter
32 #include "frontend/DecoratorEmitter.h" // DecoratorEmitter
33 #include "frontend/DefaultEmitter.h" // DefaultEmitter
34 #include "frontend/DoWhileEmitter.h" // DoWhileEmitter
35 #include "frontend/ElemOpEmitter.h" // ElemOpEmitter
36 #include "frontend/EmitterScope.h" // EmitterScope
37 #include "frontend/ExpressionStatementEmitter.h" // ExpressionStatementEmitter
38 #include "frontend/ForInEmitter.h" // ForInEmitter
39 #include "frontend/ForOfEmitter.h" // ForOfEmitter
40 #include "frontend/FunctionEmitter.h" // FunctionEmitter, FunctionScriptEmitter, FunctionParamsEmitter
41 #include "frontend/IfEmitter.h" // IfEmitter, InternalIfEmitter, CondEmitter
42 #include "frontend/LabelEmitter.h" // LabelEmitter
43 #include "frontend/LexicalScopeEmitter.h" // LexicalScopeEmitter
44 #include "frontend/ModuleSharedContext.h" // ModuleSharedContext
45 #include "frontend/NameAnalysisTypes.h" // PrivateNameKind
46 #include "frontend/NameFunctions.h" // NameFunctions
47 #include "frontend/NameOpEmitter.h" // NameOpEmitter
48 #include "frontend/ObjectEmitter.h" // PropertyEmitter, ObjectEmitter, ClassEmitter
49 #include "frontend/OptionalEmitter.h" // OptionalEmitter
50 #include "frontend/ParseNode.h" // ParseNodeKind, ParseNode and subclasses
51 #include "frontend/Parser.h" // Parser
52 #include "frontend/ParserAtom.h" // ParserAtomsTable, ParserAtom
53 #include "frontend/PrivateOpEmitter.h" // PrivateOpEmitter
54 #include "frontend/PropOpEmitter.h" // PropOpEmitter
55 #include "frontend/SourceNotes.h" // SrcNote, SrcNoteType, SrcNoteWriter
56 #include "frontend/SwitchEmitter.h" // SwitchEmitter
57 #include "frontend/TaggedParserAtomIndexHasher.h" // TaggedParserAtomIndexHasher
58 #include "frontend/TDZCheckCache.h" // TDZCheckCache
59 #include "frontend/TryEmitter.h" // TryEmitter
60 #include "frontend/WhileEmitter.h" // WhileEmitter
61 #include "js/ColumnNumber.h" // JS::LimitedColumnNumberZeroOrigin, JS::ColumnNumberOffset
62 #include "js/friend/ErrorMessages.h" // JSMSG_*
63 #include "js/friend/StackLimits.h" // AutoCheckRecursionLimit
64 #include "util/StringBuffer.h" // StringBuffer
65 #include "vm/BytecodeUtil.h" // JOF_*, IsArgOp, IsLocalOp, SET_UINT24, SET_ICINDEX, BytecodeFallsThrough, BytecodeIsJumpTarget
66 #include "vm/CompletionKind.h" // CompletionKind
67 #include "vm/FunctionPrefixKind.h" // FunctionPrefixKind
68 #include "vm/GeneratorObject.h" // AbstractGeneratorObject
69 #include "vm/Opcodes.h" // JSOp, JSOpLength_*
70 #include "vm/PropMap.h" // SharedPropMap::MaxPropsForNonDictionary
71 #include "vm/Scope.h" // GetScopeDataTrailingNames
72 #include "vm/SharedStencil.h" // ScopeNote
73 #include "vm/ThrowMsgKind.h" // ThrowMsgKind
75 using namespace js;
76 using namespace js::frontend;
78 using mozilla::AssertedCast;
79 using mozilla::AsVariant;
80 using mozilla::DebugOnly;
81 using mozilla::Maybe;
82 using mozilla::Nothing;
83 using mozilla::NumberEqualsInt32;
84 using mozilla::NumberIsInt32;
85 using mozilla::PodCopy;
86 using mozilla::Some;
88 static bool ParseNodeRequiresSpecialLineNumberNotes(ParseNode* pn) {
89 // The few node types listed below are exceptions to the usual
90 // location-source-note-emitting code in BytecodeEmitter::emitTree().
91 // Single-line `while` loops and C-style `for` loops require careful
92 // handling to avoid strange stepping behavior.
93 // Functions usually shouldn't have location information (bug 1431202).
95 ParseNodeKind kind = pn->getKind();
96 return kind == ParseNodeKind::WhileStmt || kind == ParseNodeKind::ForStmt ||
97 kind == ParseNodeKind::Function;
100 static bool NeedsFieldInitializer(ParseNode* member, bool inStaticContext) {
101 // For the purposes of bytecode emission, StaticClassBlocks are treated as if
102 // they were static initializers.
103 return (member->is<StaticClassBlock>() && inStaticContext) ||
104 (member->is<ClassField>() &&
105 member->as<ClassField>().isStatic() == inStaticContext);
108 static bool NeedsAccessorInitializer(ParseNode* member, bool isStatic) {
109 if (isStatic) {
110 return false;
112 return member->is<ClassMethod>() &&
113 member->as<ClassMethod>().name().isKind(ParseNodeKind::PrivateName) &&
114 !member->as<ClassMethod>().isStatic() &&
115 member->as<ClassMethod>().accessorType() != AccessorType::None;
118 static bool ShouldSuppressBreakpointsAndSourceNotes(
119 SharedContext* sc, BytecodeEmitter::EmitterMode emitterMode) {
120 // Suppress for all self-hosting code.
121 if (emitterMode == BytecodeEmitter::EmitterMode::SelfHosting) {
122 return true;
125 // Suppress for synthesized class constructors.
126 if (sc->isFunctionBox()) {
127 FunctionBox* funbox = sc->asFunctionBox();
128 return funbox->isSyntheticFunction() && funbox->isClassConstructor();
131 return false;
134 BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent, FrontendContext* fc,
135 SharedContext* sc,
136 const ErrorReporter& errorReporter,
137 CompilationState& compilationState,
138 EmitterMode emitterMode)
139 : sc(sc),
140 fc(fc),
141 parent(parent),
142 bytecodeSection_(fc, sc->extent().lineno, sc->extent().column),
143 perScriptData_(fc, compilationState),
144 errorReporter_(errorReporter),
145 compilationState(compilationState),
146 suppressBreakpointsAndSourceNotes(
147 ShouldSuppressBreakpointsAndSourceNotes(sc, emitterMode)),
148 emitterMode(emitterMode) {
149 MOZ_ASSERT_IF(parent, fc == parent->fc);
152 BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent, SharedContext* sc)
153 : BytecodeEmitter(parent, parent->fc, sc, parent->errorReporter_,
154 parent->compilationState, parent->emitterMode) {}
156 BytecodeEmitter::BytecodeEmitter(FrontendContext* fc,
157 const EitherParser& parser, SharedContext* sc,
158 CompilationState& compilationState,
159 EmitterMode emitterMode)
160 : BytecodeEmitter(nullptr, fc, sc, parser.errorReporter(), compilationState,
161 emitterMode) {
162 ep_.emplace(parser);
165 void BytecodeEmitter::initFromBodyPosition(TokenPos bodyPosition) {
166 setScriptStartOffsetIfUnset(bodyPosition.begin);
167 setFunctionBodyEndPos(bodyPosition.end);
170 bool BytecodeEmitter::init() {
171 if (!parent) {
172 if (!compilationState.prepareSharedDataStorage(fc)) {
173 return false;
176 return perScriptData_.init(fc);
179 bool BytecodeEmitter::init(TokenPos bodyPosition) {
180 initFromBodyPosition(bodyPosition);
181 return init();
184 template <typename T>
185 T* BytecodeEmitter::findInnermostNestableControl() const {
186 return NestableControl::findNearest<T>(innermostNestableControl);
189 template <typename T, typename Predicate /* (T*) -> bool */>
190 T* BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const {
191 return NestableControl::findNearest<T>(innermostNestableControl, predicate);
194 NameLocation BytecodeEmitter::lookupName(TaggedParserAtomIndex name) {
195 return innermostEmitterScope()->lookup(this, name);
198 void BytecodeEmitter::lookupPrivate(TaggedParserAtomIndex name,
199 NameLocation& loc,
200 Maybe<NameLocation>& brandLoc) {
201 innermostEmitterScope()->lookupPrivate(this, name, loc, brandLoc);
204 Maybe<NameLocation> BytecodeEmitter::locationOfNameBoundInScope(
205 TaggedParserAtomIndex name, EmitterScope* target) {
206 return innermostEmitterScope()->locationBoundInScope(name, target);
209 template <typename T>
210 Maybe<NameLocation> BytecodeEmitter::locationOfNameBoundInScopeType(
211 TaggedParserAtomIndex name, EmitterScope* source) {
212 EmitterScope* aScope = source;
213 while (!aScope->scope(this).is<T>()) {
214 aScope = aScope->enclosingInFrame();
216 return source->locationBoundInScope(name, aScope);
219 bool BytecodeEmitter::markStepBreakpoint() {
220 if (skipBreakpointSrcNotes()) {
221 return true;
224 if (!newSrcNote(SrcNoteType::BreakpointStepSep)) {
225 return false;
228 // We track the location of the most recent separator for use in
229 // markSimpleBreakpoint. Note that this means that the position must already
230 // be set before markStepBreakpoint is called.
231 bytecodeSection().updateSeparatorPosition();
233 return true;
236 bool BytecodeEmitter::markSimpleBreakpoint() {
237 if (skipBreakpointSrcNotes()) {
238 return true;
241 // If a breakable call ends up being the same location as the most recent
242 // expression start, we need to skip marking it breakable in order to avoid
243 // having two breakpoints with the same line/column position.
244 // Note: This assumes that the position for the call has already been set.
245 if (!bytecodeSection().isDuplicateLocation()) {
246 if (!newSrcNote(SrcNoteType::Breakpoint)) {
247 return false;
251 return true;
254 bool BytecodeEmitter::emitCheck(JSOp op, ptrdiff_t delta,
255 BytecodeOffset* offset) {
256 size_t oldLength = bytecodeSection().code().length();
257 *offset = BytecodeOffset(oldLength);
259 size_t newLength = oldLength + size_t(delta);
260 if (MOZ_UNLIKELY(newLength > MaxBytecodeLength)) {
261 ReportAllocationOverflow(fc);
262 return false;
265 if (!bytecodeSection().code().growByUninitialized(delta)) {
266 return false;
269 if (BytecodeOpHasIC(op)) {
270 // Even if every bytecode op is a JOF_IC op and the function has ARGC_LIMIT
271 // arguments, numICEntries cannot overflow.
272 static_assert(MaxBytecodeLength + 1 /* this */ + ARGC_LIMIT <= UINT32_MAX,
273 "numICEntries must not overflow");
274 bytecodeSection().incrementNumICEntries();
277 return true;
280 #ifdef DEBUG
281 bool BytecodeEmitter::checkStrictOrSloppy(JSOp op) {
282 if (IsCheckStrictOp(op) && !sc->strict()) {
283 return false;
285 if (IsCheckSloppyOp(op) && sc->strict()) {
286 return false;
288 return true;
290 #endif
292 bool BytecodeEmitter::emit1(JSOp op) {
293 MOZ_ASSERT(checkStrictOrSloppy(op));
295 BytecodeOffset offset;
296 if (!emitCheck(op, 1, &offset)) {
297 return false;
300 jsbytecode* code = bytecodeSection().code(offset);
301 code[0] = jsbytecode(op);
302 bytecodeSection().updateDepth(op, offset);
303 return true;
306 bool BytecodeEmitter::emit2(JSOp op, uint8_t op1) {
307 MOZ_ASSERT(checkStrictOrSloppy(op));
309 BytecodeOffset offset;
310 if (!emitCheck(op, 2, &offset)) {
311 return false;
314 jsbytecode* code = bytecodeSection().code(offset);
315 code[0] = jsbytecode(op);
316 code[1] = jsbytecode(op1);
317 bytecodeSection().updateDepth(op, offset);
318 return true;
321 bool BytecodeEmitter::emit3(JSOp op, jsbytecode op1, jsbytecode op2) {
322 MOZ_ASSERT(checkStrictOrSloppy(op));
324 /* These should filter through emitVarOp. */
325 MOZ_ASSERT(!IsArgOp(op));
326 MOZ_ASSERT(!IsLocalOp(op));
328 BytecodeOffset offset;
329 if (!emitCheck(op, 3, &offset)) {
330 return false;
333 jsbytecode* code = bytecodeSection().code(offset);
334 code[0] = jsbytecode(op);
335 code[1] = op1;
336 code[2] = op2;
337 bytecodeSection().updateDepth(op, offset);
338 return true;
341 bool BytecodeEmitter::emitN(JSOp op, size_t extra, BytecodeOffset* offset) {
342 MOZ_ASSERT(checkStrictOrSloppy(op));
343 ptrdiff_t length = 1 + ptrdiff_t(extra);
345 BytecodeOffset off;
346 if (!emitCheck(op, length, &off)) {
347 return false;
350 jsbytecode* code = bytecodeSection().code(off);
351 code[0] = jsbytecode(op);
352 /* The remaining |extra| bytes are set by the caller */
355 * Don't updateDepth if op's use-count comes from the immediate
356 * operand yet to be stored in the extra bytes after op.
358 if (CodeSpec(op).nuses >= 0) {
359 bytecodeSection().updateDepth(op, off);
362 if (offset) {
363 *offset = off;
365 return true;
368 bool BytecodeEmitter::emitJumpTargetOp(JSOp op, BytecodeOffset* off) {
369 MOZ_ASSERT(BytecodeIsJumpTarget(op));
371 // Record the current IC-entry index at start of this op.
372 uint32_t numEntries = bytecodeSection().numICEntries();
374 size_t n = GetOpLength(op) - 1;
375 MOZ_ASSERT(GetOpLength(op) >= 1 + ICINDEX_LEN);
377 if (!emitN(op, n, off)) {
378 return false;
381 SET_ICINDEX(bytecodeSection().code(*off), numEntries);
382 return true;
385 bool BytecodeEmitter::emitJumpTarget(JumpTarget* target) {
386 BytecodeOffset off = bytecodeSection().offset();
388 // Alias consecutive jump targets.
389 if (bytecodeSection().lastTargetOffset().valid() &&
390 off == bytecodeSection().lastTargetOffset() +
391 BytecodeOffsetDiff(JSOpLength_JumpTarget)) {
392 target->offset = bytecodeSection().lastTargetOffset();
393 return true;
396 target->offset = off;
397 bytecodeSection().setLastTargetOffset(off);
399 BytecodeOffset opOff;
400 return emitJumpTargetOp(JSOp::JumpTarget, &opOff);
403 bool BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump) {
404 BytecodeOffset offset;
405 if (!emitCheck(op, 5, &offset)) {
406 return false;
409 jsbytecode* code = bytecodeSection().code(offset);
410 code[0] = jsbytecode(op);
411 MOZ_ASSERT(!jump->offset.valid() ||
412 (0 <= jump->offset.value() && jump->offset < offset));
413 jump->push(bytecodeSection().code(BytecodeOffset(0)), offset);
414 bytecodeSection().updateDepth(op, offset);
415 return true;
418 bool BytecodeEmitter::emitJump(JSOp op, JumpList* jump) {
419 if (!emitJumpNoFallthrough(op, jump)) {
420 return false;
422 if (BytecodeFallsThrough(op)) {
423 JumpTarget fallthrough;
424 if (!emitJumpTarget(&fallthrough)) {
425 return false;
428 return true;
431 void BytecodeEmitter::patchJumpsToTarget(JumpList jump, JumpTarget target) {
432 MOZ_ASSERT(
433 !jump.offset.valid() ||
434 (0 <= jump.offset.value() && jump.offset <= bytecodeSection().offset()));
435 MOZ_ASSERT(0 <= target.offset.value() &&
436 target.offset <= bytecodeSection().offset());
437 MOZ_ASSERT_IF(
438 jump.offset.valid() &&
439 target.offset + BytecodeOffsetDiff(4) <= bytecodeSection().offset(),
440 BytecodeIsJumpTarget(JSOp(*bytecodeSection().code(target.offset))));
441 jump.patchAll(bytecodeSection().code(BytecodeOffset(0)), target);
444 bool BytecodeEmitter::emitJumpTargetAndPatch(JumpList jump) {
445 if (!jump.offset.valid()) {
446 return true;
448 JumpTarget target;
449 if (!emitJumpTarget(&target)) {
450 return false;
452 patchJumpsToTarget(jump, target);
453 return true;
456 bool BytecodeEmitter::emitCall(JSOp op, uint16_t argc,
457 const Maybe<uint32_t>& sourceCoordOffset) {
458 if (sourceCoordOffset.isSome()) {
459 if (!updateSourceCoordNotes(*sourceCoordOffset)) {
460 return false;
463 return emit3(op, ARGC_LO(argc), ARGC_HI(argc));
466 bool BytecodeEmitter::emitCall(JSOp op, uint16_t argc, ParseNode* pn) {
467 return emitCall(op, argc, pn ? Some(pn->pn_pos.begin) : Nothing());
470 bool BytecodeEmitter::emitDupAt(unsigned slotFromTop, unsigned count) {
471 MOZ_ASSERT(slotFromTop < unsigned(bytecodeSection().stackDepth()));
472 MOZ_ASSERT(slotFromTop + 1 >= count);
474 if (slotFromTop == 0 && count == 1) {
475 return emit1(JSOp::Dup);
478 if (slotFromTop == 1 && count == 2) {
479 return emit1(JSOp::Dup2);
482 if (slotFromTop >= Bit(24)) {
483 reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
484 return false;
487 for (unsigned i = 0; i < count; i++) {
488 BytecodeOffset off;
489 if (!emitN(JSOp::DupAt, 3, &off)) {
490 return false;
493 jsbytecode* pc = bytecodeSection().code(off);
494 SET_UINT24(pc, slotFromTop);
497 return true;
500 bool BytecodeEmitter::emitPopN(unsigned n) {
501 MOZ_ASSERT(n != 0);
503 if (n == 1) {
504 return emit1(JSOp::Pop);
507 // 2 JSOp::Pop instructions (2 bytes) are shorter than JSOp::PopN (3 bytes).
508 if (n == 2) {
509 return emit1(JSOp::Pop) && emit1(JSOp::Pop);
512 return emitUint16Operand(JSOp::PopN, n);
515 bool BytecodeEmitter::emitPickN(uint8_t n) {
516 MOZ_ASSERT(n != 0);
518 if (n == 1) {
519 return emit1(JSOp::Swap);
522 return emit2(JSOp::Pick, n);
525 bool BytecodeEmitter::emitUnpickN(uint8_t n) {
526 MOZ_ASSERT(n != 0);
528 if (n == 1) {
529 return emit1(JSOp::Swap);
532 return emit2(JSOp::Unpick, n);
535 bool BytecodeEmitter::emitCheckIsObj(CheckIsObjectKind kind) {
536 return emit2(JSOp::CheckIsObj, uint8_t(kind));
539 bool BytecodeEmitter::emitBuiltinObject(BuiltinObjectKind kind) {
540 return emit2(JSOp::BuiltinObject, uint8_t(kind));
543 /* Updates line number notes, not column notes. */
544 bool BytecodeEmitter::updateLineNumberNotes(uint32_t offset) {
545 if (skipLocationSrcNotes()) {
546 return true;
549 const ErrorReporter& er = errorReporter();
550 std::optional<bool> onThisLineStatus =
551 er.isOnThisLine(offset, bytecodeSection().currentLine());
552 if (!onThisLineStatus.has_value()) {
553 er.errorNoOffset(JSMSG_OUT_OF_MEMORY);
554 return false;
557 bool onThisLine = *onThisLineStatus;
559 if (!onThisLine) {
560 unsigned line = er.lineAt(offset);
561 unsigned delta = line - bytecodeSection().currentLine();
563 // If we use a `SetLine` note below, we want it to be relative to the
564 // scripts initial line number for better chance of sharing.
565 unsigned initialLine = sc->extent().lineno;
566 MOZ_ASSERT(line >= initialLine);
569 * Encode any change in the current source line number by using
570 * either several SrcNoteType::NewLine notes or just one
571 * SrcNoteType::SetLine note, whichever consumes less space.
573 * NB: We handle backward line number deltas (possible with for
574 * loops where the update part is emitted after the body, but its
575 * line number is <= any line number in the body) here by letting
576 * unsigned delta_ wrap to a very large number, which triggers a
577 * SrcNoteType::SetLine.
579 bytecodeSection().setCurrentLine(line, offset);
580 if (delta >= SrcNote::SetLine::lengthFor(line, initialLine)) {
581 if (!newSrcNote2(SrcNoteType::SetLine,
582 SrcNote::SetLine::toOperand(line, initialLine))) {
583 return false;
585 } else {
586 do {
587 if (!newSrcNote(SrcNoteType::NewLine)) {
588 return false;
590 } while (--delta != 0);
593 bytecodeSection().updateSeparatorPositionIfPresent();
595 return true;
598 /* Updates the line number and column number information in the source notes. */
599 bool BytecodeEmitter::updateSourceCoordNotes(uint32_t offset) {
600 if (skipLocationSrcNotes()) {
601 return true;
604 if (!updateLineNumberNotes(offset)) {
605 return false;
608 JS::LimitedColumnNumberZeroOrigin columnIndex =
609 errorReporter().columnAt(offset);
611 // Assert colspan is always representable.
612 static_assert((0 - ptrdiff_t(JS::LimitedColumnNumberZeroOrigin::Limit)) >=
613 SrcNote::ColSpan::MinColSpan);
614 static_assert((ptrdiff_t(JS::LimitedColumnNumberZeroOrigin::Limit) - 0) <=
615 SrcNote::ColSpan::MaxColSpan);
617 JS::ColumnNumberOffset colspan = columnIndex - bytecodeSection().lastColumn();
619 if (colspan != JS::ColumnNumberOffset::zero()) {
620 if (lastLineOnlySrcNoteIndex != LastSrcNoteIsNotLineOnly) {
621 MOZ_ASSERT(bytecodeSection().lastColumn() ==
622 JS::LimitedColumnNumberZeroOrigin::zero());
624 const SrcNotesVector& notes = bytecodeSection().notes();
625 SrcNoteType type = notes[lastLineOnlySrcNoteIndex].type();
626 if (type == SrcNoteType::NewLine) {
627 if (!convertLastNewLineToNewLineColumn(columnIndex)) {
628 return false;
630 } else {
631 MOZ_ASSERT(type == SrcNoteType::SetLine);
632 if (!convertLastSetLineToSetLineColumn(columnIndex)) {
633 return false;
636 } else {
637 if (!newSrcNote2(SrcNoteType::ColSpan,
638 SrcNote::ColSpan::toOperand(colspan))) {
639 return false;
642 bytecodeSection().setLastColumn(columnIndex, offset);
643 bytecodeSection().updateSeparatorPositionIfPresent();
645 return true;
648 bool BytecodeEmitter::updateSourceCoordNotesIfNonLiteral(ParseNode* node) {
649 if (node->isLiteral()) {
650 return true;
652 return updateSourceCoordNotes(node->pn_pos.begin);
655 uint32_t BytecodeEmitter::getOffsetForLoop(ParseNode* nextpn) {
656 // Try to give the JSOp::LoopHead the same line number as the next
657 // instruction. nextpn is often a block, in which case the next instruction
658 // typically comes from the first statement inside.
659 if (nextpn->is<LexicalScopeNode>()) {
660 nextpn = nextpn->as<LexicalScopeNode>().scopeBody();
662 if (nextpn->isKind(ParseNodeKind::StatementList)) {
663 if (ParseNode* firstStatement = nextpn->as<ListNode>().head()) {
664 nextpn = firstStatement;
668 return nextpn->pn_pos.begin;
671 bool BytecodeEmitter::emitUint16Operand(JSOp op, uint32_t operand) {
672 MOZ_ASSERT(operand <= UINT16_MAX);
673 if (!emit3(op, UINT16_LO(operand), UINT16_HI(operand))) {
674 return false;
676 return true;
679 bool BytecodeEmitter::emitUint32Operand(JSOp op, uint32_t operand) {
680 BytecodeOffset off;
681 if (!emitN(op, 4, &off)) {
682 return false;
684 SET_UINT32(bytecodeSection().code(off), operand);
685 return true;
688 bool BytecodeEmitter::emitGoto(NestableControl* target, GotoKind kind) {
689 NonLocalExitControl nle(this, kind == GotoKind::Continue
690 ? NonLocalExitKind::Continue
691 : NonLocalExitKind::Break);
692 return nle.emitNonLocalJump(target);
695 AbstractScopePtr BytecodeEmitter::innermostScope() const {
696 return innermostEmitterScope()->scope(this);
699 ScopeIndex BytecodeEmitter::innermostScopeIndex() const {
700 return *innermostEmitterScope()->scopeIndex(this);
703 bool BytecodeEmitter::emitGCIndexOp(JSOp op, GCThingIndex index) {
704 MOZ_ASSERT(checkStrictOrSloppy(op));
706 constexpr size_t OpLength = 1 + GCTHING_INDEX_LEN;
707 MOZ_ASSERT(GetOpLength(op) == OpLength);
709 BytecodeOffset offset;
710 if (!emitCheck(op, OpLength, &offset)) {
711 return false;
714 jsbytecode* code = bytecodeSection().code(offset);
715 code[0] = jsbytecode(op);
716 SET_GCTHING_INDEX(code, index);
717 bytecodeSection().updateDepth(op, offset);
718 return true;
721 bool BytecodeEmitter::emitAtomOp(JSOp op, TaggedParserAtomIndex atom) {
722 MOZ_ASSERT(atom);
724 // .generator lookups should be emitted as JSOp::GetAliasedVar instead of
725 // JSOp::GetName etc, to bypass |with| objects on the scope chain.
726 // It's safe to emit .this lookups though because |with| objects skip
727 // those.
728 MOZ_ASSERT_IF(op == JSOp::GetName || op == JSOp::GetGName,
729 atom != TaggedParserAtomIndex::WellKnown::dot_generator_());
731 GCThingIndex index;
732 if (!makeAtomIndex(atom, ParserAtom::Atomize::Yes, &index)) {
733 return false;
736 return emitAtomOp(op, index);
739 bool BytecodeEmitter::emitAtomOp(JSOp op, GCThingIndex atomIndex) {
740 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
741 #ifdef DEBUG
742 auto atom = perScriptData().gcThingList().getAtom(atomIndex);
743 MOZ_ASSERT(compilationState.parserAtoms.isInstantiatedAsJSAtom(atom));
744 #endif
745 return emitGCIndexOp(op, atomIndex);
748 bool BytecodeEmitter::emitStringOp(JSOp op, TaggedParserAtomIndex atom) {
749 MOZ_ASSERT(atom);
750 GCThingIndex index;
751 if (!makeAtomIndex(atom, ParserAtom::Atomize::No, &index)) {
752 return false;
755 return emitStringOp(op, index);
758 bool BytecodeEmitter::emitStringOp(JSOp op, GCThingIndex atomIndex) {
759 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_STRING);
760 return emitGCIndexOp(op, atomIndex);
763 bool BytecodeEmitter::emitInternedScopeOp(GCThingIndex index, JSOp op) {
764 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_SCOPE);
765 MOZ_ASSERT(index < perScriptData().gcThingList().length());
766 return emitGCIndexOp(op, index);
769 bool BytecodeEmitter::emitInternedObjectOp(GCThingIndex index, JSOp op) {
770 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
771 MOZ_ASSERT(index < perScriptData().gcThingList().length());
772 return emitGCIndexOp(op, index);
775 bool BytecodeEmitter::emitRegExp(GCThingIndex index) {
776 return emitGCIndexOp(JSOp::RegExp, index);
779 bool BytecodeEmitter::emitLocalOp(JSOp op, uint32_t slot) {
780 MOZ_ASSERT(JOF_OPTYPE(op) != JOF_ENVCOORD);
781 MOZ_ASSERT(IsLocalOp(op));
783 BytecodeOffset off;
784 if (!emitN(op, LOCALNO_LEN, &off)) {
785 return false;
788 SET_LOCALNO(bytecodeSection().code(off), slot);
789 return true;
792 bool BytecodeEmitter::emitArgOp(JSOp op, uint16_t slot) {
793 MOZ_ASSERT(IsArgOp(op));
794 BytecodeOffset off;
795 if (!emitN(op, ARGNO_LEN, &off)) {
796 return false;
799 SET_ARGNO(bytecodeSection().code(off), slot);
800 return true;
803 bool BytecodeEmitter::emitEnvCoordOp(JSOp op, EnvironmentCoordinate ec) {
804 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ENVCOORD ||
805 JOF_OPTYPE(op) == JOF_DEBUGCOORD);
807 constexpr size_t N = ENVCOORD_HOPS_LEN + ENVCOORD_SLOT_LEN;
808 MOZ_ASSERT(GetOpLength(op) == 1 + N);
810 BytecodeOffset off;
811 if (!emitN(op, N, &off)) {
812 return false;
815 jsbytecode* pc = bytecodeSection().code(off);
816 SET_ENVCOORD_HOPS(pc, ec.hops());
817 pc += ENVCOORD_HOPS_LEN;
818 SET_ENVCOORD_SLOT(pc, ec.slot());
819 pc += ENVCOORD_SLOT_LEN;
820 return true;
823 JSOp BytecodeEmitter::strictifySetNameOp(JSOp op) {
824 switch (op) {
825 case JSOp::SetName:
826 if (sc->strict()) {
827 op = JSOp::StrictSetName;
829 break;
830 case JSOp::SetGName:
831 if (sc->strict()) {
832 op = JSOp::StrictSetGName;
834 break;
835 default:;
837 return op;
840 bool BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) {
841 AutoCheckRecursionLimit recursion(fc);
842 if (!recursion.check(fc)) {
843 return false;
846 restart:
848 switch (pn->getKind()) {
849 // Trivial cases with no side effects.
850 case ParseNodeKind::EmptyStmt:
851 case ParseNodeKind::TrueExpr:
852 case ParseNodeKind::FalseExpr:
853 case ParseNodeKind::NullExpr:
854 case ParseNodeKind::RawUndefinedExpr:
855 case ParseNodeKind::Elision:
856 case ParseNodeKind::Generator:
857 MOZ_ASSERT(pn->is<NullaryNode>());
858 *answer = false;
859 return true;
861 case ParseNodeKind::ObjectPropertyName:
862 case ParseNodeKind::PrivateName: // no side effects, unlike
863 // ParseNodeKind::Name
864 case ParseNodeKind::StringExpr:
865 case ParseNodeKind::TemplateStringExpr:
866 MOZ_ASSERT(pn->is<NameNode>());
867 *answer = false;
868 return true;
870 case ParseNodeKind::RegExpExpr:
871 MOZ_ASSERT(pn->is<RegExpLiteral>());
872 *answer = false;
873 return true;
875 case ParseNodeKind::NumberExpr:
876 MOZ_ASSERT(pn->is<NumericLiteral>());
877 *answer = false;
878 return true;
880 case ParseNodeKind::BigIntExpr:
881 MOZ_ASSERT(pn->is<BigIntLiteral>());
882 *answer = false;
883 return true;
885 // |this| can throw in derived class constructors, including nested arrow
886 // functions or eval.
887 case ParseNodeKind::ThisExpr:
888 MOZ_ASSERT(pn->is<UnaryNode>());
889 *answer = sc->needsThisTDZChecks();
890 return true;
892 // |new.target| doesn't have any side-effects.
893 case ParseNodeKind::NewTargetExpr: {
894 MOZ_ASSERT(pn->is<NewTargetNode>());
895 *answer = false;
896 return true;
899 // Trivial binary nodes with more token pos holders.
900 case ParseNodeKind::ImportMetaExpr: {
901 MOZ_ASSERT(pn->as<BinaryNode>().left()->isKind(ParseNodeKind::PosHolder));
902 MOZ_ASSERT(
903 pn->as<BinaryNode>().right()->isKind(ParseNodeKind::PosHolder));
904 *answer = false;
905 return true;
908 case ParseNodeKind::BreakStmt:
909 MOZ_ASSERT(pn->is<BreakStatement>());
910 *answer = true;
911 return true;
913 case ParseNodeKind::ContinueStmt:
914 MOZ_ASSERT(pn->is<ContinueStatement>());
915 *answer = true;
916 return true;
918 case ParseNodeKind::DebuggerStmt:
919 MOZ_ASSERT(pn->is<DebuggerStatement>());
920 *answer = true;
921 return true;
923 // Watch out for getters!
924 case ParseNodeKind::OptionalDotExpr:
925 case ParseNodeKind::DotExpr:
926 MOZ_ASSERT(pn->is<BinaryNode>());
927 *answer = true;
928 return true;
930 // Unary cases with side effects only if the child has them.
931 case ParseNodeKind::TypeOfExpr:
932 case ParseNodeKind::VoidExpr:
933 case ParseNodeKind::NotExpr:
934 return checkSideEffects(pn->as<UnaryNode>().kid(), answer);
936 // Even if the name expression is effect-free, performing ToPropertyKey on
937 // it might not be effect-free:
939 // RegExp.prototype.toString = () => { throw 42; };
940 // ({ [/regex/]: 0 }); // ToPropertyKey(/regex/) throws 42
942 // function Q() {
943 // ({ [new.target]: 0 });
944 // }
945 // Q.toString = () => { throw 17; };
946 // new Q; // new.target will be Q, ToPropertyKey(Q) throws 17
947 case ParseNodeKind::ComputedName:
948 MOZ_ASSERT(pn->is<UnaryNode>());
949 *answer = true;
950 return true;
952 // Looking up or evaluating the associated name could throw.
953 case ParseNodeKind::TypeOfNameExpr:
954 MOZ_ASSERT(pn->is<UnaryNode>());
955 *answer = true;
956 return true;
958 // This unary case has side effects on the enclosing object, sure. But
959 // that's not the question this function answers: it's whether the
960 // operation may have a side effect on something *other* than the result
961 // of the overall operation in which it's embedded. The answer to that
962 // is no, because an object literal having a mutated prototype only
963 // produces a value, without affecting anything else.
964 case ParseNodeKind::MutateProto:
965 return checkSideEffects(pn->as<UnaryNode>().kid(), answer);
967 // Unary cases with obvious side effects.
968 case ParseNodeKind::PreIncrementExpr:
969 case ParseNodeKind::PostIncrementExpr:
970 case ParseNodeKind::PreDecrementExpr:
971 case ParseNodeKind::PostDecrementExpr:
972 case ParseNodeKind::ThrowStmt:
973 MOZ_ASSERT(pn->is<UnaryNode>());
974 *answer = true;
975 return true;
977 // These might invoke valueOf/toString, even with a subexpression without
978 // side effects! Consider |+{ valueOf: null, toString: null }|.
979 case ParseNodeKind::BitNotExpr:
980 case ParseNodeKind::PosExpr:
981 case ParseNodeKind::NegExpr:
982 MOZ_ASSERT(pn->is<UnaryNode>());
983 *answer = true;
984 return true;
986 // This invokes the (user-controllable) iterator protocol.
987 case ParseNodeKind::Spread:
988 MOZ_ASSERT(pn->is<UnaryNode>());
989 *answer = true;
990 return true;
992 case ParseNodeKind::InitialYield:
993 case ParseNodeKind::YieldStarExpr:
994 case ParseNodeKind::YieldExpr:
995 case ParseNodeKind::AwaitExpr:
996 MOZ_ASSERT(pn->is<UnaryNode>());
997 *answer = true;
998 return true;
1000 // Deletion generally has side effects, even if isolated cases have none.
1001 case ParseNodeKind::DeleteNameExpr:
1002 case ParseNodeKind::DeletePropExpr:
1003 case ParseNodeKind::DeleteElemExpr:
1004 case ParseNodeKind::DeleteOptionalChainExpr:
1005 MOZ_ASSERT(pn->is<UnaryNode>());
1006 *answer = true;
1007 return true;
1009 // Deletion of a non-Reference expression has side effects only through
1010 // evaluating the expression.
1011 case ParseNodeKind::DeleteExpr: {
1012 ParseNode* expr = pn->as<UnaryNode>().kid();
1013 return checkSideEffects(expr, answer);
1016 case ParseNodeKind::ExpressionStmt:
1017 return checkSideEffects(pn->as<UnaryNode>().kid(), answer);
1019 // Binary cases with obvious side effects.
1020 case ParseNodeKind::InitExpr:
1021 *answer = true;
1022 return true;
1024 case ParseNodeKind::AssignExpr:
1025 case ParseNodeKind::AddAssignExpr:
1026 case ParseNodeKind::SubAssignExpr:
1027 case ParseNodeKind::CoalesceAssignExpr:
1028 case ParseNodeKind::OrAssignExpr:
1029 case ParseNodeKind::AndAssignExpr:
1030 case ParseNodeKind::BitOrAssignExpr:
1031 case ParseNodeKind::BitXorAssignExpr:
1032 case ParseNodeKind::BitAndAssignExpr:
1033 case ParseNodeKind::LshAssignExpr:
1034 case ParseNodeKind::RshAssignExpr:
1035 case ParseNodeKind::UrshAssignExpr:
1036 case ParseNodeKind::MulAssignExpr:
1037 case ParseNodeKind::DivAssignExpr:
1038 case ParseNodeKind::ModAssignExpr:
1039 case ParseNodeKind::PowAssignExpr:
1040 MOZ_ASSERT(pn->is<AssignmentNode>());
1041 *answer = true;
1042 return true;
1044 case ParseNodeKind::SetThis:
1045 MOZ_ASSERT(pn->is<BinaryNode>());
1046 *answer = true;
1047 return true;
1049 case ParseNodeKind::StatementList:
1050 // Strict equality operations and short circuit operators are well-behaved
1051 // and perform no conversions.
1052 case ParseNodeKind::CoalesceExpr:
1053 case ParseNodeKind::OrExpr:
1054 case ParseNodeKind::AndExpr:
1055 case ParseNodeKind::StrictEqExpr:
1056 case ParseNodeKind::StrictNeExpr:
1057 // Any subexpression of a comma expression could be effectful.
1058 case ParseNodeKind::CommaExpr:
1059 MOZ_ASSERT(!pn->as<ListNode>().empty());
1060 [[fallthrough]];
1061 // Subcomponents of a literal may be effectful.
1062 case ParseNodeKind::ArrayExpr:
1063 case ParseNodeKind::ObjectExpr:
1064 for (ParseNode* item : pn->as<ListNode>().contents()) {
1065 if (!checkSideEffects(item, answer)) {
1066 return false;
1068 if (*answer) {
1069 return true;
1072 return true;
1074 #ifdef ENABLE_RECORD_TUPLE
1075 case ParseNodeKind::RecordExpr:
1076 case ParseNodeKind::TupleExpr:
1077 MOZ_CRASH("Record and Tuple are not supported yet");
1078 #endif
1080 #ifdef ENABLE_DECORATORS
1081 case ParseNodeKind::DecoratorList:
1082 MOZ_CRASH("Decorators are not supported yet");
1083 #endif
1085 // Most other binary operations (parsed as lists in SpiderMonkey) may
1086 // perform conversions triggering side effects. Math operations perform
1087 // ToNumber and may fail invoking invalid user-defined toString/valueOf:
1088 // |5 < { toString: null }|. |instanceof| throws if provided a
1089 // non-object constructor: |null instanceof null|. |in| throws if given
1090 // a non-object RHS: |5 in null|.
1091 case ParseNodeKind::BitOrExpr:
1092 case ParseNodeKind::BitXorExpr:
1093 case ParseNodeKind::BitAndExpr:
1094 case ParseNodeKind::EqExpr:
1095 case ParseNodeKind::NeExpr:
1096 case ParseNodeKind::LtExpr:
1097 case ParseNodeKind::LeExpr:
1098 case ParseNodeKind::GtExpr:
1099 case ParseNodeKind::GeExpr:
1100 case ParseNodeKind::InstanceOfExpr:
1101 case ParseNodeKind::InExpr:
1102 case ParseNodeKind::PrivateInExpr:
1103 case ParseNodeKind::LshExpr:
1104 case ParseNodeKind::RshExpr:
1105 case ParseNodeKind::UrshExpr:
1106 case ParseNodeKind::AddExpr:
1107 case ParseNodeKind::SubExpr:
1108 case ParseNodeKind::MulExpr:
1109 case ParseNodeKind::DivExpr:
1110 case ParseNodeKind::ModExpr:
1111 case ParseNodeKind::PowExpr:
1112 MOZ_ASSERT(pn->as<ListNode>().count() >= 2);
1113 *answer = true;
1114 return true;
1116 case ParseNodeKind::PropertyDefinition:
1117 case ParseNodeKind::Case: {
1118 BinaryNode* node = &pn->as<BinaryNode>();
1119 if (!checkSideEffects(node->left(), answer)) {
1120 return false;
1122 if (*answer) {
1123 return true;
1125 return checkSideEffects(node->right(), answer);
1128 // More getters.
1129 case ParseNodeKind::ElemExpr:
1130 case ParseNodeKind::OptionalElemExpr:
1131 MOZ_ASSERT(pn->is<BinaryNode>());
1132 *answer = true;
1133 return true;
1135 // Throws if the operand is not of the right class. Can also call a private
1136 // getter.
1137 case ParseNodeKind::PrivateMemberExpr:
1138 case ParseNodeKind::OptionalPrivateMemberExpr:
1139 *answer = true;
1140 return true;
1142 // These affect visible names in this code, or in other code.
1143 case ParseNodeKind::ImportDecl:
1144 case ParseNodeKind::ExportFromStmt:
1145 case ParseNodeKind::ExportDefaultStmt:
1146 MOZ_ASSERT(pn->is<BinaryNode>());
1147 *answer = true;
1148 return true;
1150 // Likewise.
1151 case ParseNodeKind::ExportStmt:
1152 MOZ_ASSERT(pn->is<UnaryNode>());
1153 *answer = true;
1154 return true;
1156 case ParseNodeKind::CallImportExpr:
1157 case ParseNodeKind::CallImportSpec:
1158 MOZ_ASSERT(pn->is<BinaryNode>());
1159 *answer = true;
1160 return true;
1162 // Every part of a loop might be effect-free, but looping infinitely *is*
1163 // an effect. (Language lawyer trivia: C++ says threads can be assumed
1164 // to exit or have side effects, C++14 [intro.multithread]p27, so a C++
1165 // implementation's equivalent of the below could set |*answer = false;|
1166 // if all loop sub-nodes set |*answer = false|!)
1167 case ParseNodeKind::DoWhileStmt:
1168 case ParseNodeKind::WhileStmt:
1169 case ParseNodeKind::ForStmt:
1170 MOZ_ASSERT(pn->is<BinaryNode>());
1171 *answer = true;
1172 return true;
1174 // Declarations affect the name set of the relevant scope.
1175 case ParseNodeKind::VarStmt:
1176 case ParseNodeKind::ConstDecl:
1177 case ParseNodeKind::LetDecl:
1178 MOZ_ASSERT(pn->is<ListNode>());
1179 *answer = true;
1180 return true;
1182 case ParseNodeKind::IfStmt:
1183 case ParseNodeKind::ConditionalExpr: {
1184 TernaryNode* node = &pn->as<TernaryNode>();
1185 if (!checkSideEffects(node->kid1(), answer)) {
1186 return false;
1188 if (*answer) {
1189 return true;
1191 if (!checkSideEffects(node->kid2(), answer)) {
1192 return false;
1194 if (*answer) {
1195 return true;
1197 if ((pn = node->kid3())) {
1198 goto restart;
1200 return true;
1203 // Function calls can invoke non-local code.
1204 case ParseNodeKind::NewExpr:
1205 case ParseNodeKind::CallExpr:
1206 case ParseNodeKind::OptionalCallExpr:
1207 case ParseNodeKind::TaggedTemplateExpr:
1208 case ParseNodeKind::SuperCallExpr:
1209 MOZ_ASSERT(pn->is<BinaryNode>());
1210 *answer = true;
1211 return true;
1213 // Function arg lists can contain arbitrary expressions. Technically
1214 // this only causes side-effects if one of the arguments does, but since
1215 // the call being made will always trigger side-effects, it isn't needed.
1216 case ParseNodeKind::Arguments:
1217 MOZ_ASSERT(pn->is<ListNode>());
1218 *answer = true;
1219 return true;
1221 case ParseNodeKind::OptionalChain:
1222 MOZ_ASSERT(pn->is<UnaryNode>());
1223 *answer = true;
1224 return true;
1226 // Classes typically introduce names. Even if no name is introduced,
1227 // the heritage and/or class body (through computed property names)
1228 // usually have effects.
1229 case ParseNodeKind::ClassDecl:
1230 MOZ_ASSERT(pn->is<ClassNode>());
1231 *answer = true;
1232 return true;
1234 // |with| calls |ToObject| on its expression and so throws if that value
1235 // is null/undefined.
1236 case ParseNodeKind::WithStmt:
1237 MOZ_ASSERT(pn->is<BinaryNode>());
1238 *answer = true;
1239 return true;
1241 case ParseNodeKind::ReturnStmt:
1242 MOZ_ASSERT(pn->is<BinaryNode>());
1243 *answer = true;
1244 return true;
1246 case ParseNodeKind::Name:
1247 MOZ_ASSERT(pn->is<NameNode>());
1248 *answer = true;
1249 return true;
1251 // Shorthands could trigger getters: the |x| in the object literal in
1252 // |with ({ get x() { throw 42; } }) ({ x });|, for example, triggers
1253 // one. (Of course, it isn't necessary to use |with| for a shorthand to
1254 // trigger a getter.)
1255 case ParseNodeKind::Shorthand:
1256 MOZ_ASSERT(pn->is<BinaryNode>());
1257 *answer = true;
1258 return true;
1260 case ParseNodeKind::Function:
1261 MOZ_ASSERT(pn->is<FunctionNode>());
1263 * A named function, contrary to ES3, is no longer effectful, because
1264 * we bind its name lexically (using JSOp::Callee) instead of creating
1265 * an Object instance and binding a readonly, permanent property in it
1266 * (the object and binding can be detected and hijacked or captured).
1267 * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
1269 *answer = false;
1270 return true;
1272 case ParseNodeKind::Module:
1273 *answer = false;
1274 return true;
1276 case ParseNodeKind::TryStmt: {
1277 TryNode* tryNode = &pn->as<TryNode>();
1278 if (!checkSideEffects(tryNode->body(), answer)) {
1279 return false;
1281 if (*answer) {
1282 return true;
1284 if (LexicalScopeNode* catchScope = tryNode->catchScope()) {
1285 if (!checkSideEffects(catchScope, answer)) {
1286 return false;
1288 if (*answer) {
1289 return true;
1292 if (ParseNode* finallyBlock = tryNode->finallyBlock()) {
1293 if (!checkSideEffects(finallyBlock, answer)) {
1294 return false;
1297 return true;
1300 case ParseNodeKind::Catch: {
1301 BinaryNode* catchClause = &pn->as<BinaryNode>();
1302 if (ParseNode* name = catchClause->left()) {
1303 if (!checkSideEffects(name, answer)) {
1304 return false;
1306 if (*answer) {
1307 return true;
1310 return checkSideEffects(catchClause->right(), answer);
1313 case ParseNodeKind::SwitchStmt: {
1314 SwitchStatement* switchStmt = &pn->as<SwitchStatement>();
1315 if (!checkSideEffects(&switchStmt->discriminant(), answer)) {
1316 return false;
1318 return *answer ||
1319 checkSideEffects(&switchStmt->lexicalForCaseList(), answer);
1322 case ParseNodeKind::LabelStmt:
1323 return checkSideEffects(pn->as<LabeledStatement>().statement(), answer);
1325 case ParseNodeKind::LexicalScope:
1326 return checkSideEffects(pn->as<LexicalScopeNode>().scopeBody(), answer);
1328 // We could methodically check every interpolated expression, but it's
1329 // probably not worth the trouble. Treat template strings as effect-free
1330 // only if they don't contain any substitutions.
1331 case ParseNodeKind::TemplateStringListExpr: {
1332 ListNode* list = &pn->as<ListNode>();
1333 MOZ_ASSERT(!list->empty());
1334 MOZ_ASSERT((list->count() % 2) == 1,
1335 "template strings must alternate template and substitution "
1336 "parts");
1337 *answer = list->count() > 1;
1338 return true;
1341 // This should be unreachable but is left as-is for now.
1342 case ParseNodeKind::ParamsBody:
1343 *answer = true;
1344 return true;
1346 case ParseNodeKind::ForIn: // by ParseNodeKind::For
1347 case ParseNodeKind::ForOf: // by ParseNodeKind::For
1348 case ParseNodeKind::ForHead: // by ParseNodeKind::For
1349 case ParseNodeKind::DefaultConstructor: // by ParseNodeKind::ClassDecl
1350 case ParseNodeKind::ClassBodyScope: // by ParseNodeKind::ClassDecl
1351 case ParseNodeKind::ClassMethod: // by ParseNodeKind::ClassDecl
1352 case ParseNodeKind::ClassField: // by ParseNodeKind::ClassDecl
1353 case ParseNodeKind::ClassNames: // by ParseNodeKind::ClassDecl
1354 case ParseNodeKind::StaticClassBlock: // by ParseNodeKind::ClassDecl
1355 case ParseNodeKind::ClassMemberList: // by ParseNodeKind::ClassDecl
1356 case ParseNodeKind::ImportSpecList: // by ParseNodeKind::Import
1357 case ParseNodeKind::ImportSpec: // by ParseNodeKind::Import
1358 case ParseNodeKind::ImportNamespaceSpec: // by ParseNodeKind::Import
1359 case ParseNodeKind::ImportAssertion: // by ParseNodeKind::Import
1360 case ParseNodeKind::ImportAssertionList: // by ParseNodeKind::Import
1361 case ParseNodeKind::ImportModuleRequest: // by ParseNodeKind::Import
1362 case ParseNodeKind::ExportBatchSpecStmt: // by ParseNodeKind::Export
1363 case ParseNodeKind::ExportSpecList: // by ParseNodeKind::Export
1364 case ParseNodeKind::ExportSpec: // by ParseNodeKind::Export
1365 case ParseNodeKind::ExportNamespaceSpec: // by ParseNodeKind::Export
1366 case ParseNodeKind::CallSiteObj: // by ParseNodeKind::TaggedTemplate
1367 case ParseNodeKind::PosHolder: // by ParseNodeKind::NewTarget
1368 case ParseNodeKind::SuperBase: // by ParseNodeKind::Elem and others
1369 case ParseNodeKind::PropertyNameExpr: // by ParseNodeKind::Dot
1370 MOZ_CRASH("handled by parent nodes");
1372 case ParseNodeKind::LastUnused:
1373 case ParseNodeKind::Limit:
1374 MOZ_CRASH("invalid node kind");
1377 MOZ_CRASH(
1378 "invalid, unenumerated ParseNodeKind value encountered in "
1379 "BytecodeEmitter::checkSideEffects");
1382 bool BytecodeEmitter::isInLoop() {
1383 return findInnermostNestableControl<LoopControl>();
1386 bool BytecodeEmitter::checkSingletonContext() {
1387 MOZ_ASSERT_IF(sc->treatAsRunOnce(), sc->isTopLevelContext());
1388 return sc->treatAsRunOnce() && !isInLoop();
1391 bool BytecodeEmitter::needsImplicitThis() {
1392 // Short-circuit if there is an enclosing 'with' scope.
1393 if (sc->inWith()) {
1394 return true;
1397 // Otherwise see if the current point is under a 'with'.
1398 for (EmitterScope* es = innermostEmitterScope(); es;
1399 es = es->enclosingInFrame()) {
1400 if (es->scope(this).kind() == ScopeKind::With) {
1401 return true;
1405 return false;
1408 size_t BytecodeEmitter::countThisEnvironmentHops() {
1409 unsigned numHops = 0;
1411 for (BytecodeEmitter* current = this; current; current = current->parent) {
1412 for (EmitterScope* es = current->innermostEmitterScope(); es;
1413 es = es->enclosingInFrame()) {
1414 if (es->scope(current).is<FunctionScope>()) {
1415 if (!es->scope(current).isArrow()) {
1416 // The Parser is responsible for marking the environment as either
1417 // closed-over or used-by-eval which ensure that is must exist.
1418 MOZ_ASSERT(es->scope(current).hasEnvironment());
1419 return numHops;
1422 if (es->scope(current).hasEnvironment()) {
1423 numHops++;
1428 // The "this" environment exists outside of the compilation, but the
1429 // `ScopeContext` recorded the number of additional hops needed, so add
1430 // those in now.
1431 MOZ_ASSERT(sc->allowSuperProperty());
1432 numHops += compilationState.scopeContext.enclosingThisEnvironmentHops;
1433 return numHops;
1436 bool BytecodeEmitter::emitThisEnvironmentCallee() {
1437 // Get the innermost enclosing function that has a |this| binding.
1439 // Directly load callee from the frame if possible.
1440 if (sc->isFunctionBox() && !sc->asFunctionBox()->isArrow()) {
1441 return emit1(JSOp::Callee);
1444 // We have to load the callee from the environment chain.
1445 size_t numHops = countThisEnvironmentHops();
1447 static_assert(
1448 ENVCOORD_HOPS_LIMIT - 1 <= UINT8_MAX,
1449 "JSOp::EnvCallee operand size should match ENVCOORD_HOPS_LIMIT");
1451 MOZ_ASSERT(numHops < ENVCOORD_HOPS_LIMIT - 1);
1453 return emit2(JSOp::EnvCallee, numHops);
1456 bool BytecodeEmitter::emitSuperBase() {
1457 if (!emitThisEnvironmentCallee()) {
1458 return false;
1461 return emit1(JSOp::SuperBase);
1464 void BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...) {
1465 uint32_t offset = pn ? pn->pn_pos.begin : *scriptStartOffset;
1467 va_list args;
1468 va_start(args, errorNumber);
1470 errorReporter().errorWithNotesAtVA(nullptr, AsVariant(offset), errorNumber,
1471 &args);
1473 va_end(args);
1476 void BytecodeEmitter::reportError(uint32_t offset, unsigned errorNumber, ...) {
1477 va_list args;
1478 va_start(args, errorNumber);
1480 errorReporter().errorWithNotesAtVA(nullptr, AsVariant(offset), errorNumber,
1481 &args);
1483 va_end(args);
1486 bool BytecodeEmitter::addObjLiteralData(ObjLiteralWriter& writer,
1487 GCThingIndex* outIndex) {
1488 if (!writer.checkForDuplicatedNames(fc)) {
1489 return false;
1492 size_t len = writer.getCode().size();
1493 auto* code = compilationState.alloc.newArrayUninitialized<uint8_t>(len);
1494 if (!code) {
1495 js::ReportOutOfMemory(fc);
1496 return false;
1498 memcpy(code, writer.getCode().data(), len);
1500 ObjLiteralIndex objIndex(compilationState.objLiteralData.length());
1501 if (uint32_t(objIndex) >= TaggedScriptThingIndex::IndexLimit) {
1502 ReportAllocationOverflow(fc);
1503 return false;
1505 if (!compilationState.objLiteralData.emplaceBack(code, len, writer.getKind(),
1506 writer.getFlags(),
1507 writer.getPropertyCount())) {
1508 js::ReportOutOfMemory(fc);
1509 return false;
1512 return perScriptData().gcThingList().append(objIndex, outIndex);
1515 bool BytecodeEmitter::emitPrepareIteratorResult() {
1516 constexpr JSOp op = JSOp::NewObject;
1518 ObjLiteralWriter writer;
1519 writer.beginShape(op);
1521 writer.setPropNameNoDuplicateCheck(parserAtoms(),
1522 TaggedParserAtomIndex::WellKnown::value());
1523 if (!writer.propWithUndefinedValue(fc)) {
1524 return false;
1526 writer.setPropNameNoDuplicateCheck(parserAtoms(),
1527 TaggedParserAtomIndex::WellKnown::done());
1528 if (!writer.propWithUndefinedValue(fc)) {
1529 return false;
1532 GCThingIndex shape;
1533 if (!addObjLiteralData(writer, &shape)) {
1534 return false;
1537 return emitGCIndexOp(op, shape);
1540 bool BytecodeEmitter::emitFinishIteratorResult(bool done) {
1541 if (!emitAtomOp(JSOp::InitProp, TaggedParserAtomIndex::WellKnown::value())) {
1542 return false;
1544 if (!emit1(done ? JSOp::True : JSOp::False)) {
1545 return false;
1547 if (!emitAtomOp(JSOp::InitProp, TaggedParserAtomIndex::WellKnown::done())) {
1548 return false;
1550 return true;
1553 bool BytecodeEmitter::emitGetNameAtLocation(TaggedParserAtomIndex name,
1554 const NameLocation& loc) {
1555 NameOpEmitter noe(this, name, loc, NameOpEmitter::Kind::Get);
1556 if (!noe.emitGet()) {
1557 return false;
1560 return true;
1563 bool BytecodeEmitter::emitGetName(NameNode* name) {
1564 MOZ_ASSERT(name->isKind(ParseNodeKind::Name));
1566 return emitGetName(name->name());
1569 bool BytecodeEmitter::emitGetPrivateName(NameNode* name) {
1570 MOZ_ASSERT(name->isKind(ParseNodeKind::PrivateName));
1571 return emitGetPrivateName(name->name());
1574 bool BytecodeEmitter::emitGetPrivateName(TaggedParserAtomIndex nameAtom) {
1575 // The parser ensures the private name is present on the environment chain,
1576 // but its location can be Dynamic or Global when emitting debugger
1577 // eval-in-frame code.
1578 NameLocation location = lookupName(nameAtom);
1579 MOZ_ASSERT(location.kind() == NameLocation::Kind::FrameSlot ||
1580 location.kind() == NameLocation::Kind::EnvironmentCoordinate ||
1581 location.kind() == NameLocation::Kind::Dynamic ||
1582 location.kind() == NameLocation::Kind::Global);
1584 return emitGetNameAtLocation(nameAtom, location);
1587 bool BytecodeEmitter::emitTDZCheckIfNeeded(TaggedParserAtomIndex name,
1588 const NameLocation& loc,
1589 ValueIsOnStack isOnStack) {
1590 // Dynamic accesses have TDZ checks built into their VM code and should
1591 // never emit explicit TDZ checks.
1592 MOZ_ASSERT(loc.hasKnownSlot());
1593 MOZ_ASSERT(loc.isLexical() || loc.isPrivateMethod() || loc.isSynthetic());
1595 // Private names are implemented as lexical bindings, but it's just an
1596 // implementation detail. Per spec there's no TDZ check when using them.
1597 if (parserAtoms().isPrivateName(name)) {
1598 return true;
1601 Maybe<MaybeCheckTDZ> check =
1602 innermostTDZCheckCache->needsTDZCheck(this, name);
1603 if (!check) {
1604 return false;
1607 // We've already emitted a check in this basic block.
1608 if (*check == DontCheckTDZ) {
1609 return true;
1612 // If the value is not on the stack, we have to load it first.
1613 if (isOnStack == ValueIsOnStack::No) {
1614 if (loc.kind() == NameLocation::Kind::FrameSlot) {
1615 if (!emitLocalOp(JSOp::GetLocal, loc.frameSlot())) {
1616 return false;
1618 } else {
1619 if (!emitEnvCoordOp(JSOp::GetAliasedVar, loc.environmentCoordinate())) {
1620 return false;
1625 // Emit the lexical check.
1626 if (loc.kind() == NameLocation::Kind::FrameSlot) {
1627 if (!emitLocalOp(JSOp::CheckLexical, loc.frameSlot())) {
1628 return false;
1630 } else {
1631 if (!emitEnvCoordOp(JSOp::CheckAliasedLexical,
1632 loc.environmentCoordinate())) {
1633 return false;
1637 // Pop the value if needed.
1638 if (isOnStack == ValueIsOnStack::No) {
1639 if (!emit1(JSOp::Pop)) {
1640 return false;
1644 return innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ);
1647 bool BytecodeEmitter::emitPropLHS(PropertyAccess* prop) {
1648 MOZ_ASSERT(!prop->isSuper());
1650 ParseNode* expr = &prop->expression();
1652 if (!expr->is<PropertyAccess>() || expr->as<PropertyAccess>().isSuper()) {
1653 // The non-optimized case.
1654 return emitTree(expr);
1657 // If the object operand is also a dotted property reference, reverse the
1658 // list linked via expression() temporarily so we can iterate over it from
1659 // the bottom up (reversing again as we go), to avoid excessive recursion.
1660 PropertyAccess* pndot = &expr->as<PropertyAccess>();
1661 ParseNode* pnup = nullptr;
1662 ParseNode* pndown;
1663 for (;;) {
1664 // Reverse pndot->expression() to point up, not down.
1665 pndown = &pndot->expression();
1666 pndot->setExpression(pnup);
1667 if (!pndown->is<PropertyAccess>() ||
1668 pndown->as<PropertyAccess>().isSuper()) {
1669 break;
1671 pnup = pndot;
1672 pndot = &pndown->as<PropertyAccess>();
1675 // pndown is a primary expression, not a dotted property reference.
1676 if (!emitTree(pndown)) {
1677 return false;
1680 while (true) {
1681 // Walk back up the list, emitting annotated name ops.
1682 if (!emitAtomOp(JSOp::GetProp, pndot->key().atom())) {
1683 return false;
1686 // Reverse the pndot->expression() link again.
1687 pnup = pndot->maybeExpression();
1688 pndot->setExpression(pndown);
1689 pndown = pndot;
1690 if (!pnup) {
1691 break;
1693 pndot = &pnup->as<PropertyAccess>();
1695 return true;
1698 bool BytecodeEmitter::emitPropIncDec(UnaryNode* incDec, ValueUsage valueUsage) {
1699 PropertyAccess* prop = &incDec->kid()->as<PropertyAccess>();
1700 bool isSuper = prop->isSuper();
1701 ParseNodeKind kind = incDec->getKind();
1702 PropOpEmitter poe(
1703 this,
1704 kind == ParseNodeKind::PostIncrementExpr
1705 ? PropOpEmitter::Kind::PostIncrement
1706 : kind == ParseNodeKind::PreIncrementExpr
1707 ? PropOpEmitter::Kind::PreIncrement
1708 : kind == ParseNodeKind::PostDecrementExpr
1709 ? PropOpEmitter::Kind::PostDecrement
1710 : PropOpEmitter::Kind::PreDecrement,
1711 isSuper ? PropOpEmitter::ObjKind::Super : PropOpEmitter::ObjKind::Other);
1712 if (!poe.prepareForObj()) {
1713 return false;
1715 if (isSuper) {
1716 UnaryNode* base = &prop->expression().as<UnaryNode>();
1717 if (!emitGetThisForSuperBase(base)) {
1718 // [stack] THIS
1719 return false;
1721 } else {
1722 if (!emitPropLHS(prop)) {
1723 // [stack] OBJ
1724 return false;
1727 if (!poe.emitIncDec(prop->key().atom(), valueUsage)) {
1728 // [stack] RESULT
1729 return false;
1732 return true;
1735 bool BytecodeEmitter::emitNameIncDec(UnaryNode* incDec, ValueUsage valueUsage) {
1736 MOZ_ASSERT(incDec->kid()->isKind(ParseNodeKind::Name));
1738 ParseNodeKind kind = incDec->getKind();
1739 NameNode* name = &incDec->kid()->as<NameNode>();
1740 NameOpEmitter noe(this, name->atom(),
1741 kind == ParseNodeKind::PostIncrementExpr
1742 ? NameOpEmitter::Kind::PostIncrement
1743 : kind == ParseNodeKind::PreIncrementExpr
1744 ? NameOpEmitter::Kind::PreIncrement
1745 : kind == ParseNodeKind::PostDecrementExpr
1746 ? NameOpEmitter::Kind::PostDecrement
1747 : NameOpEmitter::Kind::PreDecrement);
1748 if (!noe.emitIncDec(valueUsage)) {
1749 return false;
1752 return true;
1755 bool BytecodeEmitter::emitObjAndKey(ParseNode* exprOrSuper, ParseNode* key,
1756 ElemOpEmitter& eoe) {
1757 if (exprOrSuper->isKind(ParseNodeKind::SuperBase)) {
1758 if (!eoe.prepareForObj()) {
1759 // [stack]
1760 return false;
1762 UnaryNode* base = &exprOrSuper->as<UnaryNode>();
1763 if (!emitGetThisForSuperBase(base)) {
1764 // [stack] THIS
1765 return false;
1767 if (!eoe.prepareForKey()) {
1768 // [stack] THIS
1769 return false;
1771 if (!emitTree(key)) {
1772 // [stack] THIS KEY
1773 return false;
1776 return true;
1779 if (!eoe.prepareForObj()) {
1780 // [stack]
1781 return false;
1783 if (!emitTree(exprOrSuper)) {
1784 // [stack] OBJ
1785 return false;
1787 if (!eoe.prepareForKey()) {
1788 // [stack] OBJ? OBJ
1789 return false;
1791 if (!emitTree(key)) {
1792 // [stack] OBJ? OBJ KEY
1793 return false;
1796 return true;
1799 bool BytecodeEmitter::emitElemOpBase(JSOp op) {
1800 if (!emit1(op)) {
1801 return false;
1804 return true;
1807 bool BytecodeEmitter::emitElemObjAndKey(PropertyByValue* elem, bool isSuper,
1808 ElemOpEmitter& eoe) {
1809 MOZ_ASSERT(isSuper == elem->expression().isKind(ParseNodeKind::SuperBase));
1810 return emitObjAndKey(&elem->expression(), &elem->key(), eoe);
1813 static ElemOpEmitter::Kind ConvertIncDecKind(ParseNodeKind kind) {
1814 switch (kind) {
1815 case ParseNodeKind::PostIncrementExpr:
1816 return ElemOpEmitter::Kind::PostIncrement;
1817 case ParseNodeKind::PreIncrementExpr:
1818 return ElemOpEmitter::Kind::PreIncrement;
1819 case ParseNodeKind::PostDecrementExpr:
1820 return ElemOpEmitter::Kind::PostDecrement;
1821 case ParseNodeKind::PreDecrementExpr:
1822 return ElemOpEmitter::Kind::PreDecrement;
1823 default:
1824 MOZ_CRASH("unexpected inc/dec node kind");
1828 static PrivateOpEmitter::Kind PrivateConvertIncDecKind(ParseNodeKind kind) {
1829 switch (kind) {
1830 case ParseNodeKind::PostIncrementExpr:
1831 return PrivateOpEmitter::Kind::PostIncrement;
1832 case ParseNodeKind::PreIncrementExpr:
1833 return PrivateOpEmitter::Kind::PreIncrement;
1834 case ParseNodeKind::PostDecrementExpr:
1835 return PrivateOpEmitter::Kind::PostDecrement;
1836 case ParseNodeKind::PreDecrementExpr:
1837 return PrivateOpEmitter::Kind::PreDecrement;
1838 default:
1839 MOZ_CRASH("unexpected inc/dec node kind");
1843 bool BytecodeEmitter::emitElemIncDec(UnaryNode* incDec, ValueUsage valueUsage) {
1844 PropertyByValue* elemExpr = &incDec->kid()->as<PropertyByValue>();
1845 bool isSuper = elemExpr->isSuper();
1846 MOZ_ASSERT(!elemExpr->key().isKind(ParseNodeKind::PrivateName));
1847 ParseNodeKind kind = incDec->getKind();
1848 ElemOpEmitter eoe(
1849 this, ConvertIncDecKind(kind),
1850 isSuper ? ElemOpEmitter::ObjKind::Super : ElemOpEmitter::ObjKind::Other);
1851 if (!emitElemObjAndKey(elemExpr, isSuper, eoe)) {
1852 // [stack] # if Super
1853 // [stack] THIS KEY
1854 // [stack] # otherwise
1855 // [stack] OBJ KEY
1856 return false;
1858 if (!eoe.emitIncDec(valueUsage)) {
1859 // [stack] RESULT
1860 return false;
1863 return true;
1866 bool BytecodeEmitter::emitCallIncDec(UnaryNode* incDec) {
1867 MOZ_ASSERT(incDec->isKind(ParseNodeKind::PreIncrementExpr) ||
1868 incDec->isKind(ParseNodeKind::PostIncrementExpr) ||
1869 incDec->isKind(ParseNodeKind::PreDecrementExpr) ||
1870 incDec->isKind(ParseNodeKind::PostDecrementExpr));
1872 ParseNode* call = incDec->kid();
1873 MOZ_ASSERT(call->isKind(ParseNodeKind::CallExpr));
1874 if (!emitTree(call)) {
1875 // [stack] CALLRESULT
1876 return false;
1878 if (!emit1(JSOp::ToNumeric)) {
1879 // [stack] N
1880 return false;
1883 // The increment/decrement has no side effects, so proceed to throw for
1884 // invalid assignment target.
1885 return emit2(JSOp::ThrowMsg, uint8_t(ThrowMsgKind::AssignToCall));
1888 bool BytecodeEmitter::emitPrivateIncDec(UnaryNode* incDec,
1889 ValueUsage valueUsage) {
1890 PrivateMemberAccess* privateExpr = &incDec->kid()->as<PrivateMemberAccess>();
1891 ParseNodeKind kind = incDec->getKind();
1892 PrivateOpEmitter xoe(this, PrivateConvertIncDecKind(kind),
1893 privateExpr->privateName().name());
1894 if (!emitTree(&privateExpr->expression())) {
1895 // [stack] OBJ
1896 return false;
1898 if (!xoe.emitReference()) {
1899 // [stack] OBJ NAME
1900 return false;
1902 if (!xoe.emitIncDec(valueUsage)) {
1903 // [stack] RESULT
1904 return false;
1907 return true;
1910 bool BytecodeEmitter::emitDouble(double d) {
1911 BytecodeOffset offset;
1912 if (!emitCheck(JSOp::Double, 9, &offset)) {
1913 return false;
1916 jsbytecode* code = bytecodeSection().code(offset);
1917 code[0] = jsbytecode(JSOp::Double);
1918 SET_INLINE_VALUE(code, DoubleValue(d));
1919 bytecodeSection().updateDepth(JSOp::Double, offset);
1920 return true;
1923 bool BytecodeEmitter::emitNumberOp(double dval) {
1924 int32_t ival;
1925 if (NumberIsInt32(dval, &ival)) {
1926 if (ival == 0) {
1927 return emit1(JSOp::Zero);
1929 if (ival == 1) {
1930 return emit1(JSOp::One);
1932 if ((int)(int8_t)ival == ival) {
1933 return emit2(JSOp::Int8, uint8_t(int8_t(ival)));
1936 uint32_t u = uint32_t(ival);
1937 if (u < Bit(16)) {
1938 if (!emitUint16Operand(JSOp::Uint16, u)) {
1939 return false;
1941 } else if (u < Bit(24)) {
1942 BytecodeOffset off;
1943 if (!emitN(JSOp::Uint24, 3, &off)) {
1944 return false;
1946 SET_UINT24(bytecodeSection().code(off), u);
1947 } else {
1948 BytecodeOffset off;
1949 if (!emitN(JSOp::Int32, 4, &off)) {
1950 return false;
1952 SET_INT32(bytecodeSection().code(off), ival);
1954 return true;
1957 return emitDouble(dval);
1961 * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047.
1962 * LLVM is deciding to inline this function which uses a lot of stack space
1963 * into emitTree which is recursive and uses relatively little stack space.
1965 MOZ_NEVER_INLINE bool BytecodeEmitter::emitSwitch(SwitchStatement* switchStmt) {
1966 LexicalScopeNode& lexical = switchStmt->lexicalForCaseList();
1967 MOZ_ASSERT(lexical.isKind(ParseNodeKind::LexicalScope));
1968 ListNode* cases = &lexical.scopeBody()->as<ListNode>();
1969 MOZ_ASSERT(cases->isKind(ParseNodeKind::StatementList));
1971 SwitchEmitter se(this);
1972 if (!se.emitDiscriminant(switchStmt->discriminant().pn_pos.begin)) {
1973 return false;
1976 if (!markStepBreakpoint()) {
1977 return false;
1979 if (!emitTree(&switchStmt->discriminant())) {
1980 return false;
1983 // Enter the scope before pushing the switch BreakableControl since all
1984 // breaks are under this scope.
1986 if (!lexical.isEmptyScope()) {
1987 if (!se.emitLexical(lexical.scopeBindings())) {
1988 return false;
1991 // A switch statement may contain hoisted functions inside its
1992 // cases. The hasTopLevelFunctionDeclarations flag is propagated from the
1993 // StatementList bodies of the cases to the case list.
1994 if (cases->hasTopLevelFunctionDeclarations()) {
1995 for (ParseNode* item : cases->contents()) {
1996 CaseClause* caseClause = &item->as<CaseClause>();
1997 ListNode* statements = caseClause->statementList();
1998 if (statements->hasTopLevelFunctionDeclarations()) {
1999 if (!emitHoistedFunctionsInList(statements)) {
2000 return false;
2005 } else {
2006 MOZ_ASSERT(!cases->hasTopLevelFunctionDeclarations());
2009 SwitchEmitter::TableGenerator tableGen(this);
2010 uint32_t caseCount = cases->count() - (switchStmt->hasDefault() ? 1 : 0);
2011 if (caseCount == 0) {
2012 tableGen.finish(0);
2013 } else {
2014 for (ParseNode* item : cases->contents()) {
2015 CaseClause* caseClause = &item->as<CaseClause>();
2016 if (caseClause->isDefault()) {
2017 continue;
2020 ParseNode* caseValue = caseClause->caseExpression();
2022 if (caseValue->getKind() != ParseNodeKind::NumberExpr) {
2023 tableGen.setInvalid();
2024 break;
2027 int32_t i;
2028 if (!NumberEqualsInt32(caseValue->as<NumericLiteral>().value(), &i)) {
2029 tableGen.setInvalid();
2030 break;
2033 if (!tableGen.addNumber(i)) {
2034 return false;
2038 tableGen.finish(caseCount);
2041 if (!se.validateCaseCount(caseCount)) {
2042 return false;
2045 bool isTableSwitch = tableGen.isValid();
2046 if (isTableSwitch) {
2047 if (!se.emitTable(tableGen)) {
2048 return false;
2050 } else {
2051 if (!se.emitCond()) {
2052 return false;
2055 // Emit code for evaluating cases and jumping to case statements.
2056 for (ParseNode* item : cases->contents()) {
2057 CaseClause* caseClause = &item->as<CaseClause>();
2058 if (caseClause->isDefault()) {
2059 continue;
2062 if (!se.prepareForCaseValue()) {
2063 return false;
2066 ParseNode* caseValue = caseClause->caseExpression();
2067 // If the expression is a literal, suppress line number emission so
2068 // that debugging works more naturally.
2069 if (!emitTree(
2070 caseValue, ValueUsage::WantValue,
2071 caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE)) {
2072 return false;
2075 if (!se.emitCaseJump()) {
2076 return false;
2081 // Emit code for each case's statements.
2082 for (ParseNode* item : cases->contents()) {
2083 CaseClause* caseClause = &item->as<CaseClause>();
2084 if (caseClause->isDefault()) {
2085 if (!se.emitDefaultBody()) {
2086 return false;
2088 } else {
2089 if (isTableSwitch) {
2090 ParseNode* caseValue = caseClause->caseExpression();
2091 MOZ_ASSERT(caseValue->isKind(ParseNodeKind::NumberExpr));
2093 NumericLiteral* literal = &caseValue->as<NumericLiteral>();
2094 #ifdef DEBUG
2095 // Use NumberEqualsInt32 here because switches compare using
2096 // strict equality, which will equate -0 and +0. In contrast
2097 // NumberIsInt32 would return false for -0.
2098 int32_t v;
2099 MOZ_ASSERT(mozilla::NumberEqualsInt32(literal->value(), &v));
2100 #endif
2101 int32_t i = int32_t(literal->value());
2103 if (!se.emitCaseBody(i, tableGen)) {
2104 return false;
2106 } else {
2107 if (!se.emitCaseBody()) {
2108 return false;
2113 if (!emitTree(caseClause->statementList())) {
2114 return false;
2118 if (!se.emitEnd()) {
2119 return false;
2122 return true;
2125 bool BytecodeEmitter::allocateResumeIndex(BytecodeOffset offset,
2126 uint32_t* resumeIndex) {
2127 static constexpr uint32_t MaxResumeIndex = BitMask(24);
2129 static_assert(
2130 MaxResumeIndex < uint32_t(AbstractGeneratorObject::RESUME_INDEX_RUNNING),
2131 "resumeIndex should not include magic AbstractGeneratorObject "
2132 "resumeIndex values");
2133 static_assert(
2134 MaxResumeIndex <= INT32_MAX / sizeof(uintptr_t),
2135 "resumeIndex * sizeof(uintptr_t) must fit in an int32. JIT code relies "
2136 "on this when loading resume entries from BaselineScript");
2138 *resumeIndex = bytecodeSection().resumeOffsetList().length();
2139 if (*resumeIndex > MaxResumeIndex) {
2140 reportError(nullptr, JSMSG_TOO_MANY_RESUME_INDEXES);
2141 return false;
2144 return bytecodeSection().resumeOffsetList().append(offset.value());
2147 bool BytecodeEmitter::allocateResumeIndexRange(
2148 mozilla::Span<BytecodeOffset> offsets, uint32_t* firstResumeIndex) {
2149 *firstResumeIndex = 0;
2151 for (size_t i = 0, len = offsets.size(); i < len; i++) {
2152 uint32_t resumeIndex;
2153 if (!allocateResumeIndex(offsets[i], &resumeIndex)) {
2154 return false;
2156 if (i == 0) {
2157 *firstResumeIndex = resumeIndex;
2161 return true;
2164 bool BytecodeEmitter::emitYieldOp(JSOp op) {
2165 if (op == JSOp::FinalYieldRval) {
2166 return emit1(JSOp::FinalYieldRval);
2169 MOZ_ASSERT(op == JSOp::InitialYield || op == JSOp::Yield ||
2170 op == JSOp::Await);
2172 BytecodeOffset off;
2173 if (!emitN(op, 3, &off)) {
2174 return false;
2177 if (op == JSOp::InitialYield || op == JSOp::Yield) {
2178 bytecodeSection().addNumYields();
2181 uint32_t resumeIndex;
2182 if (!allocateResumeIndex(bytecodeSection().offset(), &resumeIndex)) {
2183 return false;
2186 SET_RESUMEINDEX(bytecodeSection().code(off), resumeIndex);
2188 BytecodeOffset unusedOffset;
2189 return emitJumpTargetOp(JSOp::AfterYield, &unusedOffset);
2192 bool BytecodeEmitter::emitPushResumeKind(GeneratorResumeKind kind) {
2193 return emit2(JSOp::ResumeKind, uint8_t(kind));
2196 bool BytecodeEmitter::emitSetThis(BinaryNode* setThisNode) {
2197 // ParseNodeKind::SetThis is used to update |this| after a super() call
2198 // in a derived class constructor.
2200 MOZ_ASSERT(setThisNode->isKind(ParseNodeKind::SetThis));
2201 MOZ_ASSERT(setThisNode->left()->isKind(ParseNodeKind::Name));
2203 auto name = setThisNode->left()->as<NameNode>().name();
2205 // The 'this' binding is not lexical, but due to super() semantics this
2206 // initialization needs to be treated as a lexical one.
2207 NameLocation loc = lookupName(name);
2208 NameLocation lexicalLoc;
2209 if (loc.kind() == NameLocation::Kind::FrameSlot) {
2210 lexicalLoc = NameLocation::FrameSlot(BindingKind::Let, loc.frameSlot());
2211 } else if (loc.kind() == NameLocation::Kind::EnvironmentCoordinate) {
2212 EnvironmentCoordinate coord = loc.environmentCoordinate();
2213 uint8_t hops = AssertedCast<uint8_t>(coord.hops());
2214 lexicalLoc = NameLocation::EnvironmentCoordinate(BindingKind::Let, hops,
2215 coord.slot());
2216 } else {
2217 MOZ_ASSERT(loc.kind() == NameLocation::Kind::Dynamic);
2218 lexicalLoc = loc;
2221 NameOpEmitter noe(this, name, lexicalLoc, NameOpEmitter::Kind::Initialize);
2222 if (!noe.prepareForRhs()) {
2223 // [stack]
2224 return false;
2227 // Emit the new |this| value.
2228 if (!emitTree(setThisNode->right())) {
2229 // [stack] NEWTHIS
2230 return false;
2233 // Get the original |this| and throw if we already initialized
2234 // it. Do *not* use the NameLocation argument, as that's the special
2235 // lexical location below to deal with super() semantics.
2236 if (!emitGetName(name)) {
2237 // [stack] NEWTHIS THIS
2238 return false;
2240 if (!emit1(JSOp::CheckThisReinit)) {
2241 // [stack] NEWTHIS THIS
2242 return false;
2244 if (!emit1(JSOp::Pop)) {
2245 // [stack] NEWTHIS
2246 return false;
2248 if (!noe.emitAssignment()) {
2249 // [stack] NEWTHIS
2250 return false;
2253 if (!emitInitializeInstanceMembers(true)) {
2254 return false;
2257 return true;
2260 bool BytecodeEmitter::defineHoistedTopLevelFunctions(ParseNode* body) {
2261 MOZ_ASSERT(inPrologue());
2262 MOZ_ASSERT(sc->isGlobalContext() || (sc->isEvalContext() && !sc->strict()));
2263 MOZ_ASSERT(body->is<LexicalScopeNode>() || body->is<ListNode>());
2265 if (body->is<LexicalScopeNode>()) {
2266 body = body->as<LexicalScopeNode>().scopeBody();
2267 MOZ_ASSERT(body->is<ListNode>());
2270 if (!body->as<ListNode>().hasTopLevelFunctionDeclarations()) {
2271 return true;
2274 return emitHoistedFunctionsInList(&body->as<ListNode>());
2277 // For Global and sloppy-Eval scripts, this performs most of the steps of the
2278 // spec's [GlobalDeclarationInstantiation] and [EvalDeclarationInstantiation]
2279 // operations.
2281 // Note that while strict-Eval is handled in the same part of the spec, it never
2282 // fails for global-redeclaration checks so those scripts initialize directly in
2283 // their bytecode.
2284 bool BytecodeEmitter::emitDeclarationInstantiation(ParseNode* body) {
2285 if (sc->isModuleContext()) {
2286 // ES Modules have dedicated variable and lexial environments and therefore
2287 // do not have to perform redeclaration checks. We initialize their bindings
2288 // elsewhere in bytecode.
2289 return true;
2292 if (sc->isEvalContext() && sc->strict()) {
2293 // Strict Eval has a dedicated variables (and lexical) environment and
2294 // therefore does not have to perform redeclaration checks. We initialize
2295 // their bindings elsewhere in the bytecode.
2296 return true;
2299 // If we have no variables bindings, then we are done!
2300 if (sc->isGlobalContext()) {
2301 if (!sc->asGlobalContext()->bindings) {
2302 return true;
2304 } else {
2305 MOZ_ASSERT(sc->isEvalContext());
2307 if (!sc->asEvalContext()->bindings) {
2308 return true;
2312 #if DEBUG
2313 // There should be no emitted functions yet.
2314 for (const auto& thing : perScriptData().gcThingList().objects()) {
2315 MOZ_ASSERT(thing.isEmptyGlobalScope() || thing.isScope());
2317 #endif
2319 // Emit the hoisted functions to gc-things list. There is no bytecode
2320 // generated yet to bind them.
2321 if (!defineHoistedTopLevelFunctions(body)) {
2322 return false;
2325 // Save the last GCThingIndex emitted. The hoisted functions are contained in
2326 // the gc-things list up until this point. This set of gc-things also contain
2327 // initial scopes (of which there must be at least one).
2328 MOZ_ASSERT(perScriptData().gcThingList().length() > 0);
2329 GCThingIndex lastFun =
2330 GCThingIndex(perScriptData().gcThingList().length() - 1);
2332 #if DEBUG
2333 for (const auto& thing : perScriptData().gcThingList().objects()) {
2334 MOZ_ASSERT(thing.isEmptyGlobalScope() || thing.isScope() ||
2335 thing.isFunction());
2337 #endif
2339 // Check for declaration conflicts and initialize the bindings.
2340 // NOTE: The self-hosting top-level script should not populate the builtins
2341 // directly on the GlobalObject (and instead uses JSOp::GetIntrinsic for
2342 // lookups).
2343 if (emitterMode == BytecodeEmitter::EmitterMode::Normal) {
2344 if (!emitGCIndexOp(JSOp::GlobalOrEvalDeclInstantiation, lastFun)) {
2345 return false;
2349 return true;
2352 bool BytecodeEmitter::emitScript(ParseNode* body) {
2353 setScriptStartOffsetIfUnset(body->pn_pos.begin);
2355 MOZ_ASSERT(inPrologue());
2357 TDZCheckCache tdzCache(this);
2358 EmitterScope emitterScope(this);
2359 Maybe<AsyncEmitter> topLevelAwait;
2360 if (sc->isGlobalContext()) {
2361 if (!emitterScope.enterGlobal(this, sc->asGlobalContext())) {
2362 return false;
2364 } else if (sc->isEvalContext()) {
2365 if (!emitterScope.enterEval(this, sc->asEvalContext())) {
2366 return false;
2368 } else {
2369 MOZ_ASSERT(sc->isModuleContext());
2370 if (!emitterScope.enterModule(this, sc->asModuleContext())) {
2371 return false;
2373 if (sc->asModuleContext()->isAsync()) {
2374 topLevelAwait.emplace(this);
2378 setFunctionBodyEndPos(body->pn_pos.end);
2380 bool isSloppyEval = sc->isEvalContext() && !sc->strict();
2381 if (isSloppyEval && body->is<LexicalScopeNode>() &&
2382 !body->as<LexicalScopeNode>().isEmptyScope()) {
2383 // Sloppy eval scripts may emit hoisted functions bindings with a
2384 // `JSOp::GlobalOrEvalDeclInstantiation` opcode below. If this eval needs a
2385 // top-level lexical environment, we must ensure that environment is created
2386 // before those functions are created and bound.
2388 // This differs from the global-script case below because the global-lexical
2389 // environment exists outside the script itself. In the case of strict eval
2390 // scripts, the `emitterScope` above is already sufficient.
2391 EmitterScope lexicalEmitterScope(this);
2392 LexicalScopeNode* scope = &body->as<LexicalScopeNode>();
2394 if (!lexicalEmitterScope.enterLexical(this, ScopeKind::Lexical,
2395 scope->scopeBindings())) {
2396 return false;
2399 if (!emitDeclarationInstantiation(scope->scopeBody())) {
2400 return false;
2403 switchToMain();
2405 ParseNode* scopeBody = scope->scopeBody();
2406 if (!emitLexicalScopeBody(scopeBody)) {
2407 return false;
2410 if (!updateSourceCoordNotes(scopeBody->pn_pos.end)) {
2411 return false;
2414 if (!lexicalEmitterScope.leave(this)) {
2415 return false;
2417 } else {
2418 if (!emitDeclarationInstantiation(body)) {
2419 return false;
2421 if (topLevelAwait) {
2422 if (!topLevelAwait->prepareForModule()) {
2423 return false;
2427 switchToMain();
2429 if (topLevelAwait) {
2430 if (!topLevelAwait->prepareForBody()) {
2431 return false;
2435 if (!emitTree(body)) {
2436 // [stack]
2437 return false;
2440 if (!updateSourceCoordNotes(body->pn_pos.end)) {
2441 return false;
2445 if (topLevelAwait) {
2446 if (!topLevelAwait->emitEndModule()) {
2447 return false;
2451 if (!markSimpleBreakpoint()) {
2452 return false;
2455 if (!emitReturnRval()) {
2456 return false;
2459 if (!emitterScope.leave(this)) {
2460 return false;
2463 if (!NameFunctions(fc, parserAtoms(), body)) {
2464 return false;
2467 // Create a Stencil and convert it into a JSScript.
2468 return intoScriptStencil(CompilationStencil::TopLevelIndex);
2471 js::UniquePtr<ImmutableScriptData>
2472 BytecodeEmitter::createImmutableScriptData() {
2473 uint32_t nslots;
2474 if (!getNslots(&nslots)) {
2475 return nullptr;
2478 bool isFunction = sc->isFunctionBox();
2479 uint16_t funLength = isFunction ? sc->asFunctionBox()->length() : 0;
2481 mozilla::SaturateUint8 propertyCountEstimate = propertyAdditionEstimate;
2483 // Add fields to the property count estimate.
2484 if (isFunction && sc->asFunctionBox()->useMemberInitializers()) {
2485 propertyCountEstimate +=
2486 sc->asFunctionBox()->memberInitializers().numMemberInitializers;
2489 return ImmutableScriptData::new_(
2490 fc, mainOffset(), maxFixedSlots, nslots, bodyScopeIndex,
2491 bytecodeSection().numICEntries(), isFunction, funLength,
2492 propertyCountEstimate.value(), bytecodeSection().code(),
2493 bytecodeSection().notes(), bytecodeSection().resumeOffsetList().span(),
2494 bytecodeSection().scopeNoteList().span(),
2495 bytecodeSection().tryNoteList().span());
2498 bool BytecodeEmitter::getNslots(uint32_t* nslots) {
2499 uint64_t nslots64 =
2500 maxFixedSlots + static_cast<uint64_t>(bytecodeSection().maxStackDepth());
2501 if (nslots64 > UINT32_MAX) {
2502 reportError(nullptr, JSMSG_NEED_DIET, "script");
2503 return false;
2505 *nslots = nslots64;
2506 return true;
2509 bool BytecodeEmitter::emitFunctionScript(FunctionNode* funNode) {
2510 MOZ_ASSERT(inPrologue());
2511 ParamsBodyNode* paramsBody = funNode->body();
2512 FunctionBox* funbox = sc->asFunctionBox();
2514 setScriptStartOffsetIfUnset(paramsBody->pn_pos.begin);
2516 // [stack]
2518 FunctionScriptEmitter fse(this, funbox, Some(paramsBody->pn_pos.begin),
2519 Some(paramsBody->pn_pos.end));
2520 if (!fse.prepareForParameters()) {
2521 // [stack]
2522 return false;
2525 if (!emitFunctionFormalParameters(paramsBody)) {
2526 // [stack]
2527 return false;
2530 if (!fse.prepareForBody()) {
2531 // [stack]
2532 return false;
2535 if (!emitTree(paramsBody->body())) {
2536 // [stack]
2537 return false;
2540 if (!fse.emitEndBody()) {
2541 // [stack]
2542 return false;
2545 if (funbox->index() == CompilationStencil::TopLevelIndex) {
2546 if (!NameFunctions(fc, parserAtoms(), funNode)) {
2547 return false;
2551 return fse.intoStencil();
2554 bool BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target,
2555 size_t* emitted) {
2556 #ifdef DEBUG
2557 int depth = bytecodeSection().stackDepth();
2558 #endif
2560 switch (target->getKind()) {
2561 case ParseNodeKind::Name:
2562 case ParseNodeKind::ArrayExpr:
2563 case ParseNodeKind::ObjectExpr:
2564 // No need to recurse into ParseNodeKind::Array and ParseNodeKind::Object
2565 // subpatterns here, since emitSetOrInitializeDestructuring does the
2566 // recursion when setting or initializing the value. Getting reference
2567 // doesn't recurse.
2568 *emitted = 0;
2569 break;
2571 case ParseNodeKind::DotExpr: {
2572 PropertyAccess* prop = &target->as<PropertyAccess>();
2573 bool isSuper = prop->isSuper();
2574 PropOpEmitter poe(this, PropOpEmitter::Kind::SimpleAssignment,
2575 isSuper ? PropOpEmitter::ObjKind::Super
2576 : PropOpEmitter::ObjKind::Other);
2577 if (!poe.prepareForObj()) {
2578 return false;
2580 if (isSuper) {
2581 UnaryNode* base = &prop->expression().as<UnaryNode>();
2582 if (!emitGetThisForSuperBase(base)) {
2583 // [stack] THIS SUPERBASE
2584 return false;
2586 } else {
2587 if (!emitTree(&prop->expression())) {
2588 // [stack] OBJ
2589 return false;
2592 if (!poe.prepareForRhs()) {
2593 // [stack] # if Super
2594 // [stack] THIS SUPERBASE
2595 // [stack] # otherwise
2596 // [stack] OBJ
2597 return false;
2600 // SUPERBASE was pushed onto THIS in poe.prepareForRhs above.
2601 *emitted = 1 + isSuper;
2602 break;
2605 case ParseNodeKind::ElemExpr: {
2606 PropertyByValue* elem = &target->as<PropertyByValue>();
2607 bool isSuper = elem->isSuper();
2608 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
2609 ElemOpEmitter eoe(this, ElemOpEmitter::Kind::SimpleAssignment,
2610 isSuper ? ElemOpEmitter::ObjKind::Super
2611 : ElemOpEmitter::ObjKind::Other);
2612 if (!emitElemObjAndKey(elem, isSuper, eoe)) {
2613 // [stack] # if Super
2614 // [stack] THIS KEY
2615 // [stack] # otherwise
2616 // [stack] OBJ KEY
2617 return false;
2619 if (!eoe.prepareForRhs()) {
2620 // [stack] # if Super
2621 // [stack] THIS KEY SUPERBASE
2622 // [stack] # otherwise
2623 // [stack] OBJ KEY
2624 return false;
2627 // SUPERBASE was pushed onto KEY in eoe.prepareForRhs above.
2628 *emitted = 2 + isSuper;
2629 break;
2632 case ParseNodeKind::PrivateMemberExpr: {
2633 PrivateMemberAccess* privateExpr = &target->as<PrivateMemberAccess>();
2634 PrivateOpEmitter xoe(this, PrivateOpEmitter::Kind::SimpleAssignment,
2635 privateExpr->privateName().name());
2636 if (!emitTree(&privateExpr->expression())) {
2637 // [stack] OBJ
2638 return false;
2640 if (!xoe.emitReference()) {
2641 // [stack] OBJ NAME
2642 return false;
2644 *emitted = xoe.numReferenceSlots();
2645 break;
2648 case ParseNodeKind::CallExpr:
2649 MOZ_ASSERT_UNREACHABLE(
2650 "Parser::reportIfNotValidSimpleAssignmentTarget "
2651 "rejects function calls as assignment "
2652 "targets in destructuring assignments");
2653 break;
2655 default:
2656 MOZ_CRASH("emitDestructuringLHSRef: bad lhs kind");
2659 MOZ_ASSERT(bytecodeSection().stackDepth() == depth + int(*emitted));
2661 return true;
2664 bool BytecodeEmitter::emitSetOrInitializeDestructuring(
2665 ParseNode* target, DestructuringFlavor flav) {
2666 // Now emit the lvalue opcode sequence. If the lvalue is a nested
2667 // destructuring initialiser-form, call ourselves to handle it, then pop
2668 // the matched value. Otherwise emit an lvalue bytecode sequence followed
2669 // by an assignment op.
2671 switch (target->getKind()) {
2672 case ParseNodeKind::ArrayExpr:
2673 case ParseNodeKind::ObjectExpr:
2674 if (!emitDestructuringOps(&target->as<ListNode>(), flav)) {
2675 return false;
2677 // emitDestructuringOps leaves the assigned (to-be-destructured) value on
2678 // top of the stack.
2679 break;
2681 case ParseNodeKind::Name: {
2682 auto name = target->as<NameNode>().name();
2683 NameLocation loc = lookupName(name);
2684 NameOpEmitter::Kind kind;
2685 switch (flav) {
2686 case DestructuringFlavor::Declaration:
2687 kind = NameOpEmitter::Kind::Initialize;
2688 break;
2690 case DestructuringFlavor::Assignment:
2691 kind = NameOpEmitter::Kind::SimpleAssignment;
2692 break;
2695 NameOpEmitter noe(this, name, loc, kind);
2696 if (!noe.prepareForRhs()) {
2697 // [stack] V ENV?
2698 return false;
2700 if (noe.emittedBindOp()) {
2701 // This is like ordinary assignment, but with one difference.
2703 // In `a = b`, we first determine a binding for `a` (using
2704 // JSOp::BindName or JSOp::BindGName), then we evaluate `b`, then
2705 // a JSOp::SetName instruction.
2707 // In `[a] = [b]`, per spec, `b` is evaluated first, then we
2708 // determine a binding for `a`. Then we need to do assignment--
2709 // but the operands are on the stack in the wrong order for
2710 // JSOp::SetProp, so we have to add a JSOp::Swap.
2712 // In the cases where we are emitting a name op, emit a swap
2713 // because of this.
2714 if (!emit1(JSOp::Swap)) {
2715 // [stack] ENV V
2716 return false;
2718 } else {
2719 // In cases of emitting a frame slot or environment slot,
2720 // nothing needs be done.
2722 if (!noe.emitAssignment()) {
2723 // [stack] V
2724 return false;
2727 break;
2730 case ParseNodeKind::DotExpr: {
2731 // The reference is already pushed by emitDestructuringLHSRef.
2732 // [stack] # if Super
2733 // [stack] THIS SUPERBASE VAL
2734 // [stack] # otherwise
2735 // [stack] OBJ VAL
2736 PropertyAccess* prop = &target->as<PropertyAccess>();
2737 bool isSuper = prop->isSuper();
2738 PropOpEmitter poe(this, PropOpEmitter::Kind::SimpleAssignment,
2739 isSuper ? PropOpEmitter::ObjKind::Super
2740 : PropOpEmitter::ObjKind::Other);
2741 if (!poe.skipObjAndRhs()) {
2742 return false;
2744 // [stack] # VAL
2745 if (!poe.emitAssignment(prop->key().atom())) {
2746 return false;
2748 break;
2751 case ParseNodeKind::ElemExpr: {
2752 // The reference is already pushed by emitDestructuringLHSRef.
2753 // [stack] # if Super
2754 // [stack] THIS KEY SUPERBASE VAL
2755 // [stack] # otherwise
2756 // [stack] OBJ KEY VAL
2757 PropertyByValue* elem = &target->as<PropertyByValue>();
2758 bool isSuper = elem->isSuper();
2759 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
2760 ElemOpEmitter eoe(this, ElemOpEmitter::Kind::SimpleAssignment,
2761 isSuper ? ElemOpEmitter::ObjKind::Super
2762 : ElemOpEmitter::ObjKind::Other);
2763 if (!eoe.skipObjAndKeyAndRhs()) {
2764 return false;
2766 if (!eoe.emitAssignment()) {
2767 // [stack] VAL
2768 return false;
2770 break;
2773 case ParseNodeKind::PrivateMemberExpr: {
2774 // The reference is already pushed by emitDestructuringLHSRef.
2775 // [stack] OBJ NAME VAL
2776 PrivateMemberAccess* privateExpr = &target->as<PrivateMemberAccess>();
2777 PrivateOpEmitter xoe(this, PrivateOpEmitter::Kind::SimpleAssignment,
2778 privateExpr->privateName().name());
2779 if (!xoe.skipReference()) {
2780 return false;
2782 if (!xoe.emitAssignment()) {
2783 // [stack] VAL
2784 return false;
2786 break;
2789 case ParseNodeKind::CallExpr:
2790 MOZ_ASSERT_UNREACHABLE(
2791 "Parser::reportIfNotValidSimpleAssignmentTarget "
2792 "rejects function calls as assignment "
2793 "targets in destructuring assignments");
2794 break;
2796 default:
2797 MOZ_CRASH("emitSetOrInitializeDestructuring: bad lhs kind");
2800 // Pop the assigned value.
2801 if (!emit1(JSOp::Pop)) {
2802 // [stack] # empty
2803 return false;
2806 return true;
2809 JSOp BytecodeEmitter::getIterCallOp(JSOp callOp,
2810 SelfHostedIter selfHostedIter) {
2811 if (emitterMode == BytecodeEmitter::SelfHosting) {
2812 MOZ_ASSERT(selfHostedIter != SelfHostedIter::Deny);
2814 switch (callOp) {
2815 case JSOp::Call:
2816 return JSOp::CallContent;
2817 case JSOp::CallIter:
2818 return JSOp::CallContentIter;
2819 default:
2820 MOZ_CRASH("Unknown iterator call op");
2824 return callOp;
2827 bool BytecodeEmitter::emitIteratorNext(
2828 const Maybe<uint32_t>& callSourceCoordOffset,
2829 IteratorKind iterKind /* = IteratorKind::Sync */,
2830 SelfHostedIter selfHostedIter /* = SelfHostedIter::Deny */) {
2831 MOZ_ASSERT(selfHostedIter != SelfHostedIter::Deny ||
2832 emitterMode != BytecodeEmitter::SelfHosting,
2833 ".next() iteration is prohibited in self-hosted code because it"
2834 "can run user-modifiable iteration code");
2836 // [stack] ... NEXT ITER
2837 MOZ_ASSERT(bytecodeSection().stackDepth() >= 2);
2839 if (!emitCall(getIterCallOp(JSOp::Call, selfHostedIter), 0,
2840 callSourceCoordOffset)) {
2841 // [stack] ... RESULT
2842 return false;
2845 if (iterKind == IteratorKind::Async) {
2846 if (!emitAwaitInInnermostScope()) {
2847 // [stack] ... RESULT
2848 return false;
2852 if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) {
2853 // [stack] ... RESULT
2854 return false;
2856 return true;
2859 bool BytecodeEmitter::emitIteratorCloseInScope(
2860 EmitterScope& currentScope,
2861 IteratorKind iterKind /* = IteratorKind::Sync */,
2862 CompletionKind completionKind /* = CompletionKind::Normal */,
2863 SelfHostedIter selfHostedIter /* = SelfHostedIter::Deny */) {
2864 MOZ_ASSERT(selfHostedIter != SelfHostedIter::Deny ||
2865 emitterMode != BytecodeEmitter::SelfHosting,
2866 ".close() on iterators is prohibited in self-hosted code because "
2867 "it can run user-modifiable iteration code");
2869 if (iterKind == IteratorKind::Sync) {
2870 return emit2(JSOp::CloseIter, uint8_t(completionKind));
2873 // Generate inline logic corresponding to IteratorClose (ES2021 7.4.6) and
2874 // AsyncIteratorClose (ES2021 7.4.7). Steps numbers apply to both operations.
2876 // Callers need to ensure that the iterator object is at the top of the
2877 // stack.
2879 // For non-Throw completions, we emit the equivalent of:
2881 // var returnMethod = GetMethod(iterator, "return");
2882 // if (returnMethod !== undefined) {
2883 // var innerResult = [Await] Call(returnMethod, iterator);
2884 // CheckIsObj(innerResult);
2885 // }
2887 // Whereas for Throw completions, we emit:
2889 // try {
2890 // var returnMethod = GetMethod(iterator, "return");
2891 // if (returnMethod !== undefined) {
2892 // [Await] Call(returnMethod, iterator);
2893 // }
2894 // } catch {}
2896 Maybe<TryEmitter> tryCatch;
2898 if (completionKind == CompletionKind::Throw) {
2899 tryCatch.emplace(this, TryEmitter::Kind::TryCatch,
2900 TryEmitter::ControlKind::NonSyntactic);
2902 if (!tryCatch->emitTry()) {
2903 // [stack] ... ITER
2904 return false;
2908 if (!emit1(JSOp::Dup)) {
2909 // [stack] ... ITER ITER
2910 return false;
2913 // Steps 1-2 are assertions, step 3 is implicit.
2915 // Step 4.
2917 // Get the "return" method.
2918 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::return_())) {
2919 // [stack] ... ITER RET
2920 return false;
2923 // Step 5.
2925 // Do nothing if "return" is undefined or null.
2926 InternalIfEmitter ifReturnMethodIsDefined(this);
2927 if (!emit1(JSOp::IsNullOrUndefined)) {
2928 // [stack] ... ITER RET NULL-OR-UNDEF
2929 return false;
2932 if (!ifReturnMethodIsDefined.emitThenElse(
2933 IfEmitter::ConditionKind::Negative)) {
2934 // [stack] ... ITER RET
2935 return false;
2938 // Steps 5.c, 7.
2940 // Call the "return" method.
2941 if (!emit1(JSOp::Swap)) {
2942 // [stack] ... RET ITER
2943 return false;
2946 if (!emitCall(getIterCallOp(JSOp::Call, selfHostedIter), 0)) {
2947 // [stack] ... RESULT
2948 return false;
2951 // 7.4.7 AsyncIteratorClose, step 5.d.
2952 if (iterKind == IteratorKind::Async) {
2953 if (completionKind != CompletionKind::Throw) {
2954 // Await clobbers rval, so save the current rval.
2955 if (!emit1(JSOp::GetRval)) {
2956 // [stack] ... RESULT RVAL
2957 return false;
2959 if (!emit1(JSOp::Swap)) {
2960 // [stack] ... RVAL RESULT
2961 return false;
2965 if (!emitAwaitInScope(currentScope)) {
2966 // [stack] ... RVAL? RESULT
2967 return false;
2970 if (completionKind != CompletionKind::Throw) {
2971 if (!emit1(JSOp::Swap)) {
2972 // [stack] ... RESULT RVAL
2973 return false;
2975 if (!emit1(JSOp::SetRval)) {
2976 // [stack] ... RESULT
2977 return false;
2982 // Step 6 (Handled in caller).
2984 // Step 8.
2985 if (completionKind != CompletionKind::Throw) {
2986 // Check that the "return" result is an object.
2987 if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) {
2988 // [stack] ... RESULT
2989 return false;
2993 if (!ifReturnMethodIsDefined.emitElse()) {
2994 // [stack] ... ITER RET
2995 return false;
2998 if (!emit1(JSOp::Pop)) {
2999 // [stack] ... ITER
3000 return false;
3003 if (!ifReturnMethodIsDefined.emitEnd()) {
3004 return false;
3007 if (completionKind == CompletionKind::Throw) {
3008 if (!tryCatch->emitCatch()) {
3009 // [stack] ... ITER EXC
3010 return false;
3013 // Just ignore the exception thrown by call and await.
3014 if (!emit1(JSOp::Pop)) {
3015 // [stack] ... ITER
3016 return false;
3019 if (!tryCatch->emitEnd()) {
3020 // [stack] ... ITER
3021 return false;
3025 // Step 9 (Handled in caller).
3027 return emit1(JSOp::Pop);
3028 // [stack] ...
3031 template <typename InnerEmitter>
3032 bool BytecodeEmitter::wrapWithDestructuringTryNote(int32_t iterDepth,
3033 InnerEmitter emitter) {
3034 MOZ_ASSERT(bytecodeSection().stackDepth() >= iterDepth);
3036 // Pad a nop at the beginning of the bytecode covered by the trynote so
3037 // that when unwinding environments, we may unwind to the scope
3038 // corresponding to the pc *before* the start, in case the first bytecode
3039 // emitted by |emitter| is the start of an inner scope. See comment above
3040 // UnwindEnvironmentToTryPc.
3041 if (!emit1(JSOp::TryDestructuring)) {
3042 return false;
3045 BytecodeOffset start = bytecodeSection().offset();
3046 if (!emitter(this)) {
3047 return false;
3049 BytecodeOffset end = bytecodeSection().offset();
3050 if (start != end) {
3051 return addTryNote(TryNoteKind::Destructuring, iterDepth, start, end);
3053 return true;
3056 bool BytecodeEmitter::emitDefault(ParseNode* defaultExpr, ParseNode* pattern) {
3057 // [stack] VALUE
3059 DefaultEmitter de(this);
3060 if (!de.prepareForDefault()) {
3061 // [stack]
3062 return false;
3064 if (!emitInitializer(defaultExpr, pattern)) {
3065 // [stack] DEFAULTVALUE
3066 return false;
3068 if (!de.emitEnd()) {
3069 // [stack] VALUE/DEFAULTVALUE
3070 return false;
3072 return true;
3075 bool BytecodeEmitter::emitAnonymousFunctionWithName(
3076 ParseNode* node, TaggedParserAtomIndex name) {
3077 MOZ_ASSERT(node->isDirectRHSAnonFunction());
3079 if (node->is<FunctionNode>()) {
3080 // Function doesn't have 'name' property at this point.
3081 // Set function's name at compile time.
3082 if (!setFunName(node->as<FunctionNode>().funbox(), name)) {
3083 return false;
3086 return emitTree(node);
3089 MOZ_ASSERT(node->is<ClassNode>());
3091 return emitClass(&node->as<ClassNode>(), ClassNameKind::InferredName, name);
3094 bool BytecodeEmitter::emitAnonymousFunctionWithComputedName(
3095 ParseNode* node, FunctionPrefixKind prefixKind) {
3096 MOZ_ASSERT(node->isDirectRHSAnonFunction());
3098 if (node->is<FunctionNode>()) {
3099 if (!emitTree(node)) {
3100 // [stack] NAME FUN
3101 return false;
3103 if (!emitDupAt(1)) {
3104 // [stack] NAME FUN NAME
3105 return false;
3107 if (!emit2(JSOp::SetFunName, uint8_t(prefixKind))) {
3108 // [stack] NAME FUN
3109 return false;
3111 return true;
3114 MOZ_ASSERT(node->is<ClassNode>());
3115 MOZ_ASSERT(prefixKind == FunctionPrefixKind::None);
3117 return emitClass(&node->as<ClassNode>(), ClassNameKind::ComputedName);
3120 bool BytecodeEmitter::setFunName(FunctionBox* funbox,
3121 TaggedParserAtomIndex name) {
3122 // The inferred name may already be set if this function is an interpreted
3123 // lazy function and we OOM'ed after we set the inferred name the first
3124 // time.
3125 if (funbox->hasInferredName()) {
3126 MOZ_ASSERT(!funbox->emitBytecode);
3127 MOZ_ASSERT(funbox->displayAtom() == name);
3129 return true;
3132 funbox->setInferredName(name);
3133 return true;
3136 bool BytecodeEmitter::emitInitializer(ParseNode* initializer,
3137 ParseNode* pattern) {
3138 if (initializer->isDirectRHSAnonFunction()) {
3139 MOZ_ASSERT(!pattern->isInParens());
3140 auto name = pattern->as<NameNode>().name();
3141 if (!emitAnonymousFunctionWithName(initializer, name)) {
3142 return false;
3144 } else {
3145 if (!emitTree(initializer)) {
3146 return false;
3150 return true;
3153 bool BytecodeEmitter::emitDestructuringOpsArray(ListNode* pattern,
3154 DestructuringFlavor flav) {
3155 MOZ_ASSERT(getSelfHostedIterFor(pattern) == SelfHostedIter::Deny,
3156 "array destructuring is prohibited in self-hosted code because it"
3157 "can run user-modifiable iteration code");
3158 MOZ_ASSERT(pattern->isKind(ParseNodeKind::ArrayExpr));
3159 MOZ_ASSERT(bytecodeSection().stackDepth() != 0);
3161 // Here's pseudo code for |let [a, b, , c=y, ...d] = x;|
3163 // Lines that are annotated "covered by trynote" mean that upon throwing
3164 // an exception, IteratorClose is called on iter only if done is false.
3166 // let x, y;
3167 // let a, b, c, d;
3168 // let iter, next, lref, result, done, value; // stack values
3170 // // NOTE: the fast path for this example is not applicable, because of
3171 // // the spread and the assignment |c=y|, but it is documented here for a
3172 // // simpler example, |let [a,b] = x;|
3173 // //
3174 // // if (IsOptimizableArray(x)) {
3175 // // a = x[0];
3176 // // b = x[1];
3177 // // goto end: // (skip everything below)
3178 // // }
3180 // iter = x[Symbol.iterator]();
3181 // next = iter.next;
3183 // // ==== emitted by loop for a ====
3184 // lref = GetReference(a); // covered by trynote
3186 // result = Call(next, iter);
3187 // done = result.done;
3189 // if (done)
3190 // value = undefined;
3191 // else
3192 // value = result.value;
3194 // SetOrInitialize(lref, value); // covered by trynote
3196 // // ==== emitted by loop for b ====
3197 // lref = GetReference(b); // covered by trynote
3199 // if (done) {
3200 // value = undefined;
3201 // } else {
3202 // result = Call(next, iter);
3203 // done = result.done;
3204 // if (done)
3205 // value = undefined;
3206 // else
3207 // value = result.value;
3208 // }
3210 // SetOrInitialize(lref, value); // covered by trynote
3212 // // ==== emitted by loop for elision ====
3213 // if (done) {
3214 // value = undefined;
3215 // } else {
3216 // result = Call(next, iter);
3217 // done = result.done;
3218 // if (done)
3219 // value = undefined;
3220 // else
3221 // value = result.value;
3222 // }
3224 // // ==== emitted by loop for c ====
3225 // lref = GetReference(c); // covered by trynote
3227 // if (done) {
3228 // value = undefined;
3229 // } else {
3230 // result = Call(next, iter);
3231 // done = result.done;
3232 // if (done)
3233 // value = undefined;
3234 // else
3235 // value = result.value;
3236 // }
3238 // if (value === undefined)
3239 // value = y; // covered by trynote
3241 // SetOrInitialize(lref, value); // covered by trynote
3243 // // ==== emitted by loop for d ====
3244 // lref = GetReference(d); // covered by trynote
3246 // if (done)
3247 // value = [];
3248 // else
3249 // value = [...iter];
3251 // SetOrInitialize(lref, value); // covered by trynote
3253 // // === emitted after loop ===
3254 // if (!done)
3255 // IteratorClose(iter);
3257 // end:
3259 bool isEligibleForArrayOptimizations = true;
3260 for (ParseNode* member : pattern->contents()) {
3261 switch (member->getKind()) {
3262 case ParseNodeKind::Elision:
3263 break;
3264 case ParseNodeKind::Name: {
3265 auto name = member->as<NameNode>().name();
3266 NameLocation loc = lookupName(name);
3267 if (loc.kind() != NameLocation::Kind::ArgumentSlot &&
3268 loc.kind() != NameLocation::Kind::FrameSlot &&
3269 loc.kind() != NameLocation::Kind::EnvironmentCoordinate) {
3270 isEligibleForArrayOptimizations = false;
3272 break;
3274 default:
3275 // Unfortunately we can't handle any recursive destructuring,
3276 // because we can't guarantee that the recursed-into parts
3277 // won't run code which invalidates our constraints. We also
3278 // cannot handle ParseNodeKind::AssignExpr for similar reasons.
3279 isEligibleForArrayOptimizations = false;
3280 break;
3282 if (!isEligibleForArrayOptimizations) {
3283 break;
3287 // Use an iterator to destructure the RHS, instead of index lookup. We
3288 // must leave the *original* value on the stack.
3289 if (!emit1(JSOp::Dup)) {
3290 // [stack] ... OBJ OBJ
3291 return false;
3294 Maybe<InternalIfEmitter> ifArrayOptimizable;
3296 if (isEligibleForArrayOptimizations) {
3297 ifArrayOptimizable.emplace(
3298 this, BranchEmitterBase::LexicalKind::MayContainLexicalAccessInBranch);
3300 if (!emit1(JSOp::Dup)) {
3301 // [stack] OBJ OBJ
3302 return false;
3305 if (!emit1(JSOp::OptimizeGetIterator)) {
3306 // [stack] OBJ OBJ IS_OPTIMIZABLE
3307 return false;
3310 if (!ifArrayOptimizable->emitThenElse()) {
3311 // [stack] OBJ OBJ
3312 return false;
3315 if (!emitAtomOp(JSOp::GetProp,
3316 TaggedParserAtomIndex::WellKnown::length())) {
3317 // [stack] OBJ LENGTH
3318 return false;
3321 if (!emit1(JSOp::Swap)) {
3322 // [stack] LENGTH OBJ
3323 return false;
3326 uint32_t idx = 0;
3327 for (ParseNode* member : pattern->contents()) {
3328 if (member->isKind(ParseNodeKind::Elision)) {
3329 idx += 1;
3330 continue;
3333 if (!emit1(JSOp::Dup)) {
3334 // [stack] LENGTH OBJ OBJ
3335 return false;
3338 if (!emitNumberOp(idx)) {
3339 // [stack] LENGTH OBJ OBJ IDX
3340 return false;
3343 if (!emit1(JSOp::Dup)) {
3344 // [stack] LENGTH OBJ OBJ IDX IDX
3345 return false;
3348 if (!emitDupAt(4)) {
3349 // [stack] LENGTH OBJ OBJ IDX IDX LENGTH
3350 return false;
3353 if (!emit1(JSOp::Lt)) {
3354 // [stack] LENGTH OBJ OBJ IDX IS_IN_DENSE_BOUNDS
3355 return false;
3358 InternalIfEmitter isInDenseBounds(this);
3359 if (!isInDenseBounds.emitThenElse()) {
3360 // [stack] LENGTH OBJ OBJ IDX
3361 return false;
3364 if (!emit1(JSOp::GetElem)) {
3365 // [stack] LENGTH OBJ VALUE
3366 return false;
3369 if (!isInDenseBounds.emitElse()) {
3370 // [stack] LENGTH OBJ OBJ IDX
3371 return false;
3374 if (!emitPopN(2)) {
3375 // [stack] LENGTH OBJ
3376 return false;
3379 if (!emit1(JSOp::Undefined)) {
3380 // [stack] LENGTH OBJ UNDEFINED
3381 return false;
3384 if (!isInDenseBounds.emitEnd()) {
3385 // [stack] LENGTH OBJ VALUE|UNDEFINED
3386 return false;
3389 if (!emitSetOrInitializeDestructuring(member, flav)) {
3390 // [stack] LENGTH OBJ
3391 return false;
3394 idx += 1;
3397 if (!emit1(JSOp::Swap)) {
3398 // [stack] OBJ LENGTH
3399 return false;
3402 if (!emit1(JSOp::Pop)) {
3403 // [stack] OBJ
3404 return false;
3407 if (!ifArrayOptimizable->emitElse()) {
3408 // [stack] OBJ OBJ
3409 return false;
3413 if (!emitIterator(SelfHostedIter::Deny)) {
3414 // [stack] ... OBJ NEXT ITER
3415 return false;
3418 // For an empty pattern [], call IteratorClose unconditionally. Nothing
3419 // else needs to be done.
3420 if (!pattern->head()) {
3421 if (!emit1(JSOp::Swap)) {
3422 // [stack] ... OBJ ITER NEXT
3423 return false;
3425 if (!emit1(JSOp::Pop)) {
3426 // [stack] ... OBJ ITER
3427 return false;
3430 if (!emitIteratorCloseInInnermostScope()) {
3431 // [stack] ... OBJ
3432 return false;
3435 if (ifArrayOptimizable.isSome()) {
3436 if (!ifArrayOptimizable->emitEnd()) {
3437 // [stack] OBJ
3438 return false;
3442 return true;
3445 // Push an initial FALSE value for DONE.
3446 if (!emit1(JSOp::False)) {
3447 // [stack] ... OBJ NEXT ITER FALSE
3448 return false;
3451 // TryNoteKind::Destructuring expects the iterator and the done value
3452 // to be the second to top and the top of the stack, respectively.
3453 // IteratorClose is called upon exception only if done is false.
3454 int32_t tryNoteDepth = bytecodeSection().stackDepth();
3456 for (ParseNode* member : pattern->contents()) {
3457 bool isFirst = member == pattern->head();
3458 DebugOnly<bool> hasNext = !!member->pn_next;
3460 ParseNode* subpattern;
3461 if (member->isKind(ParseNodeKind::Spread)) {
3462 subpattern = member->as<UnaryNode>().kid();
3464 MOZ_ASSERT(!subpattern->isKind(ParseNodeKind::AssignExpr));
3465 } else {
3466 subpattern = member;
3469 ParseNode* lhsPattern = subpattern;
3470 ParseNode* pndefault = nullptr;
3471 if (subpattern->isKind(ParseNodeKind::AssignExpr)) {
3472 lhsPattern = subpattern->as<AssignmentNode>().left();
3473 pndefault = subpattern->as<AssignmentNode>().right();
3476 // Number of stack slots emitted for the LHS reference.
3477 size_t emitted = 0;
3479 // Spec requires LHS reference to be evaluated first.
3480 bool isElision = lhsPattern->isKind(ParseNodeKind::Elision);
3481 if (!isElision) {
3482 auto emitLHSRef = [lhsPattern, &emitted](BytecodeEmitter* bce) {
3483 return bce->emitDestructuringLHSRef(lhsPattern, &emitted);
3484 // [stack] ... OBJ NEXT ITER DONE LREF*
3486 if (!wrapWithDestructuringTryNote(tryNoteDepth, emitLHSRef)) {
3487 return false;
3491 // Pick the DONE value to the top of the stack.
3492 if (emitted) {
3493 if (!emitPickN(emitted)) {
3494 // [stack] ... OBJ NEXT ITER LREF* DONE
3495 return false;
3499 if (isFirst) {
3500 // If this element is the first, DONE is always FALSE, so pop it.
3502 // Non-first elements should emit if-else depending on the
3503 // member pattern, below.
3504 if (!emit1(JSOp::Pop)) {
3505 // [stack] ... OBJ NEXT ITER LREF*
3506 return false;
3510 if (member->isKind(ParseNodeKind::Spread)) {
3511 InternalIfEmitter ifThenElse(this);
3512 if (!isFirst) {
3513 // If spread is not the first element of the pattern,
3514 // iterator can already be completed.
3515 // [stack] ... OBJ NEXT ITER LREF* DONE
3517 if (!ifThenElse.emitThenElse()) {
3518 // [stack] ... OBJ NEXT ITER LREF*
3519 return false;
3522 if (!emitUint32Operand(JSOp::NewArray, 0)) {
3523 // [stack] ... OBJ NEXT ITER LREF* ARRAY
3524 return false;
3526 if (!ifThenElse.emitElse()) {
3527 // [stack] ... OBJ NEXT ITER LREF*
3528 return false;
3532 // If iterator is not completed, create a new array with the rest
3533 // of the iterator.
3534 if (!emitDupAt(emitted + 1, 2)) {
3535 // [stack] ... OBJ NEXT ITER LREF* NEXT ITER
3536 return false;
3538 if (!emitUint32Operand(JSOp::NewArray, 0)) {
3539 // [stack] ... OBJ NEXT ITER LREF* NEXT ITER ARRAY
3540 return false;
3542 if (!emitNumberOp(0)) {
3543 // [stack] ... OBJ NEXT ITER LREF* NEXT ITER ARRAY INDEX
3544 return false;
3546 if (!emitSpread(SelfHostedIter::Deny)) {
3547 // [stack] ... OBJ NEXT ITER LREF* ARRAY INDEX
3548 return false;
3550 if (!emit1(JSOp::Pop)) {
3551 // [stack] ... OBJ NEXT ITER LREF* ARRAY
3552 return false;
3555 if (!isFirst) {
3556 if (!ifThenElse.emitEnd()) {
3557 return false;
3559 MOZ_ASSERT(ifThenElse.pushed() == 1);
3562 // At this point the iterator is done. Unpick a TRUE value for DONE above
3563 // ITER.
3564 if (!emit1(JSOp::True)) {
3565 // [stack] ... OBJ NEXT ITER LREF* ARRAY TRUE
3566 return false;
3568 if (!emitUnpickN(emitted + 1)) {
3569 // [stack] ... OBJ NEXT ITER TRUE LREF* ARRAY
3570 return false;
3573 auto emitAssignment = [lhsPattern, flav](BytecodeEmitter* bce) {
3574 return bce->emitSetOrInitializeDestructuring(lhsPattern, flav);
3575 // [stack] ... OBJ NEXT ITER TRUE
3577 if (!wrapWithDestructuringTryNote(tryNoteDepth, emitAssignment)) {
3578 return false;
3581 MOZ_ASSERT(!hasNext);
3582 break;
3585 InternalIfEmitter ifAlreadyDone(this);
3586 if (!isFirst) {
3587 // [stack] ... OBJ NEXT ITER LREF* DONE
3589 if (!ifAlreadyDone.emitThenElse()) {
3590 // [stack] ... OBJ NEXT ITER LREF*
3591 return false;
3594 if (!emit1(JSOp::Undefined)) {
3595 // [stack] ... OBJ NEXT ITER LREF* UNDEF
3596 return false;
3598 if (!emit1(JSOp::NopDestructuring)) {
3599 // [stack] ... OBJ NEXT ITER LREF* UNDEF
3600 return false;
3603 // The iterator is done. Unpick a TRUE value for DONE above ITER.
3604 if (!emit1(JSOp::True)) {
3605 // [stack] ... OBJ NEXT ITER LREF* UNDEF TRUE
3606 return false;
3608 if (!emitUnpickN(emitted + 1)) {
3609 // [stack] ... OBJ NEXT ITER TRUE LREF* UNDEF
3610 return false;
3613 if (!ifAlreadyDone.emitElse()) {
3614 // [stack] ... OBJ NEXT ITER LREF*
3615 return false;
3619 if (!emitDupAt(emitted + 1, 2)) {
3620 // [stack] ... OBJ NEXT ITER LREF* NEXT
3621 return false;
3623 if (!emitIteratorNext(Some(pattern->pn_pos.begin))) {
3624 // [stack] ... OBJ NEXT ITER LREF* RESULT
3625 return false;
3627 if (!emit1(JSOp::Dup)) {
3628 // [stack] ... OBJ NEXT ITER LREF* RESULT RESULT
3629 return false;
3631 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::done())) {
3632 // [stack] ... OBJ NEXT ITER LREF* RESULT DONE
3633 return false;
3636 if (!emit1(JSOp::Dup)) {
3637 // [stack] ... OBJ NEXT ITER LREF* RESULT DONE DONE
3638 return false;
3640 if (!emitUnpickN(emitted + 2)) {
3641 // [stack] ... OBJ NEXT ITER DONE LREF* RESULT DONE
3642 return false;
3645 InternalIfEmitter ifDone(this);
3646 if (!ifDone.emitThenElse()) {
3647 // [stack] ... OBJ NEXT ITER DONE LREF* RESULT
3648 return false;
3651 if (!emit1(JSOp::Pop)) {
3652 // [stack] ... OBJ NEXT ITER DONE LREF*
3653 return false;
3655 if (!emit1(JSOp::Undefined)) {
3656 // [stack] ... OBJ NEXT ITER DONE LREF* UNDEF
3657 return false;
3659 if (!emit1(JSOp::NopDestructuring)) {
3660 // [stack] ... OBJ NEXT ITER DONE LREF* UNDEF
3661 return false;
3664 if (!ifDone.emitElse()) {
3665 // [stack] ... OBJ NEXT ITER DONE LREF* RESULT
3666 return false;
3669 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::value())) {
3670 // [stack] ... OBJ NEXT ITER DONE LREF* VALUE
3671 return false;
3674 if (!ifDone.emitEnd()) {
3675 return false;
3677 MOZ_ASSERT(ifDone.pushed() == 0);
3679 if (!isFirst) {
3680 if (!ifAlreadyDone.emitEnd()) {
3681 return false;
3683 MOZ_ASSERT(ifAlreadyDone.pushed() == 2);
3686 if (pndefault) {
3687 auto emitDefault = [pndefault, lhsPattern](BytecodeEmitter* bce) {
3688 return bce->emitDefault(pndefault, lhsPattern);
3689 // [stack] ... OBJ NEXT ITER DONE LREF* VALUE
3692 if (!wrapWithDestructuringTryNote(tryNoteDepth, emitDefault)) {
3693 return false;
3697 if (!isElision) {
3698 auto emitAssignment = [lhsPattern, flav](BytecodeEmitter* bce) {
3699 return bce->emitSetOrInitializeDestructuring(lhsPattern, flav);
3700 // [stack] ... OBJ NEXT ITER DONE
3703 if (!wrapWithDestructuringTryNote(tryNoteDepth, emitAssignment)) {
3704 return false;
3706 } else {
3707 if (!emit1(JSOp::Pop)) {
3708 // [stack] ... OBJ NEXT ITER DONE
3709 return false;
3714 // The last DONE value is on top of the stack. If not DONE, call
3715 // IteratorClose.
3716 // [stack] ... OBJ NEXT ITER DONE
3718 InternalIfEmitter ifDone(this);
3719 if (!ifDone.emitThenElse()) {
3720 // [stack] ... OBJ NEXT ITER
3721 return false;
3723 if (!emitPopN(2)) {
3724 // [stack] ... OBJ
3725 return false;
3727 if (!ifDone.emitElse()) {
3728 // [stack] ... OBJ NEXT ITER
3729 return false;
3731 if (!emit1(JSOp::Swap)) {
3732 // [stack] ... OBJ ITER NEXT
3733 return false;
3735 if (!emit1(JSOp::Pop)) {
3736 // [stack] ... OBJ ITER
3737 return false;
3739 if (!emitIteratorCloseInInnermostScope()) {
3740 // [stack] ... OBJ
3741 return false;
3743 if (!ifDone.emitEnd()) {
3744 return false;
3747 if (ifArrayOptimizable.isSome()) {
3748 if (!ifArrayOptimizable->emitEnd()) {
3749 // [stack] OBJ
3750 return false;
3754 return true;
3757 bool BytecodeEmitter::emitComputedPropertyName(UnaryNode* computedPropName) {
3758 MOZ_ASSERT(computedPropName->isKind(ParseNodeKind::ComputedName));
3759 return emitTree(computedPropName->kid()) && emit1(JSOp::ToPropertyKey);
3762 bool BytecodeEmitter::emitDestructuringOpsObject(ListNode* pattern,
3763 DestructuringFlavor flav) {
3764 MOZ_ASSERT(pattern->isKind(ParseNodeKind::ObjectExpr));
3766 // [stack] ... RHS
3767 MOZ_ASSERT(bytecodeSection().stackDepth() > 0);
3769 if (!emit1(JSOp::CheckObjCoercible)) {
3770 // [stack] ... RHS
3771 return false;
3774 bool needsRestPropertyExcludedSet =
3775 pattern->count() > 1 && pattern->last()->isKind(ParseNodeKind::Spread);
3776 if (needsRestPropertyExcludedSet) {
3777 if (!emitDestructuringObjRestExclusionSet(pattern)) {
3778 // [stack] ... RHS SET
3779 return false;
3782 if (!emit1(JSOp::Swap)) {
3783 // [stack] ... SET RHS
3784 return false;
3788 for (ParseNode* member : pattern->contents()) {
3789 ParseNode* subpattern;
3790 if (member->isKind(ParseNodeKind::MutateProto) ||
3791 member->isKind(ParseNodeKind::Spread)) {
3792 subpattern = member->as<UnaryNode>().kid();
3794 MOZ_ASSERT_IF(member->isKind(ParseNodeKind::Spread),
3795 !subpattern->isKind(ParseNodeKind::AssignExpr));
3796 } else {
3797 MOZ_ASSERT(member->isKind(ParseNodeKind::PropertyDefinition) ||
3798 member->isKind(ParseNodeKind::Shorthand));
3799 subpattern = member->as<BinaryNode>().right();
3802 ParseNode* lhs = subpattern;
3803 ParseNode* pndefault = nullptr;
3804 if (subpattern->isKind(ParseNodeKind::AssignExpr)) {
3805 lhs = subpattern->as<AssignmentNode>().left();
3806 pndefault = subpattern->as<AssignmentNode>().right();
3809 // Number of stack slots emitted for the LHS reference.
3810 size_t emitted = 0;
3812 // Spec requires LHS reference to be evaluated first.
3813 if (!emitDestructuringLHSRef(lhs, &emitted)) {
3814 // [stack] ... SET? RHS LREF*
3815 return false;
3818 // Duplicate the value being destructured to use as a reference base.
3819 if (!emitDupAt(emitted)) {
3820 // [stack] ... SET? RHS LREF* RHS
3821 return false;
3824 if (member->isKind(ParseNodeKind::Spread)) {
3825 if (!updateSourceCoordNotes(member->pn_pos.begin)) {
3826 return false;
3829 if (!emit1(JSOp::NewInit)) {
3830 // [stack] ... SET? RHS LREF* RHS TARGET
3831 return false;
3833 if (!emit1(JSOp::Dup)) {
3834 // [stack] ... SET? RHS LREF* RHS TARGET TARGET
3835 return false;
3837 if (!emit2(JSOp::Pick, 2)) {
3838 // [stack] ... SET? RHS LREF* TARGET TARGET RHS
3839 return false;
3842 if (needsRestPropertyExcludedSet) {
3843 if (!emit2(JSOp::Pick, emitted + 4)) {
3844 // [stack] ... RHS LREF* TARGET TARGET RHS SET
3845 return false;
3849 CopyOption option = needsRestPropertyExcludedSet ? CopyOption::Filtered
3850 : CopyOption::Unfiltered;
3851 if (!emitCopyDataProperties(option)) {
3852 // [stack] ... RHS LREF* TARGET
3853 return false;
3856 // Destructure TARGET per this member's lhs.
3857 if (!emitSetOrInitializeDestructuring(lhs, flav)) {
3858 // [stack] ... RHS
3859 return false;
3862 MOZ_ASSERT(member == pattern->last(), "Rest property is always last");
3863 break;
3866 // Now push the property value currently being matched, which is the value
3867 // of the current property name "label" on the left of a colon in the object
3868 // initialiser.
3869 if (member->isKind(ParseNodeKind::MutateProto)) {
3870 if (!emitAtomOp(JSOp::GetProp,
3871 TaggedParserAtomIndex::WellKnown::proto_())) {
3872 // [stack] ... SET? RHS LREF* PROP
3873 return false;
3875 } else {
3876 MOZ_ASSERT(member->isKind(ParseNodeKind::PropertyDefinition) ||
3877 member->isKind(ParseNodeKind::Shorthand));
3879 ParseNode* key = member->as<BinaryNode>().left();
3880 if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
3881 key->isKind(ParseNodeKind::StringExpr)) {
3882 if (!emitAtomOp(JSOp::GetProp, key->as<NameNode>().atom())) {
3883 // [stack] ... SET? RHS LREF* PROP
3884 return false;
3886 } else {
3887 if (key->isKind(ParseNodeKind::NumberExpr)) {
3888 if (!emitNumberOp(key->as<NumericLiteral>().value())) {
3889 // [stack]... SET? RHS LREF* RHS KEY
3890 return false;
3892 } else {
3893 // Otherwise this is a computed property name. BigInt keys are parsed
3894 // as (synthetic) computed property names, too.
3895 MOZ_ASSERT(key->isKind(ParseNodeKind::ComputedName));
3897 if (!emitComputedPropertyName(&key->as<UnaryNode>())) {
3898 // [stack] ... SET? RHS LREF* RHS KEY
3899 return false;
3902 // Add the computed property key to the exclusion set.
3903 if (needsRestPropertyExcludedSet) {
3904 if (!emitDupAt(emitted + 3)) {
3905 // [stack] ... SET RHS LREF* RHS KEY SET
3906 return false;
3908 if (!emitDupAt(1)) {
3909 // [stack] ... SET RHS LREF* RHS KEY SET KEY
3910 return false;
3912 if (!emit1(JSOp::Undefined)) {
3913 // [stack] ... SET RHS LREF* RHS KEY SET KEY UNDEFINED
3914 return false;
3916 if (!emit1(JSOp::InitElem)) {
3917 // [stack] ... SET RHS LREF* RHS KEY SET
3918 return false;
3920 if (!emit1(JSOp::Pop)) {
3921 // [stack] ... SET RHS LREF* RHS KEY
3922 return false;
3927 // Get the property value.
3928 if (!emitElemOpBase(JSOp::GetElem)) {
3929 // [stack] ... SET? RHS LREF* PROP
3930 return false;
3935 if (pndefault) {
3936 if (!emitDefault(pndefault, lhs)) {
3937 // [stack] ... SET? RHS LREF* VALUE
3938 return false;
3942 // Destructure PROP per this member's lhs.
3943 if (!emitSetOrInitializeDestructuring(lhs, flav)) {
3944 // [stack] ... SET? RHS
3945 return false;
3949 return true;
3952 static bool IsDestructuringRestExclusionSetObjLiteralCompatible(
3953 ListNode* pattern) {
3954 uint32_t propCount = 0;
3955 for (ParseNode* member : pattern->contents()) {
3956 if (member->isKind(ParseNodeKind::Spread)) {
3957 MOZ_ASSERT(!member->pn_next, "unexpected trailing element after spread");
3958 break;
3961 propCount++;
3963 if (member->isKind(ParseNodeKind::MutateProto)) {
3964 continue;
3967 ParseNode* key = member->as<BinaryNode>().left();
3968 if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
3969 key->isKind(ParseNodeKind::StringExpr)) {
3970 continue;
3973 // Number and BigInt keys aren't yet supported. Computed property names need
3974 // to be added dynamically.
3975 MOZ_ASSERT(key->isKind(ParseNodeKind::NumberExpr) ||
3976 key->isKind(ParseNodeKind::BigIntExpr) ||
3977 key->isKind(ParseNodeKind::ComputedName));
3978 return false;
3981 if (propCount > SharedPropMap::MaxPropsForNonDictionary) {
3982 // JSOp::NewObject cannot accept dictionary-mode objects.
3983 return false;
3986 return true;
3989 bool BytecodeEmitter::emitDestructuringObjRestExclusionSet(ListNode* pattern) {
3990 MOZ_ASSERT(pattern->isKind(ParseNodeKind::ObjectExpr));
3991 MOZ_ASSERT(pattern->last()->isKind(ParseNodeKind::Spread));
3993 // See if we can use ObjLiteral to construct the exclusion set object.
3994 if (IsDestructuringRestExclusionSetObjLiteralCompatible(pattern)) {
3995 if (!emitDestructuringRestExclusionSetObjLiteral(pattern)) {
3996 // [stack] OBJ
3997 return false;
3999 } else {
4000 // Take the slow but sure way and start off with a blank object.
4001 if (!emit1(JSOp::NewInit)) {
4002 // [stack] OBJ
4003 return false;
4007 for (ParseNode* member : pattern->contents()) {
4008 if (member->isKind(ParseNodeKind::Spread)) {
4009 MOZ_ASSERT(!member->pn_next, "unexpected trailing element after spread");
4010 break;
4013 TaggedParserAtomIndex pnatom;
4014 if (member->isKind(ParseNodeKind::MutateProto)) {
4015 pnatom = TaggedParserAtomIndex::WellKnown::proto_();
4016 } else {
4017 ParseNode* key = member->as<BinaryNode>().left();
4018 if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
4019 key->isKind(ParseNodeKind::StringExpr)) {
4020 pnatom = key->as<NameNode>().atom();
4021 } else if (key->isKind(ParseNodeKind::NumberExpr)) {
4022 if (!emitNumberOp(key->as<NumericLiteral>().value())) {
4023 return false;
4025 } else {
4026 // Otherwise this is a computed property name which needs to be added
4027 // dynamically. BigInt keys are parsed as (synthetic) computed property
4028 // names, too.
4029 MOZ_ASSERT(key->isKind(ParseNodeKind::ComputedName));
4030 continue;
4034 // Initialize elements with |undefined|.
4035 if (!emit1(JSOp::Undefined)) {
4036 return false;
4039 if (!pnatom) {
4040 if (!emit1(JSOp::InitElem)) {
4041 return false;
4043 } else {
4044 if (!emitAtomOp(JSOp::InitProp, pnatom)) {
4045 return false;
4050 return true;
4053 bool BytecodeEmitter::emitDestructuringOps(ListNode* pattern,
4054 DestructuringFlavor flav) {
4055 if (pattern->isKind(ParseNodeKind::ArrayExpr)) {
4056 return emitDestructuringOpsArray(pattern, flav);
4058 return emitDestructuringOpsObject(pattern, flav);
4061 bool BytecodeEmitter::emitTemplateString(ListNode* templateString) {
4062 bool pushedString = false;
4064 for (ParseNode* item : templateString->contents()) {
4065 bool isString = (item->getKind() == ParseNodeKind::StringExpr ||
4066 item->getKind() == ParseNodeKind::TemplateStringExpr);
4068 // Skip empty strings. These are very common: a template string like
4069 // `${a}${b}` has three empty strings and without this optimization
4070 // we'd emit four JSOp::Add operations instead of just one.
4071 if (isString && item->as<NameNode>().atom() ==
4072 TaggedParserAtomIndex::WellKnown::empty()) {
4073 continue;
4076 if (!isString) {
4077 // We update source notes before emitting the expression
4078 if (!updateSourceCoordNotes(item->pn_pos.begin)) {
4079 return false;
4083 if (!emitTree(item)) {
4084 return false;
4087 if (!isString) {
4088 // We need to convert the expression to a string
4089 if (!emit1(JSOp::ToString)) {
4090 return false;
4094 if (pushedString) {
4095 // We've pushed two strings onto the stack. Add them together, leaving
4096 // just one.
4097 if (!emit1(JSOp::Add)) {
4098 return false;
4100 } else {
4101 pushedString = true;
4105 if (!pushedString) {
4106 // All strings were empty, this can happen for something like `${""}`.
4107 // Just push an empty string.
4108 if (!emitStringOp(JSOp::String,
4109 TaggedParserAtomIndex::WellKnown::empty())) {
4110 return false;
4114 return true;
4117 bool BytecodeEmitter::emitDeclarationList(ListNode* declList) {
4118 for (ParseNode* decl : declList->contents()) {
4119 ParseNode* pattern;
4120 ParseNode* initializer;
4121 if (decl->isKind(ParseNodeKind::Name)) {
4122 pattern = decl;
4123 initializer = nullptr;
4124 } else {
4125 AssignmentNode* assignNode = &decl->as<AssignmentNode>();
4126 pattern = assignNode->left();
4127 initializer = assignNode->right();
4130 if (pattern->isKind(ParseNodeKind::Name)) {
4131 // initializer can be null here.
4132 if (!emitSingleDeclaration(declList, &pattern->as<NameNode>(),
4133 initializer)) {
4134 return false;
4136 } else {
4137 MOZ_ASSERT(pattern->isKind(ParseNodeKind::ArrayExpr) ||
4138 pattern->isKind(ParseNodeKind::ObjectExpr));
4139 MOZ_ASSERT(initializer != nullptr);
4141 if (!updateSourceCoordNotes(initializer->pn_pos.begin)) {
4142 return false;
4144 if (!markStepBreakpoint()) {
4145 return false;
4147 if (!emitTree(initializer)) {
4148 return false;
4151 if (!emitDestructuringOps(&pattern->as<ListNode>(),
4152 DestructuringFlavor::Declaration)) {
4153 return false;
4156 if (!emit1(JSOp::Pop)) {
4157 return false;
4161 return true;
4164 bool BytecodeEmitter::emitSingleDeclaration(ListNode* declList, NameNode* decl,
4165 ParseNode* initializer) {
4166 MOZ_ASSERT(decl->isKind(ParseNodeKind::Name));
4168 // Nothing to do for initializer-less 'var' declarations, as there's no TDZ.
4169 if (!initializer && declList->isKind(ParseNodeKind::VarStmt)) {
4170 return true;
4173 auto nameAtom = decl->name();
4174 NameOpEmitter noe(this, nameAtom, NameOpEmitter::Kind::Initialize);
4175 if (!noe.prepareForRhs()) {
4176 // [stack] ENV?
4177 return false;
4179 if (!initializer) {
4180 // Lexical declarations are initialized to undefined without an
4181 // initializer.
4182 MOZ_ASSERT(declList->isKind(ParseNodeKind::LetDecl),
4183 "var declarations without initializers handled above, "
4184 "and const declarations must have initializers");
4185 if (!emit1(JSOp::Undefined)) {
4186 // [stack] ENV? UNDEF
4187 return false;
4189 } else {
4190 MOZ_ASSERT(initializer);
4192 if (!updateSourceCoordNotes(initializer->pn_pos.begin)) {
4193 return false;
4195 if (!markStepBreakpoint()) {
4196 return false;
4198 if (!emitInitializer(initializer, decl)) {
4199 // [stack] ENV? V
4200 return false;
4203 if (!noe.emitAssignment()) {
4204 // [stack] V
4205 return false;
4207 if (!emit1(JSOp::Pop)) {
4208 // [stack]
4209 return false;
4212 return true;
4215 bool BytecodeEmitter::emitAssignmentRhs(
4216 ParseNode* rhs, TaggedParserAtomIndex anonFunctionName) {
4217 if (rhs->isDirectRHSAnonFunction()) {
4218 if (anonFunctionName) {
4219 return emitAnonymousFunctionWithName(rhs, anonFunctionName);
4221 return emitAnonymousFunctionWithComputedName(rhs, FunctionPrefixKind::None);
4223 return emitTree(rhs);
4226 // The RHS value to assign is already on the stack, i.e., the next enumeration
4227 // value in a for-in or for-of loop. Offset is the location in the stack of the
4228 // already-emitted rhs. If we emitted a JSOp::BindName or JSOp::BindGName, then
4229 // the scope is on the top of the stack and we need to dig one deeper to get
4230 // the right RHS value.
4231 bool BytecodeEmitter::emitAssignmentRhs(uint8_t offset) {
4232 if (offset != 1) {
4233 return emitPickN(offset - 1);
4236 return true;
4239 static inline JSOp CompoundAssignmentParseNodeKindToJSOp(ParseNodeKind pnk) {
4240 switch (pnk) {
4241 case ParseNodeKind::InitExpr:
4242 return JSOp::Nop;
4243 case ParseNodeKind::AssignExpr:
4244 return JSOp::Nop;
4245 case ParseNodeKind::AddAssignExpr:
4246 return JSOp::Add;
4247 case ParseNodeKind::SubAssignExpr:
4248 return JSOp::Sub;
4249 case ParseNodeKind::BitOrAssignExpr:
4250 return JSOp::BitOr;
4251 case ParseNodeKind::BitXorAssignExpr:
4252 return JSOp::BitXor;
4253 case ParseNodeKind::BitAndAssignExpr:
4254 return JSOp::BitAnd;
4255 case ParseNodeKind::LshAssignExpr:
4256 return JSOp::Lsh;
4257 case ParseNodeKind::RshAssignExpr:
4258 return JSOp::Rsh;
4259 case ParseNodeKind::UrshAssignExpr:
4260 return JSOp::Ursh;
4261 case ParseNodeKind::MulAssignExpr:
4262 return JSOp::Mul;
4263 case ParseNodeKind::DivAssignExpr:
4264 return JSOp::Div;
4265 case ParseNodeKind::ModAssignExpr:
4266 return JSOp::Mod;
4267 case ParseNodeKind::PowAssignExpr:
4268 return JSOp::Pow;
4269 case ParseNodeKind::CoalesceAssignExpr:
4270 case ParseNodeKind::OrAssignExpr:
4271 case ParseNodeKind::AndAssignExpr:
4272 // Short-circuit assignment operators are handled elsewhere.
4273 [[fallthrough]];
4274 default:
4275 MOZ_CRASH("unexpected compound assignment op");
4279 bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs,
4280 ParseNode* rhs) {
4281 JSOp compoundOp = CompoundAssignmentParseNodeKindToJSOp(kind);
4282 bool isCompound = compoundOp != JSOp::Nop;
4283 bool isInit = kind == ParseNodeKind::InitExpr;
4285 // We estimate the number of properties this could create
4286 // if used as constructor merely by counting this.foo = assignment
4287 // or init expressions;
4289 // This currently doesn't handle this[x] = foo;
4290 if (isInit || kind == ParseNodeKind::AssignExpr) {
4291 if (lhs->isKind(ParseNodeKind::DotExpr)) {
4292 if (lhs->as<PropertyAccess>().expression().isKind(
4293 ParseNodeKind::ThisExpr)) {
4294 propertyAdditionEstimate++;
4299 MOZ_ASSERT_IF(isInit, lhs->isKind(ParseNodeKind::DotExpr) ||
4300 lhs->isKind(ParseNodeKind::ElemExpr) ||
4301 lhs->isKind(ParseNodeKind::PrivateMemberExpr));
4303 // |name| is used within NameOpEmitter, so its lifetime must surpass |noe|.
4304 TaggedParserAtomIndex name;
4306 Maybe<NameOpEmitter> noe;
4307 Maybe<PropOpEmitter> poe;
4308 Maybe<ElemOpEmitter> eoe;
4309 Maybe<PrivateOpEmitter> xoe;
4311 // Deal with non-name assignments.
4312 uint8_t offset = 1;
4314 // Purpose of anonFunctionName:
4316 // In normal name assignments (`f = function(){}`), an anonymous function gets
4317 // an inferred name based on the left-hand side name node.
4319 // In normal property assignments (`obj.x = function(){}`), the anonymous
4320 // function does not have a computed name, and rhs->isDirectRHSAnonFunction()
4321 // will be false (and anonFunctionName will not be used). However, in field
4322 // initializers (`class C { x = function(){} }`), field initialization is
4323 // implemented via a property or elem assignment (where we are now), and
4324 // rhs->isDirectRHSAnonFunction() is set - so we'll assign the name of the
4325 // function.
4326 TaggedParserAtomIndex anonFunctionName;
4328 switch (lhs->getKind()) {
4329 case ParseNodeKind::Name: {
4330 name = lhs->as<NameNode>().name();
4331 anonFunctionName = name;
4332 noe.emplace(this, name,
4333 isCompound ? NameOpEmitter::Kind::CompoundAssignment
4334 : NameOpEmitter::Kind::SimpleAssignment);
4335 break;
4337 case ParseNodeKind::DotExpr: {
4338 PropertyAccess* prop = &lhs->as<PropertyAccess>();
4339 bool isSuper = prop->isSuper();
4340 poe.emplace(this,
4341 isCompound ? PropOpEmitter::Kind::CompoundAssignment
4342 : isInit ? PropOpEmitter::Kind::PropInit
4343 : PropOpEmitter::Kind::SimpleAssignment,
4344 isSuper ? PropOpEmitter::ObjKind::Super
4345 : PropOpEmitter::ObjKind::Other);
4346 if (!poe->prepareForObj()) {
4347 return false;
4349 anonFunctionName = prop->name();
4350 if (isSuper) {
4351 UnaryNode* base = &prop->expression().as<UnaryNode>();
4352 if (!emitGetThisForSuperBase(base)) {
4353 // [stack] THIS SUPERBASE
4354 return false;
4356 // SUPERBASE is pushed onto THIS later in poe->emitGet below.
4357 offset += 2;
4358 } else {
4359 if (!emitTree(&prop->expression())) {
4360 // [stack] OBJ
4361 return false;
4363 offset += 1;
4365 break;
4367 case ParseNodeKind::ElemExpr: {
4368 PropertyByValue* elem = &lhs->as<PropertyByValue>();
4369 bool isSuper = elem->isSuper();
4370 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
4371 eoe.emplace(this,
4372 isCompound ? ElemOpEmitter::Kind::CompoundAssignment
4373 : isInit ? ElemOpEmitter::Kind::PropInit
4374 : ElemOpEmitter::Kind::SimpleAssignment,
4375 isSuper ? ElemOpEmitter::ObjKind::Super
4376 : ElemOpEmitter::ObjKind::Other);
4377 if (!emitElemObjAndKey(elem, isSuper, *eoe)) {
4378 // [stack] # if Super
4379 // [stack] THIS KEY
4380 // [stack] # otherwise
4381 // [stack] OBJ KEY
4382 return false;
4384 if (isSuper) {
4385 // SUPERBASE is pushed onto KEY in eoe->emitGet below.
4386 offset += 3;
4387 } else {
4388 offset += 2;
4390 break;
4392 case ParseNodeKind::PrivateMemberExpr: {
4393 PrivateMemberAccess* privateExpr = &lhs->as<PrivateMemberAccess>();
4394 xoe.emplace(this,
4395 isCompound ? PrivateOpEmitter::Kind::CompoundAssignment
4396 : isInit ? PrivateOpEmitter::Kind::PropInit
4397 : PrivateOpEmitter::Kind::SimpleAssignment,
4398 privateExpr->privateName().name());
4399 if (!emitTree(&privateExpr->expression())) {
4400 // [stack] OBJ
4401 return false;
4403 if (!xoe->emitReference()) {
4404 // [stack] OBJ KEY
4405 return false;
4407 offset += xoe->numReferenceSlots();
4408 break;
4410 case ParseNodeKind::ArrayExpr:
4411 case ParseNodeKind::ObjectExpr:
4412 break;
4413 case ParseNodeKind::CallExpr:
4414 if (!emitTree(lhs)) {
4415 return false;
4418 // Assignment to function calls is forbidden, but we have to make the
4419 // call first. Now we can throw.
4420 if (!emit2(JSOp::ThrowMsg, uint8_t(ThrowMsgKind::AssignToCall))) {
4421 return false;
4424 // Rebalance the stack to placate stack-depth assertions.
4425 if (!emit1(JSOp::Pop)) {
4426 return false;
4428 break;
4429 default:
4430 MOZ_ASSERT(0);
4433 if (isCompound) {
4434 MOZ_ASSERT(rhs);
4435 switch (lhs->getKind()) {
4436 case ParseNodeKind::DotExpr: {
4437 PropertyAccess* prop = &lhs->as<PropertyAccess>();
4438 if (!poe->emitGet(prop->key().atom())) {
4439 // [stack] # if Super
4440 // [stack] THIS SUPERBASE PROP
4441 // [stack] # otherwise
4442 // [stack] OBJ PROP
4443 return false;
4445 break;
4447 case ParseNodeKind::ElemExpr: {
4448 if (!eoe->emitGet()) {
4449 // [stack] KEY THIS OBJ ELEM
4450 return false;
4452 break;
4454 case ParseNodeKind::PrivateMemberExpr: {
4455 if (!xoe->emitGet()) {
4456 // [stack] OBJ KEY VALUE
4457 return false;
4459 break;
4461 case ParseNodeKind::CallExpr:
4462 // We just emitted a JSOp::ThrowMsg and popped the call's return
4463 // value. Push a random value to make sure the stack depth is
4464 // correct.
4465 if (!emit1(JSOp::Null)) {
4466 // [stack] NULL
4467 return false;
4469 break;
4470 default:;
4474 switch (lhs->getKind()) {
4475 case ParseNodeKind::Name:
4476 if (!noe->prepareForRhs()) {
4477 // [stack] ENV? VAL?
4478 return false;
4480 offset += noe->emittedBindOp();
4481 break;
4482 case ParseNodeKind::DotExpr:
4483 if (!poe->prepareForRhs()) {
4484 // [stack] # if Simple Assignment with Super
4485 // [stack] THIS SUPERBASE
4486 // [stack] # if Simple Assignment with other
4487 // [stack] OBJ
4488 // [stack] # if Compound Assignment with Super
4489 // [stack] THIS SUPERBASE PROP
4490 // [stack] # if Compound Assignment with other
4491 // [stack] OBJ PROP
4492 return false;
4494 break;
4495 case ParseNodeKind::ElemExpr:
4496 if (!eoe->prepareForRhs()) {
4497 // [stack] # if Simple Assignment with Super
4498 // [stack] THIS KEY SUPERBASE
4499 // [stack] # if Simple Assignment with other
4500 // [stack] OBJ KEY
4501 // [stack] # if Compound Assignment with Super
4502 // [stack] THIS KEY SUPERBASE ELEM
4503 // [stack] # if Compound Assignment with other
4504 // [stack] OBJ KEY ELEM
4505 return false;
4507 break;
4508 case ParseNodeKind::PrivateMemberExpr:
4509 // no stack adjustment needed
4510 break;
4511 default:
4512 break;
4515 if (rhs) {
4516 if (!emitAssignmentRhs(rhs, anonFunctionName)) {
4517 // [stack] ... VAL? RHS
4518 return false;
4520 } else {
4521 // Assumption: Things with pre-emitted RHS values never need to be named.
4522 if (!emitAssignmentRhs(offset)) {
4523 // [stack] ... VAL? RHS
4524 return false;
4528 /* If += etc., emit the binary operator with a hint for the decompiler. */
4529 if (isCompound) {
4530 if (!emit1(compoundOp)) {
4531 // [stack] ... VAL
4532 return false;
4534 if (!emit1(JSOp::NopIsAssignOp)) {
4535 // [stack] ... VAL
4536 return false;
4540 /* Finally, emit the specialized assignment bytecode. */
4541 switch (lhs->getKind()) {
4542 case ParseNodeKind::Name: {
4543 if (!noe->emitAssignment()) {
4544 // [stack] VAL
4545 return false;
4547 break;
4549 case ParseNodeKind::DotExpr: {
4550 PropertyAccess* prop = &lhs->as<PropertyAccess>();
4551 if (!poe->emitAssignment(prop->key().atom())) {
4552 // [stack] VAL
4553 return false;
4555 break;
4557 case ParseNodeKind::CallExpr:
4558 // We threw above, so nothing to do here.
4559 break;
4560 case ParseNodeKind::ElemExpr: {
4561 if (!eoe->emitAssignment()) {
4562 // [stack] VAL
4563 return false;
4565 break;
4567 case ParseNodeKind::PrivateMemberExpr:
4568 if (!xoe->emitAssignment()) {
4569 // [stack] VAL
4570 return false;
4572 break;
4573 case ParseNodeKind::ArrayExpr:
4574 case ParseNodeKind::ObjectExpr:
4575 if (!emitDestructuringOps(&lhs->as<ListNode>(),
4576 DestructuringFlavor::Assignment)) {
4577 return false;
4579 break;
4580 default:
4581 MOZ_ASSERT(0);
4583 return true;
4586 bool BytecodeEmitter::emitShortCircuitAssignment(AssignmentNode* node) {
4587 TDZCheckCache tdzCache(this);
4589 JSOp op;
4590 switch (node->getKind()) {
4591 case ParseNodeKind::CoalesceAssignExpr:
4592 op = JSOp::Coalesce;
4593 break;
4594 case ParseNodeKind::OrAssignExpr:
4595 op = JSOp::Or;
4596 break;
4597 case ParseNodeKind::AndAssignExpr:
4598 op = JSOp::And;
4599 break;
4600 default:
4601 MOZ_CRASH("Unexpected ParseNodeKind");
4604 ParseNode* lhs = node->left();
4605 ParseNode* rhs = node->right();
4607 // |name| is used within NameOpEmitter, so its lifetime must surpass |noe|.
4608 TaggedParserAtomIndex name;
4610 // Select the appropriate emitter based on the left-hand side.
4611 Maybe<NameOpEmitter> noe;
4612 Maybe<PropOpEmitter> poe;
4613 Maybe<ElemOpEmitter> eoe;
4614 Maybe<PrivateOpEmitter> xoe;
4616 int32_t depth = bytecodeSection().stackDepth();
4618 // Number of values pushed onto the stack in addition to the lhs value.
4619 int32_t numPushed;
4621 // Evaluate the left-hand side expression and compute any stack values needed
4622 // for the assignment.
4623 switch (lhs->getKind()) {
4624 case ParseNodeKind::Name: {
4625 name = lhs->as<NameNode>().name();
4626 noe.emplace(this, name, NameOpEmitter::Kind::CompoundAssignment);
4628 if (!noe->prepareForRhs()) {
4629 // [stack] ENV? LHS
4630 return false;
4633 numPushed = noe->emittedBindOp();
4634 break;
4637 case ParseNodeKind::DotExpr: {
4638 PropertyAccess* prop = &lhs->as<PropertyAccess>();
4639 bool isSuper = prop->isSuper();
4641 poe.emplace(this, PropOpEmitter::Kind::CompoundAssignment,
4642 isSuper ? PropOpEmitter::ObjKind::Super
4643 : PropOpEmitter::ObjKind::Other);
4645 if (!poe->prepareForObj()) {
4646 return false;
4649 if (isSuper) {
4650 UnaryNode* base = &prop->expression().as<UnaryNode>();
4651 if (!emitGetThisForSuperBase(base)) {
4652 // [stack] THIS SUPERBASE
4653 return false;
4655 } else {
4656 if (!emitTree(&prop->expression())) {
4657 // [stack] OBJ
4658 return false;
4662 if (!poe->emitGet(prop->key().atom())) {
4663 // [stack] # if Super
4664 // [stack] THIS SUPERBASE LHS
4665 // [stack] # otherwise
4666 // [stack] OBJ LHS
4667 return false;
4670 if (!poe->prepareForRhs()) {
4671 // [stack] # if Super
4672 // [stack] THIS SUPERBASE LHS
4673 // [stack] # otherwise
4674 // [stack] OBJ LHS
4675 return false;
4678 numPushed = 1 + isSuper;
4679 break;
4682 case ParseNodeKind::ElemExpr: {
4683 PropertyByValue* elem = &lhs->as<PropertyByValue>();
4684 bool isSuper = elem->isSuper();
4685 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
4686 eoe.emplace(this, ElemOpEmitter::Kind::CompoundAssignment,
4687 isSuper ? ElemOpEmitter::ObjKind::Super
4688 : ElemOpEmitter::ObjKind::Other);
4690 if (!emitElemObjAndKey(elem, isSuper, *eoe)) {
4691 // [stack] # if Super
4692 // [stack] THIS KEY
4693 // [stack] # otherwise
4694 // [stack] OBJ KEY
4695 return false;
4698 if (!eoe->emitGet()) {
4699 // [stack] # if Super
4700 // [stack] THIS KEY SUPERBASE LHS
4701 // [stack] # otherwise
4702 // [stack] OBJ KEY LHS
4703 return false;
4706 if (!eoe->prepareForRhs()) {
4707 // [stack] # if Super
4708 // [stack] THIS KEY SUPERBASE LHS
4709 // [stack] # otherwise
4710 // [stack] OBJ KEY LHS
4711 return false;
4714 numPushed = 2 + isSuper;
4715 break;
4718 case ParseNodeKind::PrivateMemberExpr: {
4719 PrivateMemberAccess* privateExpr = &lhs->as<PrivateMemberAccess>();
4720 xoe.emplace(this, PrivateOpEmitter::Kind::CompoundAssignment,
4721 privateExpr->privateName().name());
4722 if (!emitTree(&privateExpr->expression())) {
4723 // [stack] OBJ
4724 return false;
4726 if (!xoe->emitReference()) {
4727 // [stack] OBJ NAME
4728 return false;
4730 if (!xoe->emitGet()) {
4731 // [stack] OBJ NAME LHS
4732 return false;
4734 numPushed = xoe->numReferenceSlots();
4735 break;
4738 default:
4739 MOZ_CRASH();
4742 MOZ_ASSERT(bytecodeSection().stackDepth() == depth + numPushed + 1);
4744 // Test for the short-circuit condition.
4745 JumpList jump;
4746 if (!emitJump(op, &jump)) {
4747 // [stack] ... LHS
4748 return false;
4751 // The short-circuit condition wasn't fulfilled, pop the left-hand side value
4752 // which was kept on the stack.
4753 if (!emit1(JSOp::Pop)) {
4754 // [stack] ...
4755 return false;
4758 if (!emitAssignmentRhs(rhs, name)) {
4759 // [stack] ... RHS
4760 return false;
4763 // Perform the actual assignment.
4764 switch (lhs->getKind()) {
4765 case ParseNodeKind::Name: {
4766 if (!noe->emitAssignment()) {
4767 // [stack] RHS
4768 return false;
4770 break;
4773 case ParseNodeKind::DotExpr: {
4774 PropertyAccess* prop = &lhs->as<PropertyAccess>();
4776 if (!poe->emitAssignment(prop->key().atom())) {
4777 // [stack] RHS
4778 return false;
4780 break;
4783 case ParseNodeKind::ElemExpr: {
4784 if (!eoe->emitAssignment()) {
4785 // [stack] RHS
4786 return false;
4788 break;
4791 case ParseNodeKind::PrivateMemberExpr:
4792 if (!xoe->emitAssignment()) {
4793 // [stack] RHS
4794 return false;
4796 break;
4798 default:
4799 MOZ_CRASH();
4802 MOZ_ASSERT(bytecodeSection().stackDepth() == depth + 1);
4804 // Join with the short-circuit jump and pop anything left on the stack.
4805 if (numPushed > 0) {
4806 JumpList jumpAroundPop;
4807 if (!emitJump(JSOp::Goto, &jumpAroundPop)) {
4808 // [stack] RHS
4809 return false;
4812 if (!emitJumpTargetAndPatch(jump)) {
4813 // [stack] ... LHS
4814 return false;
4817 // Reconstruct the stack depth after the jump.
4818 bytecodeSection().setStackDepth(depth + 1 + numPushed);
4820 // Move the left-hand side value to the bottom and pop the rest.
4821 if (!emitUnpickN(numPushed)) {
4822 // [stack] LHS ...
4823 return false;
4825 if (!emitPopN(numPushed)) {
4826 // [stack] LHS
4827 return false;
4830 if (!emitJumpTargetAndPatch(jumpAroundPop)) {
4831 // [stack] LHS | RHS
4832 return false;
4834 } else {
4835 if (!emitJumpTargetAndPatch(jump)) {
4836 // [stack] LHS | RHS
4837 return false;
4841 MOZ_ASSERT(bytecodeSection().stackDepth() == depth + 1);
4843 return true;
4846 bool BytecodeEmitter::emitCallSiteObjectArray(ObjLiteralWriter& writer,
4847 ListNode* cookedOrRaw,
4848 ParseNode* head, uint32_t count) {
4849 DebugOnly<size_t> idx = 0;
4850 for (ParseNode* pn : cookedOrRaw->contentsFrom(head)) {
4851 MOZ_ASSERT(pn->isKind(ParseNodeKind::TemplateStringExpr) ||
4852 pn->isKind(ParseNodeKind::RawUndefinedExpr));
4854 if (!emitObjLiteralValue(writer, pn)) {
4855 return false;
4857 idx++;
4859 MOZ_ASSERT(idx == count);
4861 return true;
4864 bool BytecodeEmitter::emitCallSiteObject(CallSiteNode* callSiteObj) {
4865 constexpr JSOp op = JSOp::CallSiteObj;
4867 // The first element of a call-site node is the raw-values list. Skip over it.
4868 ListNode* raw = callSiteObj->rawNodes();
4869 MOZ_ASSERT(raw->isKind(ParseNodeKind::ArrayExpr));
4870 ParseNode* head = callSiteObj->head()->pn_next;
4872 uint32_t count = callSiteObj->count() - 1;
4873 MOZ_ASSERT(count == raw->count());
4875 ObjLiteralWriter writer;
4876 writer.beginCallSiteObj(op);
4877 writer.beginDenseArrayElements();
4879 // Write elements of the two arrays: the 'cooked' values followed by the
4880 // 'raw' values.
4881 MOZ_RELEASE_ASSERT(count < UINT32_MAX / 2,
4882 "Number of elements for both arrays must fit in uint32_t");
4883 if (!emitCallSiteObjectArray(writer, callSiteObj, head, count)) {
4884 return false;
4886 if (!emitCallSiteObjectArray(writer, raw, raw->head(), count)) {
4887 return false;
4890 GCThingIndex cookedIndex;
4891 if (!addObjLiteralData(writer, &cookedIndex)) {
4892 return false;
4895 MOZ_ASSERT(sc->hasCallSiteObj());
4897 return emitInternedObjectOp(cookedIndex, op);
4900 bool BytecodeEmitter::emitCatch(BinaryNode* catchClause) {
4901 // We must be nested under a try-finally statement.
4902 MOZ_ASSERT(innermostNestableControl->is<TryFinallyControl>());
4904 ParseNode* param = catchClause->left();
4905 if (!param) {
4906 // Catch parameter was omitted; just discard the exception.
4907 if (!emit1(JSOp::Pop)) {
4908 return false;
4910 } else {
4911 switch (param->getKind()) {
4912 case ParseNodeKind::ArrayExpr:
4913 case ParseNodeKind::ObjectExpr:
4914 if (!emitDestructuringOps(&param->as<ListNode>(),
4915 DestructuringFlavor::Declaration)) {
4916 return false;
4918 if (!emit1(JSOp::Pop)) {
4919 return false;
4921 break;
4923 case ParseNodeKind::Name:
4924 if (!emitLexicalInitialization(&param->as<NameNode>())) {
4925 return false;
4927 if (!emit1(JSOp::Pop)) {
4928 return false;
4930 break;
4932 default:
4933 MOZ_ASSERT(0);
4937 /* Emit the catch body. */
4938 return emitTree(catchClause->right());
4941 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See the
4942 // comment on EmitSwitch.
4943 MOZ_NEVER_INLINE bool BytecodeEmitter::emitTry(TryNode* tryNode) {
4944 LexicalScopeNode* catchScope = tryNode->catchScope();
4945 ParseNode* finallyNode = tryNode->finallyBlock();
4947 TryEmitter::Kind kind;
4948 if (catchScope) {
4949 if (finallyNode) {
4950 kind = TryEmitter::Kind::TryCatchFinally;
4951 } else {
4952 kind = TryEmitter::Kind::TryCatch;
4954 } else {
4955 MOZ_ASSERT(finallyNode);
4956 kind = TryEmitter::Kind::TryFinally;
4958 TryEmitter tryCatch(this, kind, TryEmitter::ControlKind::Syntactic);
4960 if (!tryCatch.emitTry()) {
4961 return false;
4964 if (!emitTree(tryNode->body())) {
4965 return false;
4968 // If this try has a catch block, emit it.
4969 if (catchScope) {
4970 // The emitted code for a catch block looks like:
4972 // [pushlexicalenv] only if any local aliased
4973 // exception
4974 // setlocal 0; pop assign or possibly destructure exception
4975 // < catch block contents >
4976 // debugleaveblock
4977 // [poplexicalenv] only if any local aliased
4978 // if there is a finally block:
4979 // goto <finally>
4980 // [jump target for returning from finally]
4981 // goto <after finally>
4982 if (!tryCatch.emitCatch()) {
4983 return false;
4986 // Emit the lexical scope and catch body.
4987 if (!emitTree(catchScope)) {
4988 return false;
4992 // Emit the finally handler, if there is one.
4993 if (finallyNode) {
4994 if (!tryCatch.emitFinally(Some(finallyNode->pn_pos.begin))) {
4995 return false;
4998 if (!emitTree(finallyNode)) {
4999 return false;
5003 if (!tryCatch.emitEnd()) {
5004 return false;
5007 return true;
5010 [[nodiscard]] bool BytecodeEmitter::emitJumpToFinally(JumpList* jump,
5011 uint32_t idx) {
5012 // Push the continuation index.
5013 if (!emitNumberOp(idx)) {
5014 return false;
5017 // Push |throwing|.
5018 if (!emit1(JSOp::False)) {
5019 return false;
5022 // Jump to the finally block.
5023 if (!emitJumpNoFallthrough(JSOp::Goto, jump)) {
5024 return false;
5027 return true;
5030 bool BytecodeEmitter::emitIf(TernaryNode* ifNode) {
5031 IfEmitter ifThenElse(this);
5033 if (!ifThenElse.emitIf(Some(ifNode->kid1()->pn_pos.begin))) {
5034 return false;
5037 if_again:
5038 ParseNode* testNode = ifNode->kid1();
5039 auto conditionKind = IfEmitter::ConditionKind::Positive;
5040 if (testNode->isKind(ParseNodeKind::NotExpr)) {
5041 testNode = testNode->as<UnaryNode>().kid();
5042 conditionKind = IfEmitter::ConditionKind::Negative;
5045 if (!markStepBreakpoint()) {
5046 return false;
5049 // Emit code for the condition before pushing stmtInfo.
5050 // NOTE: NotExpr of testNode may be unwrapped, and in that case the negation
5051 // is handled by conditionKind.
5052 if (!emitTree(testNode)) {
5053 return false;
5056 ParseNode* elseNode = ifNode->kid3();
5057 if (elseNode) {
5058 if (!ifThenElse.emitThenElse(conditionKind)) {
5059 return false;
5061 } else {
5062 if (!ifThenElse.emitThen(conditionKind)) {
5063 return false;
5067 /* Emit code for the then part. */
5068 if (!emitTree(ifNode->kid2())) {
5069 return false;
5072 if (elseNode) {
5073 if (elseNode->isKind(ParseNodeKind::IfStmt)) {
5074 ifNode = &elseNode->as<TernaryNode>();
5076 if (!ifThenElse.emitElseIf(Some(ifNode->kid1()->pn_pos.begin))) {
5077 return false;
5080 goto if_again;
5083 if (!ifThenElse.emitElse()) {
5084 return false;
5087 /* Emit code for the else part. */
5088 if (!emitTree(elseNode)) {
5089 return false;
5093 if (!ifThenElse.emitEnd()) {
5094 return false;
5097 return true;
5100 bool BytecodeEmitter::emitHoistedFunctionsInList(ListNode* stmtList) {
5101 MOZ_ASSERT(stmtList->hasTopLevelFunctionDeclarations());
5103 // We can call this multiple times for sloppy eval scopes.
5104 if (stmtList->emittedTopLevelFunctionDeclarations()) {
5105 return true;
5108 stmtList->setEmittedTopLevelFunctionDeclarations();
5110 for (ParseNode* stmt : stmtList->contents()) {
5111 ParseNode* maybeFun = stmt;
5113 if (!sc->strict()) {
5114 while (maybeFun->isKind(ParseNodeKind::LabelStmt)) {
5115 maybeFun = maybeFun->as<LabeledStatement>().statement();
5119 if (maybeFun->is<FunctionNode>() &&
5120 maybeFun->as<FunctionNode>().functionIsHoisted()) {
5121 if (!emitTree(maybeFun)) {
5122 return false;
5127 return true;
5130 bool BytecodeEmitter::emitLexicalScopeBody(
5131 ParseNode* body, EmitLineNumberNote emitLineNote /* = EMIT_LINENOTE */) {
5132 if (body->isKind(ParseNodeKind::StatementList) &&
5133 body->as<ListNode>().hasTopLevelFunctionDeclarations()) {
5134 // This block contains function statements whose definitions are
5135 // hoisted to the top of the block. Emit these as a separate pass
5136 // before the rest of the block.
5137 if (!emitHoistedFunctionsInList(&body->as<ListNode>())) {
5138 return false;
5142 // Line notes were updated by emitLexicalScope or emitScript.
5143 return emitTree(body, ValueUsage::WantValue, emitLineNote);
5146 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
5147 // the comment on emitSwitch.
5148 MOZ_NEVER_INLINE bool BytecodeEmitter::emitLexicalScope(
5149 LexicalScopeNode* lexicalScope) {
5150 LexicalScopeEmitter lse(this);
5152 ParseNode* body = lexicalScope->scopeBody();
5153 if (lexicalScope->isEmptyScope()) {
5154 if (!lse.emitEmptyScope()) {
5155 return false;
5158 if (!emitLexicalScopeBody(body)) {
5159 return false;
5162 if (!lse.emitEnd()) {
5163 return false;
5166 return true;
5169 // We are about to emit some bytecode for what the spec calls "declaration
5170 // instantiation". Assign these instructions to the opening `{` of the
5171 // block. (Using the location of each declaration we're instantiating is
5172 // too weird when stepping in the debugger.)
5173 if (!ParseNodeRequiresSpecialLineNumberNotes(body)) {
5174 if (!updateSourceCoordNotes(lexicalScope->pn_pos.begin)) {
5175 return false;
5179 ScopeKind kind;
5180 if (body->isKind(ParseNodeKind::Catch)) {
5181 BinaryNode* catchNode = &body->as<BinaryNode>();
5182 kind =
5183 (!catchNode->left() || catchNode->left()->isKind(ParseNodeKind::Name))
5184 ? ScopeKind::SimpleCatch
5185 : ScopeKind::Catch;
5186 } else {
5187 kind = lexicalScope->kind();
5190 if (!lse.emitScope(kind, lexicalScope->scopeBindings())) {
5191 return false;
5194 if (body->isKind(ParseNodeKind::ForStmt)) {
5195 // for loops need to emit JSOp::FreshenLexicalEnv/JSOp::RecreateLexicalEnv
5196 // if there are lexical declarations in the head. Signal this by passing a
5197 // non-nullptr lexical scope.
5198 if (!emitFor(&body->as<ForNode>(), &lse.emitterScope())) {
5199 return false;
5201 } else {
5202 if (!emitLexicalScopeBody(body, SUPPRESS_LINENOTE)) {
5203 return false;
5207 if (!lse.emitEnd()) {
5208 return false;
5210 return true;
5213 bool BytecodeEmitter::emitWith(BinaryNode* withNode) {
5214 // Ensure that the column of the 'with' is set properly.
5215 if (!updateSourceCoordNotes(withNode->left()->pn_pos.begin)) {
5216 return false;
5219 if (!markStepBreakpoint()) {
5220 return false;
5223 if (!emitTree(withNode->left())) {
5224 return false;
5227 EmitterScope emitterScope(this);
5228 if (!emitterScope.enterWith(this)) {
5229 return false;
5232 if (!emitTree(withNode->right())) {
5233 return false;
5236 return emitterScope.leave(this);
5239 bool BytecodeEmitter::emitCopyDataProperties(CopyOption option) {
5240 DebugOnly<int32_t> depth = bytecodeSection().stackDepth();
5242 uint32_t argc;
5243 if (option == CopyOption::Filtered) {
5244 MOZ_ASSERT(depth > 2);
5245 // [stack] TARGET SOURCE SET
5246 argc = 3;
5248 if (!emitAtomOp(JSOp::GetIntrinsic,
5249 TaggedParserAtomIndex::WellKnown::CopyDataProperties())) {
5250 // [stack] TARGET SOURCE SET COPYDATAPROPERTIES
5251 return false;
5253 } else {
5254 MOZ_ASSERT(depth > 1);
5255 // [stack] TARGET SOURCE
5256 argc = 2;
5258 if (!emitAtomOp(
5259 JSOp::GetIntrinsic,
5260 TaggedParserAtomIndex::WellKnown::CopyDataPropertiesUnfiltered())) {
5261 // [stack] TARGET SOURCE COPYDATAPROPERTIES
5262 return false;
5266 if (!emit1(JSOp::Undefined)) {
5267 // [stack] TARGET SOURCE SET? COPYDATAPROPERTIES
5268 // UNDEFINED
5269 return false;
5271 if (!emit2(JSOp::Pick, argc + 1)) {
5272 // [stack] SOURCE SET? COPYDATAPROPERTIES UNDEFINED
5273 // TARGET
5274 return false;
5276 if (!emit2(JSOp::Pick, argc + 1)) {
5277 // [stack] SET? COPYDATAPROPERTIES UNDEFINED TARGET
5278 // SOURCE
5279 return false;
5281 if (option == CopyOption::Filtered) {
5282 if (!emit2(JSOp::Pick, argc + 1)) {
5283 // [stack] COPYDATAPROPERTIES UNDEFINED TARGET SOURCE SET
5284 return false;
5287 // Callee is always self-hosted instrinsic, and cannot be content function.
5288 if (!emitCall(JSOp::CallIgnoresRv, argc)) {
5289 // [stack] IGNORED
5290 return false;
5293 if (!emit1(JSOp::Pop)) {
5294 // [stack]
5295 return false;
5298 MOZ_ASSERT(depth - int(argc) == bytecodeSection().stackDepth());
5299 return true;
5302 bool BytecodeEmitter::emitBigIntOp(BigIntLiteral* bigint) {
5303 GCThingIndex index;
5304 if (!perScriptData().gcThingList().append(bigint, &index)) {
5305 return false;
5307 return emitGCIndexOp(JSOp::BigInt, index);
5310 bool BytecodeEmitter::emitIterable(ParseNode* value,
5311 SelfHostedIter selfHostedIter,
5312 IteratorKind iterKind) {
5313 MOZ_ASSERT(getSelfHostedIterFor(value) == selfHostedIter);
5315 if (!emitTree(value)) {
5316 // [stack] ITERABLE
5317 return false;
5320 switch (selfHostedIter) {
5321 case SelfHostedIter::Deny:
5322 case SelfHostedIter::AllowContent:
5323 // [stack] ITERABLE
5324 return true;
5326 case SelfHostedIter::AllowContentWith: {
5327 // This is the following case:
5329 // for (const nextValue of allowContentIterWith(items, usingIterator)) {
5331 // `items` is emitted by `emitTree(value)` above, and the result is on the
5332 // stack as ITERABLE.
5333 // `usingIterator` is the value of `items[Symbol.iterator]`, that's
5334 // already retrieved.
5335 ListNode* argsList = value->as<CallNode>().args();
5336 MOZ_ASSERT_IF(iterKind == IteratorKind::Sync, argsList->count() == 2);
5337 MOZ_ASSERT_IF(iterKind == IteratorKind::Async, argsList->count() == 3);
5339 if (!emitTree(argsList->head()->pn_next)) {
5340 // [stack] ITERABLE ITERFN
5341 return false;
5344 // Async iterator has two possible iterators: An async iterator and a sync
5345 // iterator.
5346 if (iterKind == IteratorKind::Async) {
5347 if (!emitTree(argsList->head()->pn_next->pn_next)) {
5348 // [stack] ITERABLE ASYNC_ITERFN SYNC_ITERFN
5349 return false;
5353 // [stack] ITERABLE ASYNC_ITERFN? SYNC_ITERFN
5354 return true;
5357 case SelfHostedIter::AllowContentWithNext: {
5358 // This is the following case:
5360 // for (const nextValue of allowContentIterWithNext(iterator, next)) {
5362 // `iterator` is emitted by `emitTree(value)` above, and the result is on
5363 // the stack as ITER.
5364 // `next` is the value of `iterator.next`, that's already retrieved.
5365 ListNode* argsList = value->as<CallNode>().args();
5366 MOZ_ASSERT(argsList->count() == 2);
5368 if (!emitTree(argsList->head()->pn_next)) {
5369 // [stack] ITER NEXT
5370 return false;
5373 if (!emit1(JSOp::Swap)) {
5374 // [stack] NEXT ITER
5375 return false;
5378 // [stack] NEXT ITER
5379 return true;
5383 MOZ_CRASH("invalid self-hosted iteration kind");
5386 bool BytecodeEmitter::emitIterator(SelfHostedIter selfHostedIter) {
5387 MOZ_ASSERT(selfHostedIter != SelfHostedIter::Deny ||
5388 emitterMode != BytecodeEmitter::SelfHosting,
5389 "[Symbol.iterator]() call is prohibited in self-hosted code "
5390 "because it can run user-modifiable iteration code");
5392 if (selfHostedIter == SelfHostedIter::AllowContentWithNext) {
5393 // [stack] NEXT ITER
5395 // Nothing to do, stack already contains the iterator and its `next` method.
5396 return true;
5399 if (selfHostedIter != SelfHostedIter::AllowContentWith) {
5400 // [stack] OBJ
5402 // Convert iterable to iterator.
5403 if (!emit1(JSOp::Dup)) {
5404 // [stack] OBJ OBJ
5405 return false;
5407 if (!emit2(JSOp::Symbol, uint8_t(JS::SymbolCode::iterator))) {
5408 // [stack] OBJ OBJ @@ITERATOR
5409 return false;
5411 if (!emitElemOpBase(JSOp::GetElem)) {
5412 // [stack] OBJ ITERFN
5413 return false;
5417 if (!emit1(JSOp::Swap)) {
5418 // [stack] ITERFN OBJ
5419 return false;
5421 if (!emitCall(getIterCallOp(JSOp::CallIter, selfHostedIter), 0)) {
5422 // [stack] ITER
5423 return false;
5425 if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) {
5426 // [stack] ITER
5427 return false;
5429 if (!emit1(JSOp::Dup)) {
5430 // [stack] ITER ITER
5431 return false;
5433 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::next())) {
5434 // [stack] ITER NEXT
5435 return false;
5437 if (!emit1(JSOp::Swap)) {
5438 // [stack] NEXT ITER
5439 return false;
5441 return true;
5444 bool BytecodeEmitter::emitAsyncIterator(SelfHostedIter selfHostedIter) {
5445 MOZ_ASSERT(selfHostedIter != SelfHostedIter::AllowContentWithNext);
5446 MOZ_ASSERT(selfHostedIter != SelfHostedIter::Deny ||
5447 emitterMode != BytecodeEmitter::SelfHosting,
5448 "[Symbol.asyncIterator]() call is prohibited in self-hosted code "
5449 "because it can run user-modifiable iteration code");
5451 if (selfHostedIter != SelfHostedIter::AllowContentWith) {
5452 // [stack] OBJ
5454 // Convert iterable to iterator.
5455 if (!emit1(JSOp::Dup)) {
5456 // [stack] OBJ OBJ
5457 return false;
5459 if (!emit2(JSOp::Symbol, uint8_t(JS::SymbolCode::asyncIterator))) {
5460 // [stack] OBJ OBJ @@ASYNCITERATOR
5461 return false;
5463 if (!emitElemOpBase(JSOp::GetElem)) {
5464 // [stack] OBJ ASYNC_ITERFN
5465 return false;
5467 } else {
5468 // [stack] OBJ ASYNC_ITERFN SYNC_ITERFN
5470 if (!emitElemOpBase(JSOp::Swap)) {
5471 // [stack] OBJ SYNC_ITERFN ASYNC_ITERFN
5472 return false;
5476 InternalIfEmitter ifAsyncIterIsUndefined(this);
5477 if (!emit1(JSOp::IsNullOrUndefined)) {
5478 // [stack] OBJ SYNC_ITERFN? ASYNC_ITERFN NULL-OR-UNDEF
5479 return false;
5481 if (!ifAsyncIterIsUndefined.emitThenElse()) {
5482 // [stack] OBJ SYNC_ITERFN? ASYNC_ITERFN
5483 return false;
5486 if (!emit1(JSOp::Pop)) {
5487 // [stack] OBJ SYNC_ITERFN?
5488 return false;
5491 if (selfHostedIter != SelfHostedIter::AllowContentWith) {
5492 if (!emit1(JSOp::Dup)) {
5493 // [stack] OBJ OBJ
5494 return false;
5496 if (!emit2(JSOp::Symbol, uint8_t(JS::SymbolCode::iterator))) {
5497 // [stack] OBJ OBJ @@ITERATOR
5498 return false;
5500 if (!emitElemOpBase(JSOp::GetElem)) {
5501 // [stack] OBJ SYNC_ITERFN
5502 return false;
5504 } else {
5505 // [stack] OBJ SYNC_ITERFN
5508 if (!emit1(JSOp::Swap)) {
5509 // [stack] SYNC_ITERFN OBJ
5510 return false;
5512 if (!emitCall(getIterCallOp(JSOp::CallIter, selfHostedIter), 0)) {
5513 // [stack] ITER
5514 return false;
5516 if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) {
5517 // [stack] ITER
5518 return false;
5521 if (!emit1(JSOp::Dup)) {
5522 // [stack] ITER ITER
5523 return false;
5525 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::next())) {
5526 // [stack] ITER SYNCNEXT
5527 return false;
5530 if (!emit1(JSOp::ToAsyncIter)) {
5531 // [stack] ITER
5532 return false;
5535 if (!ifAsyncIterIsUndefined.emitElse()) {
5536 // [stack] OBJ SYNC_ITERFN? ASYNC_ITERFN
5537 return false;
5540 if (selfHostedIter == SelfHostedIter::AllowContentWith) {
5541 if (!emit1(JSOp::Swap)) {
5542 // [stack] OBJ ASYNC_ITERFN SYNC_ITERFN
5543 return false;
5545 if (!emit1(JSOp::Pop)) {
5546 // [stack] OBJ ASYNC_ITERFN
5547 return false;
5551 if (!emit1(JSOp::Swap)) {
5552 // [stack] ASYNC_ITERFN OBJ
5553 return false;
5555 if (!emitCall(getIterCallOp(JSOp::CallIter, selfHostedIter), 0)) {
5556 // [stack] ITER
5557 return false;
5559 if (!emitCheckIsObj(CheckIsObjectKind::GetAsyncIterator)) {
5560 // [stack] ITER
5561 return false;
5564 if (!ifAsyncIterIsUndefined.emitEnd()) {
5565 // [stack] ITER
5566 return false;
5569 if (!emit1(JSOp::Dup)) {
5570 // [stack] ITER ITER
5571 return false;
5573 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::next())) {
5574 // [stack] ITER NEXT
5575 return false;
5577 if (!emit1(JSOp::Swap)) {
5578 // [stack] NEXT ITER
5579 return false;
5582 return true;
5585 bool BytecodeEmitter::emitSpread(SelfHostedIter selfHostedIter) {
5586 // [stack] NEXT ITER ARR I
5587 return emitSpread(selfHostedIter, 2, JSOp::InitElemInc);
5588 // [stack] ARR FINAL_INDEX
5591 bool BytecodeEmitter::emitSpread(SelfHostedIter selfHostedIter,
5592 int spreadeeStackItems, JSOp storeElementOp) {
5593 LoopControl loopInfo(this, StatementKind::Spread);
5594 // In the [stack] annotations, (spreadee) can be "ARR I" (when spreading
5595 // into an array or into call parameters, or "TUPLE" (when spreading into a
5596 // tuple)
5598 if (!loopInfo.emitLoopHead(this, Nothing())) {
5599 // [stack] NEXT ITER (spreadee)
5600 return false;
5604 #ifdef DEBUG
5605 auto loopDepth = bytecodeSection().stackDepth();
5606 #endif
5608 // Spread operations can't contain |continue|, so don't bother setting loop
5609 // and enclosing "update" offsets, as we do with for-loops.
5611 if (!emitDupAt(spreadeeStackItems + 1, 2)) {
5612 // [stack] NEXT ITER (spreadee) NEXT ITER
5613 return false;
5615 if (!emitIteratorNext(Nothing(), IteratorKind::Sync, selfHostedIter)) {
5616 // [stack] NEXT ITER (spreadee) RESULT
5617 return false;
5619 if (!emit1(JSOp::Dup)) {
5620 // [stack] NEXT ITER (spreadee) RESULT RESULT
5621 return false;
5623 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::done())) {
5624 // [stack] NEXT ITER (spreadee) RESULT DONE
5625 return false;
5627 if (!emitJump(JSOp::JumpIfTrue, &loopInfo.breaks)) {
5628 // [stack] NEXT ITER (spreadee) RESULT
5629 return false;
5632 // Emit code to assign result.value to the iteration variable.
5633 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::value())) {
5634 // [stack] NEXT ITER (spreadee) VALUE
5635 return false;
5637 if (!emit1(storeElementOp)) {
5638 // [stack] NEXT ITER (spreadee)
5639 return false;
5642 if (!loopInfo.emitLoopEnd(this, JSOp::Goto, TryNoteKind::ForOf)) {
5643 // [stack] NEXT ITER (spreadee)
5644 return false;
5647 MOZ_ASSERT(bytecodeSection().stackDepth() == loopDepth);
5650 // When we leave the loop body and jump to this point, the result value is
5651 // still on the stack. Account for that by updating the stack depth
5652 // manually.
5653 bytecodeSection().setStackDepth(bytecodeSection().stackDepth() + 1);
5655 // No continues should occur in spreads.
5656 MOZ_ASSERT(!loopInfo.continues.offset.valid());
5658 if (!emit2(JSOp::Pick, spreadeeStackItems + 2)) {
5659 // [stack] ITER (spreadee) RESULT NEXT
5660 return false;
5662 if (!emit2(JSOp::Pick, spreadeeStackItems + 2)) {
5663 // [stack] (spreadee) RESULT NEXT ITER
5664 return false;
5667 return emitPopN(3);
5668 // [stack] (spreadee)
5671 bool BytecodeEmitter::emitInitializeForInOrOfTarget(TernaryNode* forHead) {
5672 MOZ_ASSERT(forHead->isKind(ParseNodeKind::ForIn) ||
5673 forHead->isKind(ParseNodeKind::ForOf));
5675 MOZ_ASSERT(bytecodeSection().stackDepth() >= 1,
5676 "must have a per-iteration value for initializing");
5678 ParseNode* target = forHead->kid1();
5679 MOZ_ASSERT(!forHead->kid2());
5681 // If the for-in/of loop didn't have a variable declaration, per-loop
5682 // initialization is just assigning the iteration value to a target
5683 // expression.
5684 if (!target->is<DeclarationListNode>()) {
5685 return emitAssignmentOrInit(ParseNodeKind::AssignExpr, target, nullptr);
5686 // [stack] ... ITERVAL
5689 // Otherwise, per-loop initialization is (possibly) declaration
5690 // initialization. If the declaration is a lexical declaration, it must be
5691 // initialized. If the declaration is a variable declaration, an
5692 // assignment to that name (which does *not* necessarily assign to the
5693 // variable!) must be generated.
5695 auto* declarationList = &target->as<DeclarationListNode>();
5696 if (!updateSourceCoordNotes(declarationList->pn_pos.begin)) {
5697 return false;
5700 target = declarationList->singleBinding();
5702 NameNode* nameNode = nullptr;
5703 if (target->isKind(ParseNodeKind::Name)) {
5704 nameNode = &target->as<NameNode>();
5705 } else if (target->isKind(ParseNodeKind::AssignExpr)) {
5706 BinaryNode* assignNode = &target->as<BinaryNode>();
5707 if (assignNode->left()->is<NameNode>()) {
5708 nameNode = &assignNode->left()->as<NameNode>();
5712 if (nameNode) {
5713 auto nameAtom = nameNode->name();
5714 NameOpEmitter noe(this, nameAtom, NameOpEmitter::Kind::Initialize);
5715 if (!noe.prepareForRhs()) {
5716 return false;
5718 if (noe.emittedBindOp()) {
5719 // Per-iteration initialization in for-in/of loops computes the
5720 // iteration value *before* initializing. Thus the initializing
5721 // value may be buried under a bind-specific value on the stack.
5722 // Swap it to the top of the stack.
5723 MOZ_ASSERT(bytecodeSection().stackDepth() >= 2);
5724 if (!emit1(JSOp::Swap)) {
5725 return false;
5727 } else {
5728 // In cases of emitting a frame slot or environment slot,
5729 // nothing needs be done.
5730 MOZ_ASSERT(bytecodeSection().stackDepth() >= 1);
5732 if (!noe.emitAssignment()) {
5733 return false;
5736 // The caller handles removing the iteration value from the stack.
5737 return true;
5740 MOZ_ASSERT(
5741 !target->isKind(ParseNodeKind::AssignExpr),
5742 "for-in/of loop destructuring declarations can't have initializers");
5744 MOZ_ASSERT(target->isKind(ParseNodeKind::ArrayExpr) ||
5745 target->isKind(ParseNodeKind::ObjectExpr));
5746 return emitDestructuringOps(&target->as<ListNode>(),
5747 DestructuringFlavor::Declaration);
5750 bool BytecodeEmitter::emitForOf(ForNode* forOfLoop,
5751 const EmitterScope* headLexicalEmitterScope) {
5752 MOZ_ASSERT(forOfLoop->isKind(ParseNodeKind::ForStmt));
5754 TernaryNode* forOfHead = forOfLoop->head();
5755 MOZ_ASSERT(forOfHead->isKind(ParseNodeKind::ForOf));
5757 unsigned iflags = forOfLoop->iflags();
5758 IteratorKind iterKind =
5759 (iflags & JSITER_FORAWAITOF) ? IteratorKind::Async : IteratorKind::Sync;
5760 MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->isSuspendableContext());
5761 MOZ_ASSERT_IF(iterKind == IteratorKind::Async,
5762 sc->asSuspendableContext()->isAsync());
5764 ParseNode* forHeadExpr = forOfHead->kid3();
5766 // Certain builtins (e.g. Array.from) are implemented in self-hosting
5767 // as for-of loops.
5768 auto selfHostedIter = getSelfHostedIterFor(forHeadExpr);
5769 ForOfEmitter forOf(this, headLexicalEmitterScope, selfHostedIter, iterKind);
5771 if (!forOf.emitIterated()) {
5772 // [stack]
5773 return false;
5776 if (!updateSourceCoordNotes(forHeadExpr->pn_pos.begin)) {
5777 return false;
5779 if (!markStepBreakpoint()) {
5780 return false;
5782 if (!emitIterable(forHeadExpr, selfHostedIter, iterKind)) {
5783 // [stack] ITERABLE
5784 return false;
5787 if (headLexicalEmitterScope) {
5788 DebugOnly<ParseNode*> forOfTarget = forOfHead->kid1();
5789 MOZ_ASSERT(forOfTarget->isKind(ParseNodeKind::LetDecl) ||
5790 forOfTarget->isKind(ParseNodeKind::ConstDecl));
5793 if (!forOf.emitInitialize(forOfHead->pn_pos.begin)) {
5794 // [stack] NEXT ITER VALUE
5795 return false;
5798 if (!emitInitializeForInOrOfTarget(forOfHead)) {
5799 // [stack] NEXT ITER VALUE
5800 return false;
5803 if (!forOf.emitBody()) {
5804 // [stack] NEXT ITER UNDEF
5805 return false;
5808 // Perform the loop body.
5809 ParseNode* forBody = forOfLoop->body();
5810 if (!emitTree(forBody)) {
5811 // [stack] NEXT ITER UNDEF
5812 return false;
5815 if (!forOf.emitEnd(forHeadExpr->pn_pos.begin)) {
5816 // [stack]
5817 return false;
5820 return true;
5823 bool BytecodeEmitter::emitForIn(ForNode* forInLoop,
5824 const EmitterScope* headLexicalEmitterScope) {
5825 TernaryNode* forInHead = forInLoop->head();
5826 MOZ_ASSERT(forInHead->isKind(ParseNodeKind::ForIn));
5828 ForInEmitter forIn(this, headLexicalEmitterScope);
5830 // Annex B: Evaluate the var-initializer expression if present.
5831 // |for (var i = initializer in expr) { ... }|
5832 ParseNode* forInTarget = forInHead->kid1();
5833 if (forInTarget->is<DeclarationListNode>()) {
5834 auto* declarationList = &forInTarget->as<DeclarationListNode>();
5836 ParseNode* decl = declarationList->singleBinding();
5837 if (decl->isKind(ParseNodeKind::AssignExpr)) {
5838 BinaryNode* assignNode = &decl->as<BinaryNode>();
5839 if (assignNode->left()->is<NameNode>()) {
5840 NameNode* nameNode = &assignNode->left()->as<NameNode>();
5841 ParseNode* initializer = assignNode->right();
5842 MOZ_ASSERT(
5843 forInTarget->isKind(ParseNodeKind::VarStmt),
5844 "for-in initializers are only permitted for |var| declarations");
5846 if (!updateSourceCoordNotes(decl->pn_pos.begin)) {
5847 return false;
5850 auto nameAtom = nameNode->name();
5851 NameOpEmitter noe(this, nameAtom, NameOpEmitter::Kind::Initialize);
5852 if (!noe.prepareForRhs()) {
5853 return false;
5855 if (!emitInitializer(initializer, nameNode)) {
5856 return false;
5858 if (!noe.emitAssignment()) {
5859 return false;
5862 // Pop the initializer.
5863 if (!emit1(JSOp::Pop)) {
5864 return false;
5870 if (!forIn.emitIterated()) {
5871 // [stack]
5872 return false;
5875 // Evaluate the expression being iterated.
5876 ParseNode* expr = forInHead->kid3();
5878 if (!updateSourceCoordNotes(expr->pn_pos.begin)) {
5879 return false;
5881 if (!markStepBreakpoint()) {
5882 return false;
5884 if (!emitTree(expr)) {
5885 // [stack] EXPR
5886 return false;
5889 MOZ_ASSERT(forInLoop->iflags() == 0);
5891 MOZ_ASSERT_IF(headLexicalEmitterScope,
5892 forInTarget->isKind(ParseNodeKind::LetDecl) ||
5893 forInTarget->isKind(ParseNodeKind::ConstDecl));
5895 if (!forIn.emitInitialize()) {
5896 // [stack] ITER ITERVAL
5897 return false;
5900 if (!emitInitializeForInOrOfTarget(forInHead)) {
5901 // [stack] ITER ITERVAL
5902 return false;
5905 if (!forIn.emitBody()) {
5906 // [stack] ITER ITERVAL
5907 return false;
5910 // Perform the loop body.
5911 ParseNode* forBody = forInLoop->body();
5912 if (!emitTree(forBody)) {
5913 // [stack] ITER ITERVAL
5914 return false;
5917 if (!forIn.emitEnd(forInHead->pn_pos.begin)) {
5918 // [stack]
5919 return false;
5922 return true;
5925 /* C-style `for (init; cond; update) ...` loop. */
5926 bool BytecodeEmitter::emitCStyleFor(
5927 ForNode* forNode, const EmitterScope* headLexicalEmitterScope) {
5928 TernaryNode* forHead = forNode->head();
5929 ParseNode* forBody = forNode->body();
5930 ParseNode* init = forHead->kid1();
5931 ParseNode* cond = forHead->kid2();
5932 ParseNode* update = forHead->kid3();
5933 bool isLet = init && init->isKind(ParseNodeKind::LetDecl);
5935 CForEmitter cfor(this, isLet ? headLexicalEmitterScope : nullptr);
5937 if (!cfor.emitInit(init ? Some(init->pn_pos.begin) : Nothing())) {
5938 // [stack]
5939 return false;
5942 // If the head of this for-loop declared any lexical variables, the parser
5943 // wrapped this ParseNodeKind::For node in a ParseNodeKind::LexicalScope
5944 // representing the implicit scope of those variables. By the time we get
5945 // here, we have already entered that scope. So far, so good.
5946 if (init) {
5947 // Emit the `init` clause, whether it's an expression or a variable
5948 // declaration. (The loop variables were hoisted into an enclosing
5949 // scope, but we still need to emit code for the initializers.)
5950 if (init->is<DeclarationListNode>()) {
5951 MOZ_ASSERT(!init->as<DeclarationListNode>().empty());
5953 if (!emitTree(init)) {
5954 // [stack]
5955 return false;
5957 } else {
5958 if (!updateSourceCoordNotes(init->pn_pos.begin)) {
5959 return false;
5961 if (!markStepBreakpoint()) {
5962 return false;
5965 // 'init' is an expression, not a declaration. emitTree left its
5966 // value on the stack.
5967 if (!emitTree(init, ValueUsage::IgnoreValue)) {
5968 // [stack] VAL
5969 return false;
5971 if (!emit1(JSOp::Pop)) {
5972 // [stack]
5973 return false;
5978 if (!cfor.emitCond(cond ? Some(cond->pn_pos.begin) : Nothing())) {
5979 // [stack]
5980 return false;
5983 if (cond) {
5984 if (!updateSourceCoordNotes(cond->pn_pos.begin)) {
5985 return false;
5987 if (!markStepBreakpoint()) {
5988 return false;
5990 if (!emitTree(cond)) {
5991 // [stack] VAL
5992 return false;
5996 if (!cfor.emitBody(cond ? CForEmitter::Cond::Present
5997 : CForEmitter::Cond::Missing)) {
5998 // [stack]
5999 return false;
6002 if (!emitTree(forBody)) {
6003 // [stack]
6004 return false;
6007 if (!cfor.emitUpdate(
6008 update ? CForEmitter::Update::Present : CForEmitter::Update::Missing,
6009 update ? Some(update->pn_pos.begin) : Nothing())) {
6010 // [stack]
6011 return false;
6014 // Check for update code to do before the condition (if any).
6015 if (update) {
6016 if (!updateSourceCoordNotes(update->pn_pos.begin)) {
6017 return false;
6019 if (!markStepBreakpoint()) {
6020 return false;
6022 if (!emitTree(update, ValueUsage::IgnoreValue)) {
6023 // [stack] VAL
6024 return false;
6028 if (!cfor.emitEnd(forNode->pn_pos.begin)) {
6029 // [stack]
6030 return false;
6033 return true;
6036 bool BytecodeEmitter::emitFor(ForNode* forNode,
6037 const EmitterScope* headLexicalEmitterScope) {
6038 if (forNode->head()->isKind(ParseNodeKind::ForHead)) {
6039 return emitCStyleFor(forNode, headLexicalEmitterScope);
6042 if (!updateLineNumberNotes(forNode->pn_pos.begin)) {
6043 return false;
6046 if (forNode->head()->isKind(ParseNodeKind::ForIn)) {
6047 return emitForIn(forNode, headLexicalEmitterScope);
6050 MOZ_ASSERT(forNode->head()->isKind(ParseNodeKind::ForOf));
6051 return emitForOf(forNode, headLexicalEmitterScope);
6054 MOZ_NEVER_INLINE bool BytecodeEmitter::emitFunction(
6055 FunctionNode* funNode, bool needsProto /* = false */) {
6056 FunctionBox* funbox = funNode->funbox();
6058 // [stack]
6060 FunctionEmitter fe(this, funbox, funNode->syntaxKind(),
6061 funNode->functionIsHoisted()
6062 ? FunctionEmitter::IsHoisted::Yes
6063 : FunctionEmitter::IsHoisted::No);
6065 // |wasEmittedByEnclosingScript| flag is set to true once the function has
6066 // been emitted. Function definitions that need hoisting to the top of the
6067 // function will be seen by emitFunction in two places.
6068 if (funbox->wasEmittedByEnclosingScript()) {
6069 if (!fe.emitAgain()) {
6070 // [stack]
6071 return false;
6073 MOZ_ASSERT(funNode->functionIsHoisted());
6074 } else if (funbox->isInterpreted()) {
6075 if (!funbox->emitBytecode) {
6076 return fe.emitLazy();
6077 // [stack] FUN?
6080 if (!fe.prepareForNonLazy()) {
6081 // [stack]
6082 return false;
6085 BytecodeEmitter bce2(this, funbox);
6086 if (!bce2.init(funNode->pn_pos)) {
6087 return false;
6090 /* We measured the max scope depth when we parsed the function. */
6091 if (!bce2.emitFunctionScript(funNode)) {
6092 return false;
6095 if (!fe.emitNonLazyEnd()) {
6096 // [stack] FUN?
6097 return false;
6099 } else {
6100 if (!fe.emitAsmJSModule()) {
6101 // [stack]
6102 return false;
6106 // Track the last emitted top-level self-hosted function, so that intrinsics
6107 // can adjust attributes at parse time.
6109 // NOTE: We also disallow lambda functions in the top-level body. This is done
6110 // to simplify handling of the self-hosted stencil. Within normal function
6111 // declarations there are no such restrictions.
6112 if (emitterMode == EmitterMode::SelfHosting) {
6113 if (sc->isTopLevelContext()) {
6114 MOZ_ASSERT(!funbox->isLambda());
6115 MOZ_ASSERT(funbox->explicitName());
6116 prevSelfHostedTopLevelFunction = funbox;
6120 return true;
6123 bool BytecodeEmitter::emitDo(BinaryNode* doNode) {
6124 ParseNode* bodyNode = doNode->left();
6126 DoWhileEmitter doWhile(this);
6127 if (!doWhile.emitBody(doNode->pn_pos.begin, getOffsetForLoop(bodyNode))) {
6128 return false;
6131 if (!emitTree(bodyNode)) {
6132 return false;
6135 if (!doWhile.emitCond()) {
6136 return false;
6139 ParseNode* condNode = doNode->right();
6140 if (!updateSourceCoordNotes(condNode->pn_pos.begin)) {
6141 return false;
6143 if (!markStepBreakpoint()) {
6144 return false;
6146 if (!emitTree(condNode)) {
6147 return false;
6150 if (!doWhile.emitEnd()) {
6151 return false;
6154 return true;
6157 bool BytecodeEmitter::emitWhile(BinaryNode* whileNode) {
6158 ParseNode* bodyNode = whileNode->right();
6160 WhileEmitter wh(this);
6162 ParseNode* condNode = whileNode->left();
6163 if (!wh.emitCond(whileNode->pn_pos.begin, getOffsetForLoop(condNode),
6164 whileNode->pn_pos.end)) {
6165 return false;
6168 if (!updateSourceCoordNotes(condNode->pn_pos.begin)) {
6169 return false;
6171 if (!markStepBreakpoint()) {
6172 return false;
6174 if (!emitTree(condNode)) {
6175 return false;
6178 if (!wh.emitBody()) {
6179 return false;
6181 if (!emitTree(bodyNode)) {
6182 return false;
6185 if (!wh.emitEnd()) {
6186 return false;
6189 return true;
6192 bool BytecodeEmitter::emitBreak(TaggedParserAtomIndex label) {
6193 BreakableControl* target;
6194 if (label) {
6195 // Any statement with the matching label may be the break target.
6196 auto hasSameLabel = [label](LabelControl* labelControl) {
6197 return labelControl->label() == label;
6199 target = findInnermostNestableControl<LabelControl>(hasSameLabel);
6200 } else {
6201 auto isNotLabel = [](BreakableControl* control) {
6202 return !control->is<LabelControl>();
6204 target = findInnermostNestableControl<BreakableControl>(isNotLabel);
6207 return emitGoto(target, GotoKind::Break);
6210 bool BytecodeEmitter::emitContinue(TaggedParserAtomIndex label) {
6211 LoopControl* target = nullptr;
6212 if (label) {
6213 // Find the loop statement enclosed by the matching label.
6214 NestableControl* control = innermostNestableControl;
6215 while (!control->is<LabelControl>() ||
6216 control->as<LabelControl>().label() != label) {
6217 if (control->is<LoopControl>()) {
6218 target = &control->as<LoopControl>();
6220 control = control->enclosing();
6222 } else {
6223 target = findInnermostNestableControl<LoopControl>();
6225 return emitGoto(target, GotoKind::Continue);
6228 bool BytecodeEmitter::emitGetFunctionThis(NameNode* thisName) {
6229 MOZ_ASSERT(sc->hasFunctionThisBinding());
6230 MOZ_ASSERT(thisName->isName(TaggedParserAtomIndex::WellKnown::dot_this_()));
6232 if (!updateLineNumberNotes(thisName->pn_pos.begin)) {
6233 return false;
6236 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
6237 // [stack] THIS
6238 return false;
6240 if (sc->needsThisTDZChecks()) {
6241 if (!emit1(JSOp::CheckThis)) {
6242 // [stack] THIS
6243 return false;
6247 return true;
6250 bool BytecodeEmitter::emitGetThisForSuperBase(UnaryNode* superBase) {
6251 MOZ_ASSERT(superBase->isKind(ParseNodeKind::SuperBase));
6252 NameNode* nameNode = &superBase->kid()->as<NameNode>();
6253 return emitGetFunctionThis(nameNode);
6254 // [stack] THIS
6257 bool BytecodeEmitter::emitThisLiteral(ThisLiteral* pn) {
6258 if (ParseNode* kid = pn->kid()) {
6259 NameNode* thisName = &kid->as<NameNode>();
6260 return emitGetFunctionThis(thisName);
6261 // [stack] THIS
6264 if (sc->thisBinding() == ThisBinding::Module) {
6265 return emit1(JSOp::Undefined);
6266 // [stack] UNDEF
6269 MOZ_ASSERT(sc->thisBinding() == ThisBinding::Global);
6271 MOZ_ASSERT(outermostScope().hasNonSyntacticScopeOnChain() ==
6272 sc->hasNonSyntacticScope());
6273 if (sc->hasNonSyntacticScope()) {
6274 return emit1(JSOp::NonSyntacticGlobalThis);
6275 // [stack] THIS
6278 return emit1(JSOp::GlobalThis);
6279 // [stack] THIS
6282 bool BytecodeEmitter::emitCheckDerivedClassConstructorReturn() {
6283 MOZ_ASSERT(
6284 lookupName(TaggedParserAtomIndex::WellKnown::dot_this_()).hasKnownSlot());
6285 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
6286 return false;
6288 if (!emit1(JSOp::CheckReturn)) {
6289 return false;
6291 if (!emit1(JSOp::SetRval)) {
6292 return false;
6294 return true;
6297 bool BytecodeEmitter::emitNewTarget() {
6298 MOZ_ASSERT(sc->allowNewTarget());
6300 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_newTarget_())) {
6301 // [stack] NEW.TARGET
6302 return false;
6304 return true;
6307 bool BytecodeEmitter::emitNewTarget(NewTargetNode* pn) {
6308 MOZ_ASSERT(pn->newTargetName()->isName(
6309 TaggedParserAtomIndex::WellKnown::dot_newTarget_()));
6311 return emitNewTarget();
6314 bool BytecodeEmitter::emitNewTarget(CallNode* pn) {
6315 MOZ_ASSERT(pn->callOp() == JSOp::SuperCall ||
6316 pn->callOp() == JSOp::SpreadSuperCall);
6318 // The parser is responsible for marking the "new.target" binding as being
6319 // implicitly used in super() calls.
6320 return emitNewTarget();
6323 bool BytecodeEmitter::emitReturn(UnaryNode* returnNode) {
6324 if (!updateSourceCoordNotes(returnNode->pn_pos.begin)) {
6325 return false;
6328 if (!markStepBreakpoint()) {
6329 return false;
6332 /* Push a return value */
6333 if (ParseNode* expr = returnNode->kid()) {
6334 if (!emitTree(expr)) {
6335 return false;
6338 if (sc->asSuspendableContext()->isAsync() &&
6339 sc->asSuspendableContext()->isGenerator()) {
6340 if (!emitAwaitInInnermostScope()) {
6341 return false;
6344 } else {
6345 /* No explicit return value provided */
6346 if (!emit1(JSOp::Undefined)) {
6347 return false;
6351 // We know functionBodyEndPos is set because "return" is only
6352 // valid in a function, and so we've passed through
6353 // emitFunctionScript.
6354 if (!updateSourceCoordNotes(*functionBodyEndPos)) {
6355 return false;
6359 * The return value is currently on the stack. We would like to
6360 * generate JSOp::Return, but if we have work to do before returning,
6361 * we will instead generate JSOp::SetRval / JSOp::RetRval.
6363 * We don't know whether we will need fixup code until after calling
6364 * prepareForNonLocalJumpToOutermost, so we start by generating
6365 * JSOp::SetRval, then mutate it to JSOp::Return in finishReturn if it
6366 * wasn't needed.
6368 BytecodeOffset setRvalOffset = bytecodeSection().offset();
6369 if (!emit1(JSOp::SetRval)) {
6370 return false;
6373 NonLocalExitControl nle(this, NonLocalExitKind::Return);
6374 return nle.emitReturn(setRvalOffset);
6377 bool BytecodeEmitter::finishReturn(BytecodeOffset setRvalOffset) {
6378 // The return value is currently in rval. Depending on the current function,
6379 // we may have to do additional work before returning:
6380 // - Derived class constructors must check if the return value is an object.
6381 // - Generators and async functions must do a final yield.
6382 // - Non-async generators must return the value as an iterator result:
6383 // { value: <rval>, done: true }
6384 // - Non-generator async functions must resolve the function's result promise
6385 // with the value.
6387 // If we have not generated any code since the SetRval that stored the return
6388 // value, we can also optimize the bytecode by rewriting that SetRval as a
6389 // JSOp::Return. See |emitReturn| above.
6391 bool isDerivedClassConstructor =
6392 sc->isFunctionBox() && sc->asFunctionBox()->isDerivedClassConstructor();
6393 bool needsFinalYield =
6394 sc->isFunctionBox() && sc->asFunctionBox()->needsFinalYield();
6395 bool isSimpleReturn =
6396 setRvalOffset.valid() &&
6397 setRvalOffset + BytecodeOffsetDiff(JSOpLength_SetRval) ==
6398 bytecodeSection().offset();
6400 if (isDerivedClassConstructor) {
6401 MOZ_ASSERT(!needsFinalYield);
6402 if (!emitJump(JSOp::Goto, &endOfDerivedClassConstructorBody)) {
6403 return false;
6405 return true;
6408 if (needsFinalYield) {
6409 if (!emitJump(JSOp::Goto, &finalYields)) {
6410 return false;
6412 return true;
6415 if (isSimpleReturn) {
6416 MOZ_ASSERT(JSOp(bytecodeSection().code()[setRvalOffset.value()]) ==
6417 JSOp::SetRval);
6418 bytecodeSection().code()[setRvalOffset.value()] = jsbytecode(JSOp::Return);
6419 return true;
6422 // Nothing special needs to be done.
6423 return emitReturnRval();
6426 bool BytecodeEmitter::emitGetDotGeneratorInScope(EmitterScope& currentScope) {
6427 if (!sc->isFunction() && sc->isModuleContext() &&
6428 sc->asModuleContext()->isAsync()) {
6429 NameLocation loc = *locationOfNameBoundInScopeType<ModuleScope>(
6430 TaggedParserAtomIndex::WellKnown::dot_generator_(), &currentScope);
6431 return emitGetNameAtLocation(
6432 TaggedParserAtomIndex::WellKnown::dot_generator_(), loc);
6434 NameLocation loc = *locationOfNameBoundInScopeType<FunctionScope>(
6435 TaggedParserAtomIndex::WellKnown::dot_generator_(), &currentScope);
6436 return emitGetNameAtLocation(
6437 TaggedParserAtomIndex::WellKnown::dot_generator_(), loc);
6440 bool BytecodeEmitter::emitInitialYield(UnaryNode* yieldNode) {
6441 if (!emitTree(yieldNode->kid())) {
6442 return false;
6445 if (!emitYieldOp(JSOp::InitialYield)) {
6446 // [stack] RVAL GENERATOR RESUMEKIND
6447 return false;
6449 if (!emit1(JSOp::CheckResumeKind)) {
6450 // [stack] RVAL
6451 return false;
6453 if (!emit1(JSOp::Pop)) {
6454 // [stack]
6455 return false;
6458 return true;
6461 bool BytecodeEmitter::emitYield(UnaryNode* yieldNode) {
6462 MOZ_ASSERT(sc->isFunctionBox());
6463 MOZ_ASSERT(sc->asFunctionBox()->isGenerator());
6464 MOZ_ASSERT(yieldNode->isKind(ParseNodeKind::YieldExpr));
6466 bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
6467 if (needsIteratorResult) {
6468 if (!emitPrepareIteratorResult()) {
6469 // [stack] ITEROBJ
6470 return false;
6473 if (ParseNode* expr = yieldNode->kid()) {
6474 if (!emitTree(expr)) {
6475 // [stack] ITEROBJ? VAL
6476 return false;
6478 } else {
6479 if (!emit1(JSOp::Undefined)) {
6480 // [stack] ITEROBJ? UNDEFINED
6481 return false;
6485 if (sc->asSuspendableContext()->isAsync()) {
6486 MOZ_ASSERT(!needsIteratorResult);
6487 if (!emitAwaitInInnermostScope()) {
6488 // [stack] RESULT
6489 return false;
6493 if (needsIteratorResult) {
6494 if (!emitFinishIteratorResult(false)) {
6495 // [stack] ITEROBJ
6496 return false;
6500 if (!emitGetDotGeneratorInInnermostScope()) {
6501 // [stack] # if needsIteratorResult
6502 // [stack] ITEROBJ .GENERATOR
6503 // [stack] # else
6504 // [stack] RESULT .GENERATOR
6505 return false;
6508 if (!emitYieldOp(JSOp::Yield)) {
6509 // [stack] YIELDRESULT GENERATOR RESUMEKIND
6510 return false;
6513 if (!emit1(JSOp::CheckResumeKind)) {
6514 // [stack] YIELDRESULT
6515 return false;
6518 return true;
6521 bool BytecodeEmitter::emitAwaitInInnermostScope(UnaryNode* awaitNode) {
6522 MOZ_ASSERT(sc->isSuspendableContext());
6523 MOZ_ASSERT(awaitNode->isKind(ParseNodeKind::AwaitExpr));
6525 if (!emitTree(awaitNode->kid())) {
6526 return false;
6528 return emitAwaitInInnermostScope();
6531 bool BytecodeEmitter::emitAwaitInScope(EmitterScope& currentScope) {
6532 if (!emit1(JSOp::CanSkipAwait)) {
6533 // [stack] VALUE CANSKIP
6534 return false;
6537 if (!emit1(JSOp::MaybeExtractAwaitValue)) {
6538 // [stack] VALUE_OR_RESOLVED CANSKIP
6539 return false;
6542 InternalIfEmitter ifCanSkip(this);
6543 if (!ifCanSkip.emitThen(IfEmitter::ConditionKind::Negative)) {
6544 // [stack] VALUE_OR_RESOLVED
6545 return false;
6548 if (sc->asSuspendableContext()->needsPromiseResult()) {
6549 if (!emitGetDotGeneratorInScope(currentScope)) {
6550 // [stack] VALUE GENERATOR
6551 return false;
6553 if (!emit1(JSOp::AsyncAwait)) {
6554 // [stack] PROMISE
6555 return false;
6559 if (!emitGetDotGeneratorInScope(currentScope)) {
6560 // [stack] VALUE|PROMISE GENERATOR
6561 return false;
6563 if (!emitYieldOp(JSOp::Await)) {
6564 // [stack] RESOLVED GENERATOR RESUMEKIND
6565 return false;
6567 if (!emit1(JSOp::CheckResumeKind)) {
6568 // [stack] RESOLVED
6569 return false;
6572 if (!ifCanSkip.emitEnd()) {
6573 return false;
6576 MOZ_ASSERT(ifCanSkip.popped() == 0);
6578 return true;
6581 // ES2019 draft rev 49b781ec80117b60f73327ef3054703a3111e40c
6582 // 14.4.14 Runtime Semantics: Evaluation
6583 // YieldExpression : yield* AssignmentExpression
6584 bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
6585 MOZ_ASSERT(getSelfHostedIterFor(iter) == SelfHostedIter::Deny,
6586 "yield* is prohibited in self-hosted code because it can run "
6587 "user-modifiable iteration code");
6589 MOZ_ASSERT(sc->isSuspendableContext());
6590 MOZ_ASSERT(sc->asSuspendableContext()->isGenerator());
6592 // Step 1.
6593 IteratorKind iterKind = sc->asSuspendableContext()->isAsync()
6594 ? IteratorKind::Async
6595 : IteratorKind::Sync;
6596 bool needsIteratorResult = sc->asSuspendableContext()->needsIteratorResult();
6598 // Steps 2-5.
6599 if (!emitTree(iter)) {
6600 // [stack] ITERABLE
6601 return false;
6603 if (iterKind == IteratorKind::Async) {
6604 if (!emitAsyncIterator(SelfHostedIter::Deny)) {
6605 // [stack] NEXT ITER
6606 return false;
6608 } else {
6609 if (!emitIterator(SelfHostedIter::Deny)) {
6610 // [stack] NEXT ITER
6611 return false;
6615 // Step 6.
6616 // Start with NormalCompletion(undefined).
6617 if (!emit1(JSOp::Undefined)) {
6618 // [stack] NEXT ITER RECEIVED
6619 return false;
6621 if (!emitPushResumeKind(GeneratorResumeKind::Next)) {
6622 // [stack] NEXT ITER RECEIVED RESUMEKIND
6623 return false;
6626 const int32_t startDepth = bytecodeSection().stackDepth();
6627 MOZ_ASSERT(startDepth >= 4);
6629 // Step 7 is a loop.
6630 LoopControl loopInfo(this, StatementKind::YieldStar);
6631 if (!loopInfo.emitLoopHead(this, Nothing())) {
6632 // [stack] NEXT ITER RECEIVED RESUMEKIND
6633 return false;
6636 // Step 7.a. Check for Normal completion.
6637 if (!emit1(JSOp::Dup)) {
6638 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND
6639 return false;
6641 if (!emitPushResumeKind(GeneratorResumeKind::Next)) {
6642 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND NORMAL
6643 return false;
6645 if (!emit1(JSOp::StrictEq)) {
6646 // [stack] NEXT ITER RECEIVED RESUMEKIND IS_NORMAL
6647 return false;
6650 InternalIfEmitter ifKind(this);
6651 if (!ifKind.emitThenElse()) {
6652 // [stack] NEXT ITER RECEIVED RESUMEKIND
6653 return false;
6656 if (!emit1(JSOp::Pop)) {
6657 // [stack] NEXT ITER RECEIVED
6658 return false;
6661 // Step 7.a.i.
6662 // result = iter.next(received)
6663 if (!emit2(JSOp::Unpick, 2)) {
6664 // [stack] RECEIVED NEXT ITER
6665 return false;
6667 if (!emit1(JSOp::Dup2)) {
6668 // [stack] RECEIVED NEXT ITER NEXT ITER
6669 return false;
6671 if (!emit2(JSOp::Pick, 4)) {
6672 // [stack] NEXT ITER NEXT ITER RECEIVED
6673 return false;
6675 if (!emitCall(JSOp::Call, 1, iter)) {
6676 // [stack] NEXT ITER RESULT
6677 return false;
6680 // Step 7.a.ii.
6681 if (iterKind == IteratorKind::Async) {
6682 if (!emitAwaitInInnermostScope()) {
6683 // [stack] NEXT ITER RESULT
6684 return false;
6688 // Step 7.a.iii.
6689 if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) {
6690 // [stack] NEXT ITER RESULT
6691 return false;
6694 // Bytecode for steps 7.a.iv-vii is emitted after the ifKind if-else because
6695 // it's shared with other branches.
6698 // Step 7.b. Check for Throw completion.
6699 if (!ifKind.emitElseIf(Nothing())) {
6700 // [stack] NEXT ITER RECEIVED RESUMEKIND
6701 return false;
6703 if (!emit1(JSOp::Dup)) {
6704 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND
6705 return false;
6707 if (!emitPushResumeKind(GeneratorResumeKind::Throw)) {
6708 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND THROW
6709 return false;
6711 if (!emit1(JSOp::StrictEq)) {
6712 // [stack] NEXT ITER RECEIVED RESUMEKIND IS_THROW
6713 return false;
6715 if (!ifKind.emitThenElse()) {
6716 // [stack] NEXT ITER RECEIVED RESUMEKIND
6717 return false;
6720 if (!emit1(JSOp::Pop)) {
6721 // [stack] NEXT ITER RECEIVED
6722 return false;
6724 // Step 7.b.i.
6725 if (!emitDupAt(1)) {
6726 // [stack] NEXT ITER RECEIVED ITER
6727 return false;
6729 if (!emit1(JSOp::Dup)) {
6730 // [stack] NEXT ITER RECEIVED ITER ITER
6731 return false;
6733 if (!emitAtomOp(JSOp::GetProp,
6734 TaggedParserAtomIndex::WellKnown::throw_())) {
6735 // [stack] NEXT ITER RECEIVED ITER THROW
6736 return false;
6739 // Step 7.b.ii.
6740 InternalIfEmitter ifThrowMethodIsNotDefined(this);
6741 if (!emit1(JSOp::IsNullOrUndefined)) {
6742 // [stack] NEXT ITER RECEIVED ITER THROW NULL-OR-UNDEF
6743 return false;
6746 if (!ifThrowMethodIsNotDefined.emitThenElse(
6747 IfEmitter::ConditionKind::Negative)) {
6748 // [stack] NEXT ITER RECEIVED ITER THROW
6749 return false;
6752 // Step 7.b.ii.1.
6753 // RESULT = ITER.throw(EXCEPTION)
6754 if (!emit1(JSOp::Swap)) {
6755 // [stack] NEXT ITER RECEIVED THROW ITER
6756 return false;
6758 if (!emit2(JSOp::Pick, 2)) {
6759 // [stack] NEXT ITER THROW ITER RECEIVED
6760 return false;
6762 if (!emitCall(JSOp::Call, 1, iter)) {
6763 // [stack] NEXT ITER RESULT
6764 return false;
6767 // Step 7.b.ii.2.
6768 if (iterKind == IteratorKind::Async) {
6769 if (!emitAwaitInInnermostScope()) {
6770 // [stack] NEXT ITER RESULT
6771 return false;
6775 // Step 7.b.ii.4.
6776 if (!emitCheckIsObj(CheckIsObjectKind::IteratorThrow)) {
6777 // [stack] NEXT ITER RESULT
6778 return false;
6781 // Bytecode for steps 7.b.ii.5-8 is emitted after the ifKind if-else because
6782 // it's shared with other branches.
6784 // Step 7.b.iii.
6785 if (!ifThrowMethodIsNotDefined.emitElse()) {
6786 // [stack] NEXT ITER RECEIVED ITER THROW
6787 return false;
6789 if (!emit1(JSOp::Pop)) {
6790 // [stack] NEXT ITER RECEIVED ITER
6791 return false;
6794 // Steps 7.b.iii.1-4.
6796 // If the iterator does not have a "throw" method, it calls IteratorClose
6797 // and then throws a TypeError.
6798 if (!emitIteratorCloseInInnermostScope(iterKind, CompletionKind::Normal)) {
6799 // [stack] NEXT ITER RECEIVED ITER
6800 return false;
6802 // Steps 7.b.iii.5-6.
6803 if (!emit2(JSOp::ThrowMsg, uint8_t(ThrowMsgKind::IteratorNoThrow))) {
6804 // [stack] NEXT ITER RECEIVED ITER
6805 // [stack] # throw
6806 return false;
6809 if (!ifThrowMethodIsNotDefined.emitEnd()) {
6810 return false;
6814 // Step 7.c. It must be a Return completion.
6815 if (!ifKind.emitElse()) {
6816 // [stack] NEXT ITER RECEIVED RESUMEKIND
6817 return false;
6820 if (!emit1(JSOp::Pop)) {
6821 // [stack] NEXT ITER RECEIVED
6822 return false;
6825 // Step 7.c.i.
6827 // Call iterator.return() for receiving a "forced return" completion from
6828 // the generator.
6830 // Step 7.c.ii.
6832 // Get the "return" method.
6833 if (!emitDupAt(1)) {
6834 // [stack] NEXT ITER RECEIVED ITER
6835 return false;
6837 if (!emit1(JSOp::Dup)) {
6838 // [stack] NEXT ITER RECEIVED ITER ITER
6839 return false;
6841 if (!emitAtomOp(JSOp::GetProp,
6842 TaggedParserAtomIndex::WellKnown::return_())) {
6843 // [stack] NEXT ITER RECEIVED ITER RET
6844 return false;
6847 // Step 7.c.iii.
6849 // Do nothing if "return" is undefined or null.
6850 InternalIfEmitter ifReturnMethodIsDefined(this);
6851 if (!emit1(JSOp::IsNullOrUndefined)) {
6852 // [stack] NEXT ITER RECEIVED ITER RET NULL-OR-UNDEF
6853 return false;
6856 // Step 7.c.iv.
6858 // Call "return" with the argument passed to Generator.prototype.return.
6859 if (!ifReturnMethodIsDefined.emitThenElse(
6860 IfEmitter::ConditionKind::Negative)) {
6861 // [stack] NEXT ITER RECEIVED ITER RET
6862 return false;
6864 if (!emit1(JSOp::Swap)) {
6865 // [stack] NEXT ITER RECEIVED RET ITER
6866 return false;
6868 if (!emit2(JSOp::Pick, 2)) {
6869 // [stack] NEXT ITER RET ITER RECEIVED
6870 return false;
6872 if (needsIteratorResult) {
6873 if (!emitAtomOp(JSOp::GetProp,
6874 TaggedParserAtomIndex::WellKnown::value())) {
6875 // [stack] NEXT ITER RET ITER VAL
6876 return false;
6879 if (!emitCall(JSOp::Call, 1)) {
6880 // [stack] NEXT ITER RESULT
6881 return false;
6884 // Step 7.c.v.
6885 if (iterKind == IteratorKind::Async) {
6886 if (!emitAwaitInInnermostScope()) {
6887 // [stack] NEXT ITER RESULT
6888 return false;
6892 // Step 7.c.vi.
6893 if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) {
6894 // [stack] NEXT ITER RESULT
6895 return false;
6898 // Check if the returned object from iterator.return() is done. If not,
6899 // continue yielding.
6901 // Steps 7.c.vii-viii.
6902 InternalIfEmitter ifReturnDone(this);
6903 if (!emit1(JSOp::Dup)) {
6904 // [stack] NEXT ITER RESULT RESULT
6905 return false;
6907 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::done())) {
6908 // [stack] NEXT ITER RESULT DONE
6909 return false;
6911 if (!ifReturnDone.emitThenElse()) {
6912 // [stack] NEXT ITER RESULT
6913 return false;
6916 // Step 7.c.viii.1.
6917 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::value())) {
6918 // [stack] NEXT ITER VALUE
6919 return false;
6921 if (needsIteratorResult) {
6922 if (!emitPrepareIteratorResult()) {
6923 // [stack] NEXT ITER VALUE RESULT
6924 return false;
6926 if (!emit1(JSOp::Swap)) {
6927 // [stack] NEXT ITER RESULT VALUE
6928 return false;
6930 if (!emitFinishIteratorResult(true)) {
6931 // [stack] NEXT ITER RESULT
6932 return false;
6936 if (!ifReturnDone.emitElse()) {
6937 // [stack] NEXT ITER RESULT
6938 return false;
6941 // Jump to continue label for steps 7.c.ix-x.
6942 if (!emitJump(JSOp::Goto, &loopInfo.continues)) {
6943 // [stack] NEXT ITER RESULT
6944 return false;
6947 if (!ifReturnDone.emitEnd()) {
6948 // [stack] NEXT ITER RESULT
6949 return false;
6952 // Step 7.c.iii.
6953 if (!ifReturnMethodIsDefined.emitElse()) {
6954 // [stack] NEXT ITER RECEIVED ITER RET
6955 return false;
6957 if (!emitPopN(2)) {
6958 // [stack] NEXT ITER RECEIVED
6959 return false;
6961 if (iterKind == IteratorKind::Async) {
6962 // Step 7.c.iii.1.
6963 if (!emitAwaitInInnermostScope()) {
6964 // [stack] NEXT ITER RECEIVED
6965 return false;
6968 if (!ifReturnMethodIsDefined.emitEnd()) {
6969 // [stack] NEXT ITER RECEIVED
6970 return false;
6973 // Perform a "forced generator return".
6975 // Step 7.c.iii.2.
6976 // Step 7.c.viii.2.
6977 if (!emitGetDotGeneratorInInnermostScope()) {
6978 // [stack] NEXT ITER RESULT GENOBJ
6979 return false;
6981 if (!emitPushResumeKind(GeneratorResumeKind::Return)) {
6982 // [stack] NEXT ITER RESULT GENOBJ RESUMEKIND
6983 return false;
6985 if (!emit1(JSOp::CheckResumeKind)) {
6986 // [stack] NEXT ITER RESULT GENOBJ RESUMEKIND
6987 return false;
6991 if (!ifKind.emitEnd()) {
6992 // [stack] NEXT ITER RESULT
6993 return false;
6996 // Shared tail for Normal/Throw completions.
6998 // Steps 7.a.iv-v.
6999 // Steps 7.b.ii.5-6.
7001 // [stack] NEXT ITER RESULT
7003 // if (result.done) break;
7004 if (!emit1(JSOp::Dup)) {
7005 // [stack] NEXT ITER RESULT RESULT
7006 return false;
7008 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::done())) {
7009 // [stack] NEXT ITER RESULT DONE
7010 return false;
7012 if (!emitJump(JSOp::JumpIfTrue, &loopInfo.breaks)) {
7013 // [stack] NEXT ITER RESULT
7014 return false;
7017 // Steps 7.a.vi-vii.
7018 // Steps 7.b.ii.7-8.
7019 // Steps 7.c.ix-x.
7020 if (!loopInfo.emitContinueTarget(this)) {
7021 // [stack] NEXT ITER RESULT
7022 return false;
7024 if (iterKind == IteratorKind::Async) {
7025 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::value())) {
7026 // [stack] NEXT ITER RESULT
7027 return false;
7030 if (!emitGetDotGeneratorInInnermostScope()) {
7031 // [stack] NEXT ITER RESULT GENOBJ
7032 return false;
7034 if (!emitYieldOp(JSOp::Yield)) {
7035 // [stack] NEXT ITER RVAL GENOBJ RESUMEKIND
7036 return false;
7038 if (!emit1(JSOp::Swap)) {
7039 // [stack] NEXT ITER RVAL RESUMEKIND GENOBJ
7040 return false;
7042 if (!emit1(JSOp::Pop)) {
7043 // [stack] NEXT ITER RVAL RESUMEKIND
7044 return false;
7046 if (!loopInfo.emitLoopEnd(this, JSOp::Goto, TryNoteKind::Loop)) {
7047 // [stack] NEXT ITER RVAL RESUMEKIND
7048 return false;
7051 // Jumps to this point have 3 (instead of 4) values on the stack.
7052 MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth);
7053 bytecodeSection().setStackDepth(startDepth - 1);
7055 // [stack] NEXT ITER RESULT
7057 // Step 7.a.v.1.
7058 // Step 7.b.ii.6.a.
7060 // result.value
7061 if (!emit2(JSOp::Unpick, 2)) {
7062 // [stack] RESULT NEXT ITER
7063 return false;
7065 if (!emitPopN(2)) {
7066 // [stack] RESULT
7067 return false;
7069 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::value())) {
7070 // [stack] VALUE
7071 return false;
7074 MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth - 3);
7076 return true;
7079 bool BytecodeEmitter::emitStatementList(ListNode* stmtList) {
7080 for (ParseNode* stmt : stmtList->contents()) {
7081 if (!emitTree(stmt)) {
7082 return false;
7085 return true;
7088 bool BytecodeEmitter::emitExpressionStatement(UnaryNode* exprStmt) {
7089 MOZ_ASSERT(exprStmt->isKind(ParseNodeKind::ExpressionStmt));
7092 * Top-level or called-from-a-native JS_Execute/EvaluateScript,
7093 * debugger, and eval frames may need the value of the ultimate
7094 * expression statement as the script's result, despite the fact
7095 * that it appears useless to the compiler.
7097 * API users may also set the ReadOnlyCompileOptions::noScriptRval option when
7098 * calling JS_Compile* to suppress JSOp::SetRval.
7100 bool wantval = false;
7101 bool useful = false;
7102 if (sc->isTopLevelContext()) {
7103 useful = wantval = !sc->noScriptRval();
7106 /* Don't eliminate expressions with side effects. */
7107 ParseNode* expr = exprStmt->kid();
7108 if (!useful) {
7109 if (!checkSideEffects(expr, &useful)) {
7110 return false;
7114 * Don't eliminate apparently useless expressions if they are labeled
7115 * expression statements. The startOffset() test catches the case
7116 * where we are nesting in emitTree for a labeled compound statement.
7118 if (innermostNestableControl &&
7119 innermostNestableControl->is<LabelControl>() &&
7120 innermostNestableControl->as<LabelControl>().startOffset() >=
7121 bytecodeSection().offset()) {
7122 useful = true;
7126 if (useful) {
7127 ValueUsage valueUsage =
7128 wantval ? ValueUsage::WantValue : ValueUsage::IgnoreValue;
7129 ExpressionStatementEmitter ese(this, valueUsage);
7130 if (!ese.prepareForExpr(exprStmt->pn_pos.begin)) {
7131 return false;
7133 if (!markStepBreakpoint()) {
7134 return false;
7136 if (!emitTree(expr, valueUsage)) {
7137 return false;
7139 if (!ese.emitEnd()) {
7140 return false;
7144 return true;
7147 bool BytecodeEmitter::emitDeleteName(UnaryNode* deleteNode) {
7148 MOZ_ASSERT(deleteNode->isKind(ParseNodeKind::DeleteNameExpr));
7150 NameNode* nameExpr = &deleteNode->kid()->as<NameNode>();
7151 MOZ_ASSERT(nameExpr->isKind(ParseNodeKind::Name));
7153 return emitAtomOp(JSOp::DelName, nameExpr->atom());
7156 bool BytecodeEmitter::emitDeleteProperty(UnaryNode* deleteNode) {
7157 MOZ_ASSERT(deleteNode->isKind(ParseNodeKind::DeletePropExpr));
7159 PropertyAccess* propExpr = &deleteNode->kid()->as<PropertyAccess>();
7160 PropOpEmitter poe(this, PropOpEmitter::Kind::Delete,
7161 propExpr->as<PropertyAccess>().isSuper()
7162 ? PropOpEmitter::ObjKind::Super
7163 : PropOpEmitter::ObjKind::Other);
7164 if (propExpr->isSuper()) {
7165 // The expression |delete super.foo;| has to evaluate |super.foo|,
7166 // which could throw if |this| hasn't yet been set by a |super(...)|
7167 // call or the super-base is not an object, before throwing a
7168 // ReferenceError for attempting to delete a super-reference.
7169 UnaryNode* base = &propExpr->expression().as<UnaryNode>();
7170 if (!emitGetThisForSuperBase(base)) {
7171 // [stack] THIS
7172 return false;
7174 } else {
7175 if (!poe.prepareForObj()) {
7176 return false;
7178 if (!emitPropLHS(propExpr)) {
7179 // [stack] OBJ
7180 return false;
7184 if (!poe.emitDelete(propExpr->key().atom())) {
7185 // [stack] # if Super
7186 // [stack] THIS
7187 // [stack] # otherwise
7188 // [stack] SUCCEEDED
7189 return false;
7192 return true;
7195 bool BytecodeEmitter::emitDeleteElement(UnaryNode* deleteNode) {
7196 MOZ_ASSERT(deleteNode->isKind(ParseNodeKind::DeleteElemExpr));
7198 PropertyByValue* elemExpr = &deleteNode->kid()->as<PropertyByValue>();
7199 bool isSuper = elemExpr->isSuper();
7200 DebugOnly<bool> isPrivate =
7201 elemExpr->key().isKind(ParseNodeKind::PrivateName);
7202 MOZ_ASSERT(!isPrivate);
7203 ElemOpEmitter eoe(
7204 this, ElemOpEmitter::Kind::Delete,
7205 isSuper ? ElemOpEmitter::ObjKind::Super : ElemOpEmitter::ObjKind::Other);
7206 if (isSuper) {
7207 // The expression |delete super[foo];| has to evaluate |super[foo]|,
7208 // which could throw if |this| hasn't yet been set by a |super(...)|
7209 // call, or trigger side-effects when evaluating ToPropertyKey(foo),
7210 // or also throw when the super-base is not an object, before throwing
7211 // a ReferenceError for attempting to delete a super-reference.
7212 if (!eoe.prepareForObj()) {
7213 // [stack]
7214 return false;
7217 UnaryNode* base = &elemExpr->expression().as<UnaryNode>();
7218 if (!emitGetThisForSuperBase(base)) {
7219 // [stack] THIS
7220 return false;
7222 if (!eoe.prepareForKey()) {
7223 // [stack] THIS
7224 return false;
7226 if (!emitTree(&elemExpr->key())) {
7227 // [stack] THIS KEY
7228 return false;
7230 } else {
7231 if (!emitElemObjAndKey(elemExpr, false, eoe)) {
7232 // [stack] OBJ KEY
7233 return false;
7236 if (!eoe.emitDelete()) {
7237 // [stack] # if Super
7238 // [stack] THIS
7239 // [stack] # otherwise
7240 // [stack] SUCCEEDED
7241 return false;
7244 return true;
7247 bool BytecodeEmitter::emitDeleteExpression(UnaryNode* deleteNode) {
7248 MOZ_ASSERT(deleteNode->isKind(ParseNodeKind::DeleteExpr));
7250 ParseNode* expression = deleteNode->kid();
7252 // If useless, just emit JSOp::True; otherwise convert |delete <expr>| to
7253 // effectively |<expr>, true|.
7254 bool useful = false;
7255 if (!checkSideEffects(expression, &useful)) {
7256 return false;
7259 if (useful) {
7260 if (!emitTree(expression)) {
7261 return false;
7263 if (!emit1(JSOp::Pop)) {
7264 return false;
7268 return emit1(JSOp::True);
7271 bool BytecodeEmitter::emitDeleteOptionalChain(UnaryNode* deleteNode) {
7272 MOZ_ASSERT(deleteNode->isKind(ParseNodeKind::DeleteOptionalChainExpr));
7274 OptionalEmitter oe(this, bytecodeSection().stackDepth());
7276 ParseNode* kid = deleteNode->kid();
7277 switch (kid->getKind()) {
7278 case ParseNodeKind::ElemExpr:
7279 case ParseNodeKind::OptionalElemExpr: {
7280 auto* elemExpr = &kid->as<PropertyByValueBase>();
7281 if (!emitDeleteElementInOptChain(elemExpr, oe)) {
7282 // [stack] # If shortcircuit
7283 // [stack] UNDEFINED-OR-NULL
7284 // [stack] # otherwise
7285 // [stack] SUCCEEDED
7286 return false;
7289 break;
7291 case ParseNodeKind::DotExpr:
7292 case ParseNodeKind::OptionalDotExpr: {
7293 auto* propExpr = &kid->as<PropertyAccessBase>();
7294 if (!emitDeletePropertyInOptChain(propExpr, oe)) {
7295 // [stack] # If shortcircuit
7296 // [stack] UNDEFINED-OR-NULL
7297 // [stack] # otherwise
7298 // [stack] SUCCEEDED
7299 return false;
7301 break;
7303 default:
7304 MOZ_ASSERT_UNREACHABLE("Unrecognized optional delete ParseNodeKind");
7307 if (!oe.emitOptionalJumpTarget(JSOp::True)) {
7308 // [stack] # If shortcircuit
7309 // [stack] TRUE
7310 // [stack] # otherwise
7311 // [stack] SUCCEEDED
7312 return false;
7315 return true;
7318 bool BytecodeEmitter::emitDeletePropertyInOptChain(PropertyAccessBase* propExpr,
7319 OptionalEmitter& oe) {
7320 MOZ_ASSERT_IF(propExpr->is<PropertyAccess>(),
7321 !propExpr->as<PropertyAccess>().isSuper());
7322 PropOpEmitter poe(this, PropOpEmitter::Kind::Delete,
7323 PropOpEmitter::ObjKind::Other);
7325 if (!poe.prepareForObj()) {
7326 // [stack]
7327 return false;
7329 if (!emitOptionalTree(&propExpr->expression(), oe)) {
7330 // [stack] OBJ
7331 return false;
7333 if (propExpr->isKind(ParseNodeKind::OptionalDotExpr)) {
7334 if (!oe.emitJumpShortCircuit()) {
7335 // [stack] # if Jump
7336 // [stack] UNDEFINED-OR-NULL
7337 // [stack] # otherwise
7338 // [stack] OBJ
7339 return false;
7343 if (!poe.emitDelete(propExpr->key().atom())) {
7344 // [stack] SUCCEEDED
7345 return false;
7348 return true;
7351 bool BytecodeEmitter::emitDeleteElementInOptChain(PropertyByValueBase* elemExpr,
7352 OptionalEmitter& oe) {
7353 MOZ_ASSERT_IF(elemExpr->is<PropertyByValue>(),
7354 !elemExpr->as<PropertyByValue>().isSuper());
7355 ElemOpEmitter eoe(this, ElemOpEmitter::Kind::Delete,
7356 ElemOpEmitter::ObjKind::Other);
7358 if (!eoe.prepareForObj()) {
7359 // [stack]
7360 return false;
7363 if (!emitOptionalTree(&elemExpr->expression(), oe)) {
7364 // [stack] OBJ
7365 return false;
7368 if (elemExpr->isKind(ParseNodeKind::OptionalElemExpr)) {
7369 if (!oe.emitJumpShortCircuit()) {
7370 // [stack] # if Jump
7371 // [stack] UNDEFINED-OR-NULL
7372 // [stack] # otherwise
7373 // [stack] OBJ
7374 return false;
7378 if (!eoe.prepareForKey()) {
7379 // [stack] OBJ
7380 return false;
7383 if (!emitTree(&elemExpr->key())) {
7384 // [stack] OBJ KEY
7385 return false;
7388 if (!eoe.emitDelete()) {
7389 // [stack] SUCCEEDED
7390 return false;
7393 return true;
7396 bool BytecodeEmitter::emitDebugCheckSelfHosted() {
7397 // [stack] CALLEE
7399 #ifdef DEBUG
7400 if (!emit1(JSOp::DebugCheckSelfHosted)) {
7401 // [stack] CALLEE
7402 return false;
7404 #endif
7406 return true;
7409 bool BytecodeEmitter::emitSelfHostedCallFunction(CallNode* callNode, JSOp op) {
7410 // Special-casing of callFunction to emit bytecode that directly
7411 // invokes the callee with the correct |this| object and arguments.
7412 // callFunction(fun, thisArg, arg0, arg1) thus becomes:
7413 // - emit lookup for fun
7414 // - emit lookup for thisArg
7415 // - emit lookups for arg0, arg1
7417 // argc is set to the amount of actually emitted args and the
7418 // emitting of args below is disabled by setting emitArgs to false.
7419 NameNode* calleeNode = &callNode->callee()->as<NameNode>();
7420 ListNode* argsList = callNode->args();
7422 MOZ_ASSERT(argsList->count() >= 2);
7424 MOZ_ASSERT(callNode->callOp() == JSOp::Call);
7426 bool constructing =
7427 calleeNode->name() ==
7428 TaggedParserAtomIndex::WellKnown::constructContentFunction();
7429 ParseNode* funNode = argsList->head();
7431 if (!emitTree(funNode)) {
7432 // [stack] CALLEE
7433 return false;
7436 #ifdef DEBUG
7437 MOZ_ASSERT(op == JSOp::Call || op == JSOp::CallContent ||
7438 op == JSOp::NewContent);
7439 if (op == JSOp::Call) {
7440 if (!emitDebugCheckSelfHosted()) {
7441 // [stack] CALLEE
7442 return false;
7445 #endif
7447 ParseNode* thisOrNewTarget = funNode->pn_next;
7448 if (constructing) {
7449 // Save off the new.target value, but here emit a proper |this| for a
7450 // constructing call.
7451 if (!emit1(JSOp::IsConstructing)) {
7452 // [stack] CALLEE IS_CONSTRUCTING
7453 return false;
7455 } else {
7456 // It's |this|, emit it.
7457 if (!emitTree(thisOrNewTarget)) {
7458 // [stack] CALLEE THIS
7459 return false;
7463 for (ParseNode* argpn : argsList->contentsFrom(thisOrNewTarget->pn_next)) {
7464 if (!emitTree(argpn)) {
7465 // [stack] CALLEE ... ARGS...
7466 return false;
7470 if (constructing) {
7471 if (!emitTree(thisOrNewTarget)) {
7472 // [stack] CALLEE IS_CONSTRUCTING ARGS... NEW.TARGET
7473 return false;
7477 uint32_t argc = argsList->count() - 2;
7478 if (!emitCall(op, argc)) {
7479 // [stack] RVAL
7480 return false;
7483 return true;
7486 bool BytecodeEmitter::emitSelfHostedResumeGenerator(CallNode* callNode) {
7487 ListNode* argsList = callNode->args();
7489 // Syntax: resumeGenerator(gen, value, 'next'|'throw'|'return')
7490 MOZ_ASSERT(argsList->count() == 3);
7492 ParseNode* genNode = argsList->head();
7493 if (!emitTree(genNode)) {
7494 // [stack] GENERATOR
7495 return false;
7498 ParseNode* valNode = genNode->pn_next;
7499 if (!emitTree(valNode)) {
7500 // [stack] GENERATOR VALUE
7501 return false;
7504 ParseNode* kindNode = valNode->pn_next;
7505 MOZ_ASSERT(kindNode->isKind(ParseNodeKind::StringExpr));
7506 GeneratorResumeKind kind =
7507 ParserAtomToResumeKind(kindNode->as<NameNode>().atom());
7508 MOZ_ASSERT(!kindNode->pn_next);
7510 if (!emitPushResumeKind(kind)) {
7511 // [stack] GENERATOR VALUE RESUMEKIND
7512 return false;
7515 if (!emit1(JSOp::Resume)) {
7516 // [stack] RVAL
7517 return false;
7520 return true;
7523 bool BytecodeEmitter::emitSelfHostedForceInterpreter() {
7524 // JSScript::hasForceInterpreterOp() relies on JSOp::ForceInterpreter being
7525 // the first bytecode op in the script.
7526 MOZ_ASSERT(bytecodeSection().code().empty());
7528 if (!emit1(JSOp::ForceInterpreter)) {
7529 return false;
7531 if (!emit1(JSOp::Undefined)) {
7532 return false;
7535 return true;
7538 bool BytecodeEmitter::emitSelfHostedAllowContentIter(CallNode* callNode) {
7539 ListNode* argsList = callNode->args();
7541 MOZ_ASSERT(argsList->count() == 1);
7543 // We're just here as a sentinel. Pass the value through directly.
7544 return emitTree(argsList->head());
7547 bool BytecodeEmitter::emitSelfHostedAllowContentIterWith(CallNode* callNode) {
7548 ListNode* argsList = callNode->args();
7550 MOZ_ASSERT(argsList->count() == 2 || argsList->count() == 3);
7552 // We're just here as a sentinel. Pass the value through directly.
7553 return emitTree(argsList->head());
7556 bool BytecodeEmitter::emitSelfHostedAllowContentIterWithNext(
7557 CallNode* callNode) {
7558 ListNode* argsList = callNode->args();
7560 MOZ_ASSERT(argsList->count() == 2);
7562 // We're just here as a sentinel. Pass the value through directly.
7563 return emitTree(argsList->head());
7566 bool BytecodeEmitter::emitSelfHostedDefineDataProperty(CallNode* callNode) {
7567 ListNode* argsList = callNode->args();
7569 // Only optimize when 3 arguments are passed.
7570 MOZ_ASSERT(argsList->count() == 3);
7572 ParseNode* objNode = argsList->head();
7573 if (!emitTree(objNode)) {
7574 return false;
7577 ParseNode* idNode = objNode->pn_next;
7578 if (!emitTree(idNode)) {
7579 return false;
7582 ParseNode* valNode = idNode->pn_next;
7583 if (!emitTree(valNode)) {
7584 return false;
7587 // This will leave the object on the stack instead of pushing |undefined|,
7588 // but that's fine because the self-hosted code doesn't use the return
7589 // value.
7590 return emit1(JSOp::InitElem);
7593 bool BytecodeEmitter::emitSelfHostedHasOwn(CallNode* callNode) {
7594 ListNode* argsList = callNode->args();
7596 MOZ_ASSERT(argsList->count() == 2);
7598 ParseNode* idNode = argsList->head();
7599 if (!emitTree(idNode)) {
7600 return false;
7603 ParseNode* objNode = idNode->pn_next;
7604 if (!emitTree(objNode)) {
7605 return false;
7608 return emit1(JSOp::HasOwn);
7611 bool BytecodeEmitter::emitSelfHostedGetPropertySuper(CallNode* callNode) {
7612 ListNode* argsList = callNode->args();
7614 MOZ_ASSERT(argsList->count() == 3);
7616 ParseNode* objNode = argsList->head();
7617 ParseNode* idNode = objNode->pn_next;
7618 ParseNode* receiverNode = idNode->pn_next;
7620 if (!emitTree(receiverNode)) {
7621 return false;
7624 if (!emitTree(idNode)) {
7625 return false;
7628 if (!emitTree(objNode)) {
7629 return false;
7632 return emitElemOpBase(JSOp::GetElemSuper);
7635 bool BytecodeEmitter::emitSelfHostedToNumeric(CallNode* callNode) {
7636 ListNode* argsList = callNode->args();
7638 MOZ_ASSERT(argsList->count() == 1);
7640 ParseNode* argNode = argsList->head();
7642 if (!emitTree(argNode)) {
7643 return false;
7646 return emit1(JSOp::ToNumeric);
7649 bool BytecodeEmitter::emitSelfHostedToString(CallNode* callNode) {
7650 ListNode* argsList = callNode->args();
7652 MOZ_ASSERT(argsList->count() == 1);
7654 ParseNode* argNode = argsList->head();
7656 if (!emitTree(argNode)) {
7657 return false;
7660 return emit1(JSOp::ToString);
7663 bool BytecodeEmitter::emitSelfHostedIsNullOrUndefined(CallNode* callNode) {
7664 ListNode* argsList = callNode->args();
7666 MOZ_ASSERT(argsList->count() == 1);
7668 ParseNode* argNode = argsList->head();
7670 if (!emitTree(argNode)) {
7671 // [stack] ARG
7672 return false;
7674 if (!emit1(JSOp::IsNullOrUndefined)) {
7675 // [stack] ARG IS_NULL_OR_UNDEF
7676 return false;
7678 if (!emit1(JSOp::Swap)) {
7679 // [stack] IS_NULL_OR_UNDEF ARG
7680 return false;
7682 if (!emit1(JSOp::Pop)) {
7683 // [stack] IS_NULL_OR_UNDEF
7684 return false;
7686 return true;
7689 bool BytecodeEmitter::emitSelfHostedIteratorClose(CallNode* callNode) {
7690 ListNode* argsList = callNode->args();
7691 MOZ_ASSERT(argsList->count() == 1);
7693 ParseNode* argNode = argsList->head();
7694 if (!emitTree(argNode)) {
7695 // [stack] ARG
7696 return false;
7699 if (!emit2(JSOp::CloseIter, uint8_t(CompletionKind::Normal))) {
7700 // [stack]
7701 return false;
7704 // This is still a call node, so we must generate a stack value.
7705 if (!emit1(JSOp::Undefined)) {
7706 // [stack] RVAL
7707 return false;
7710 return true;
7713 bool BytecodeEmitter::emitSelfHostedGetBuiltinConstructorOrPrototype(
7714 CallNode* callNode, bool isConstructor) {
7715 ListNode* argsList = callNode->args();
7717 MOZ_ASSERT(argsList->count() == 1);
7719 ParseNode* argNode = argsList->head();
7721 if (!argNode->isKind(ParseNodeKind::StringExpr)) {
7722 reportError(callNode, JSMSG_UNEXPECTED_TYPE, "built-in name",
7723 "not a string constant");
7724 return false;
7727 auto name = argNode->as<NameNode>().atom();
7729 BuiltinObjectKind kind;
7730 if (isConstructor) {
7731 kind = BuiltinConstructorForName(name);
7732 } else {
7733 kind = BuiltinPrototypeForName(name);
7736 if (kind == BuiltinObjectKind::None) {
7737 reportError(callNode, JSMSG_UNEXPECTED_TYPE, "built-in name",
7738 "not a valid built-in");
7739 return false;
7742 return emitBuiltinObject(kind);
7745 bool BytecodeEmitter::emitSelfHostedGetBuiltinConstructor(CallNode* callNode) {
7746 return emitSelfHostedGetBuiltinConstructorOrPrototype(
7747 callNode, /* isConstructor = */ true);
7750 bool BytecodeEmitter::emitSelfHostedGetBuiltinPrototype(CallNode* callNode) {
7751 return emitSelfHostedGetBuiltinConstructorOrPrototype(
7752 callNode, /* isConstructor = */ false);
7755 JS::SymbolCode ParserAtomToSymbolCode(TaggedParserAtomIndex atom) {
7756 // NOTE: This is a linear search, but the set of entries is quite small and
7757 // this is only used for initial self-hosted parse.
7758 #define MATCH_WELL_KNOWN_SYMBOL(NAME) \
7759 if (atom == TaggedParserAtomIndex::WellKnown::NAME()) { \
7760 return JS::SymbolCode::NAME; \
7762 JS_FOR_EACH_WELL_KNOWN_SYMBOL(MATCH_WELL_KNOWN_SYMBOL)
7763 #undef MATCH_WELL_KNOWN_SYMBOL
7765 return JS::SymbolCode::Limit;
7768 bool BytecodeEmitter::emitSelfHostedGetBuiltinSymbol(CallNode* callNode) {
7769 ListNode* argsList = callNode->args();
7771 MOZ_ASSERT(argsList->count() == 1);
7773 ParseNode* argNode = argsList->head();
7775 if (!argNode->isKind(ParseNodeKind::StringExpr)) {
7776 reportError(callNode, JSMSG_UNEXPECTED_TYPE, "built-in name",
7777 "not a string constant");
7778 return false;
7781 auto name = argNode->as<NameNode>().atom();
7783 JS::SymbolCode code = ParserAtomToSymbolCode(name);
7784 if (code == JS::SymbolCode::Limit) {
7785 reportError(callNode, JSMSG_UNEXPECTED_TYPE, "built-in name",
7786 "not a valid built-in");
7787 return false;
7790 return emit2(JSOp::Symbol, uint8_t(code));
7793 bool BytecodeEmitter::emitSelfHostedArgumentsLength(CallNode* callNode) {
7794 MOZ_ASSERT(!sc->asFunctionBox()->needsArgsObj());
7795 sc->asFunctionBox()->setUsesArgumentsIntrinsics();
7797 MOZ_ASSERT(callNode->args()->count() == 0);
7799 return emit1(JSOp::ArgumentsLength);
7802 bool BytecodeEmitter::emitSelfHostedGetArgument(CallNode* callNode) {
7803 MOZ_ASSERT(!sc->asFunctionBox()->needsArgsObj());
7804 sc->asFunctionBox()->setUsesArgumentsIntrinsics();
7806 ListNode* argsList = callNode->args();
7807 MOZ_ASSERT(argsList->count() == 1);
7809 ParseNode* argNode = argsList->head();
7810 if (!emitTree(argNode)) {
7811 return false;
7814 return emit1(JSOp::GetActualArg);
7817 #ifdef DEBUG
7818 void BytecodeEmitter::assertSelfHostedExpectedTopLevel(ParseNode* node) {
7819 // The function argument is expected to be a simple binding/function name.
7820 // Eg. `function foo() { }; SpecialIntrinsic(foo)`
7821 MOZ_ASSERT(node->isKind(ParseNodeKind::Name),
7822 "argument must be a function name");
7823 TaggedParserAtomIndex targetName = node->as<NameNode>().name();
7825 // The special intrinsics must follow the target functions definition. A
7826 // simple assert is fine here since any hoisted function will cause a non-null
7827 // value to be set here.
7828 MOZ_ASSERT(prevSelfHostedTopLevelFunction);
7830 // The target function must match the most recently defined top-level
7831 // self-hosted function.
7832 MOZ_ASSERT(prevSelfHostedTopLevelFunction->explicitName() == targetName,
7833 "selfhost decorator must immediately follow target function");
7835 #endif
7837 bool BytecodeEmitter::emitSelfHostedSetIsInlinableLargeFunction(
7838 CallNode* callNode) {
7839 #ifdef DEBUG
7840 ListNode* argsList = callNode->args();
7842 MOZ_ASSERT(argsList->count() == 1);
7844 assertSelfHostedExpectedTopLevel(argsList->head());
7845 #endif
7847 MOZ_ASSERT(prevSelfHostedTopLevelFunction->isInitialCompilation);
7848 prevSelfHostedTopLevelFunction->setIsInlinableLargeFunction();
7850 // This is still a call node, so we must generate a stack value.
7851 return emit1(JSOp::Undefined);
7854 bool BytecodeEmitter::emitSelfHostedSetCanonicalName(CallNode* callNode) {
7855 ListNode* argsList = callNode->args();
7857 MOZ_ASSERT(argsList->count() == 2);
7859 #ifdef DEBUG
7860 assertSelfHostedExpectedTopLevel(argsList->head());
7861 #endif
7863 ParseNode* nameNode = argsList->last();
7864 MOZ_ASSERT(nameNode->isKind(ParseNodeKind::StringExpr));
7865 TaggedParserAtomIndex specName = nameNode->as<NameNode>().atom();
7866 // Canonical name must be atomized.
7867 compilationState.parserAtoms.markUsedByStencil(specName,
7868 ParserAtom::Atomize::Yes);
7870 // Store the canonical name for instantiation.
7871 prevSelfHostedTopLevelFunction->functionStencil().setSelfHostedCanonicalName(
7872 specName);
7874 return emit1(JSOp::Undefined);
7877 #ifdef DEBUG
7878 void BytecodeEmitter::assertSelfHostedUnsafeGetReservedSlot(
7879 ListNode* argsList) {
7880 MOZ_ASSERT(argsList->count() == 2);
7882 ParseNode* objNode = argsList->head();
7883 ParseNode* slotNode = objNode->pn_next;
7885 // Ensure that the slot argument is fixed, this is required by the JITs.
7886 MOZ_ASSERT(slotNode->isKind(ParseNodeKind::NumberExpr),
7887 "slot argument must be a constant");
7890 void BytecodeEmitter::assertSelfHostedUnsafeSetReservedSlot(
7891 ListNode* argsList) {
7892 MOZ_ASSERT(argsList->count() == 3);
7894 ParseNode* objNode = argsList->head();
7895 ParseNode* slotNode = objNode->pn_next;
7897 // Ensure that the slot argument is fixed, this is required by the JITs.
7898 MOZ_ASSERT(slotNode->isKind(ParseNodeKind::NumberExpr),
7899 "slot argument must be a constant");
7901 #endif
7903 /* A version of emitCalleeAndThis for the optional cases:
7904 * * a?.()
7905 * * a?.b()
7906 * * a?.["b"]()
7907 * * (a?.b)()
7908 * * a?.#b()
7910 * See emitCallOrNew and emitOptionalCall for more context.
7912 bool BytecodeEmitter::emitOptionalCalleeAndThis(ParseNode* callee,
7913 CallNode* call,
7914 CallOrNewEmitter& cone,
7915 OptionalEmitter& oe) {
7916 AutoCheckRecursionLimit recursion(fc);
7917 if (!recursion.check(fc)) {
7918 return false;
7921 switch (ParseNodeKind kind = callee->getKind()) {
7922 case ParseNodeKind::Name: {
7923 auto name = callee->as<NameNode>().name();
7924 if (!cone.emitNameCallee(name)) {
7925 // [stack] CALLEE THIS
7926 return false;
7928 break;
7931 case ParseNodeKind::OptionalDotExpr: {
7932 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
7933 OptionalPropertyAccess* prop = &callee->as<OptionalPropertyAccess>();
7934 bool isSuper = false;
7936 PropOpEmitter& poe = cone.prepareForPropCallee(isSuper);
7937 if (!emitOptionalDotExpression(prop, poe, isSuper, oe)) {
7938 // [stack] CALLEE THIS
7939 return false;
7941 break;
7943 case ParseNodeKind::DotExpr: {
7944 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
7945 PropertyAccess* prop = &callee->as<PropertyAccess>();
7946 bool isSuper = prop->isSuper();
7948 PropOpEmitter& poe = cone.prepareForPropCallee(isSuper);
7949 if (!emitOptionalDotExpression(prop, poe, isSuper, oe)) {
7950 // [stack] CALLEE THIS
7951 return false;
7953 break;
7956 case ParseNodeKind::OptionalElemExpr: {
7957 OptionalPropertyByValue* elem = &callee->as<OptionalPropertyByValue>();
7958 bool isSuper = false;
7959 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
7960 ElemOpEmitter& eoe = cone.prepareForElemCallee(isSuper);
7961 if (!emitOptionalElemExpression(elem, eoe, isSuper, oe)) {
7962 // [stack] CALLEE THIS
7963 return false;
7965 break;
7967 case ParseNodeKind::ElemExpr: {
7968 PropertyByValue* elem = &callee->as<PropertyByValue>();
7969 bool isSuper = elem->isSuper();
7970 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
7971 ElemOpEmitter& eoe = cone.prepareForElemCallee(isSuper);
7972 if (!emitOptionalElemExpression(elem, eoe, isSuper, oe)) {
7973 // [stack] CALLEE THIS
7974 return false;
7976 break;
7979 case ParseNodeKind::PrivateMemberExpr:
7980 case ParseNodeKind::OptionalPrivateMemberExpr: {
7981 PrivateMemberAccessBase* privateExpr =
7982 &callee->as<PrivateMemberAccessBase>();
7983 PrivateOpEmitter& xoe =
7984 cone.prepareForPrivateCallee(privateExpr->privateName().name());
7985 if (!emitOptionalPrivateExpression(privateExpr, xoe, oe)) {
7986 // [stack] CALLEE THIS
7987 return false;
7989 break;
7992 case ParseNodeKind::Function:
7993 if (!cone.prepareForFunctionCallee()) {
7994 return false;
7996 if (!emitOptionalTree(callee, oe)) {
7997 // [stack] CALLEE
7998 return false;
8000 break;
8002 case ParseNodeKind::OptionalChain: {
8003 return emitCalleeAndThisForOptionalChain(&callee->as<UnaryNode>(), call,
8004 cone);
8007 default:
8008 MOZ_RELEASE_ASSERT(kind != ParseNodeKind::SuperBase);
8010 if (!cone.prepareForOtherCallee()) {
8011 return false;
8013 if (!emitOptionalTree(callee, oe)) {
8014 // [stack] CALLEE
8015 return false;
8017 break;
8020 if (!cone.emitThis()) {
8021 // [stack] CALLEE THIS
8022 return false;
8025 return true;
8028 bool BytecodeEmitter::emitCalleeAndThis(ParseNode* callee, CallNode* call,
8029 CallOrNewEmitter& cone) {
8030 MOZ_ASSERT(call->callee() == callee);
8032 switch (callee->getKind()) {
8033 case ParseNodeKind::Name: {
8034 auto name = callee->as<NameNode>().name();
8035 if (!cone.emitNameCallee(name)) {
8036 // [stack] CALLEE THIS?
8037 return false;
8039 break;
8041 case ParseNodeKind::DotExpr: {
8042 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
8043 PropertyAccess* prop = &callee->as<PropertyAccess>();
8044 bool isSuper = prop->isSuper();
8046 PropOpEmitter& poe = cone.prepareForPropCallee(isSuper);
8047 if (!poe.prepareForObj()) {
8048 return false;
8050 if (isSuper) {
8051 UnaryNode* base = &prop->expression().as<UnaryNode>();
8052 if (!emitGetThisForSuperBase(base)) {
8053 // [stack] THIS
8054 return false;
8056 } else {
8057 if (!emitPropLHS(prop)) {
8058 // [stack] OBJ
8059 return false;
8062 if (!poe.emitGet(prop->key().atom())) {
8063 // [stack] CALLEE THIS?
8064 return false;
8067 break;
8069 case ParseNodeKind::ElemExpr: {
8070 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
8071 PropertyByValue* elem = &callee->as<PropertyByValue>();
8072 bool isSuper = elem->isSuper();
8073 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
8074 ElemOpEmitter& eoe = cone.prepareForElemCallee(isSuper);
8075 if (!emitElemObjAndKey(elem, isSuper, eoe)) {
8076 // [stack] # if Super
8077 // [stack] THIS? THIS KEY
8078 // [stack] # otherwise
8079 // [stack] OBJ? OBJ KEY
8080 return false;
8082 if (!eoe.emitGet()) {
8083 // [stack] CALLEE THIS?
8084 return false;
8087 break;
8089 case ParseNodeKind::PrivateMemberExpr: {
8090 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
8091 PrivateMemberAccessBase* privateExpr =
8092 &callee->as<PrivateMemberAccessBase>();
8093 PrivateOpEmitter& xoe =
8094 cone.prepareForPrivateCallee(privateExpr->privateName().name());
8095 if (!emitTree(&privateExpr->expression())) {
8096 // [stack] OBJ
8097 return false;
8099 if (!xoe.emitReference()) {
8100 // [stack] OBJ NAME
8101 return false;
8103 if (!xoe.emitGetForCallOrNew()) {
8104 // [stack] CALLEE THIS
8105 return false;
8108 break;
8110 case ParseNodeKind::Function:
8111 if (!cone.prepareForFunctionCallee()) {
8112 return false;
8114 if (!emitTree(callee)) {
8115 // [stack] CALLEE
8116 return false;
8118 break;
8119 case ParseNodeKind::SuperBase:
8120 MOZ_ASSERT(call->isKind(ParseNodeKind::SuperCallExpr));
8121 MOZ_ASSERT(callee->isKind(ParseNodeKind::SuperBase));
8122 if (!cone.emitSuperCallee()) {
8123 // [stack] CALLEE IsConstructing
8124 return false;
8126 break;
8127 case ParseNodeKind::OptionalChain: {
8128 return emitCalleeAndThisForOptionalChain(&callee->as<UnaryNode>(), call,
8129 cone);
8131 default:
8132 if (!cone.prepareForOtherCallee()) {
8133 return false;
8135 if (!emitTree(callee)) {
8136 return false;
8138 break;
8141 if (!cone.emitThis()) {
8142 // [stack] CALLEE THIS
8143 return false;
8146 return true;
8149 ParseNode* BytecodeEmitter::getCoordNode(ParseNode* callNode,
8150 ParseNode* calleeNode, JSOp op,
8151 ListNode* argsList) {
8152 ParseNode* coordNode = callNode;
8153 if (op == JSOp::Call || op == JSOp::SpreadCall) {
8154 // Default to using the location of the `(` itself.
8155 // obj[expr]() // expression
8156 // ^ // column coord
8157 coordNode = argsList;
8159 switch (calleeNode->getKind()) {
8160 case ParseNodeKind::DotExpr:
8161 // Use the position of a property access identifier.
8163 // obj().aprop() // expression
8164 // ^ // column coord
8166 // Note: Because of the constant folding logic in FoldElement,
8167 // this case also applies for constant string properties.
8169 // obj()['aprop']() // expression
8170 // ^ // column coord
8171 coordNode = &calleeNode->as<PropertyAccess>().key();
8172 break;
8173 case ParseNodeKind::Name: {
8174 // Use the start of callee name unless it is at a separator
8175 // or has no args.
8177 // 2 + obj() // expression
8178 // ^ // column coord
8180 if (argsList->empty() ||
8181 !bytecodeSection().atSeparator(calleeNode->pn_pos.begin)) {
8182 // Use the start of callee names.
8183 coordNode = calleeNode;
8185 break;
8188 default:
8189 break;
8192 return coordNode;
8195 bool BytecodeEmitter::emitArguments(ListNode* argsList, bool isCall,
8196 bool isSpread, CallOrNewEmitter& cone) {
8197 uint32_t argc = argsList->count();
8198 if (argc >= ARGC_LIMIT) {
8199 reportError(argsList,
8200 isCall ? JSMSG_TOO_MANY_FUN_ARGS : JSMSG_TOO_MANY_CON_ARGS);
8201 return false;
8203 if (!isSpread) {
8204 if (!cone.prepareForNonSpreadArguments()) {
8205 // [stack] CALLEE THIS
8206 return false;
8208 for (ParseNode* arg : argsList->contents()) {
8209 if (!updateSourceCoordNotesIfNonLiteral(arg)) {
8210 return false;
8212 if (!emitTree(arg)) {
8213 // [stack] CALLEE THIS ARG*
8214 return false;
8217 } else if (cone.wantSpreadOperand()) {
8218 auto* spreadNode = &argsList->head()->as<UnaryNode>();
8219 if (!updateSourceCoordNotesIfNonLiteral(spreadNode->kid())) {
8220 return false;
8222 if (!emitTree(spreadNode->kid())) {
8223 // [stack] CALLEE THIS ARG0
8224 return false;
8227 if (!cone.emitSpreadArgumentsTest()) {
8228 // [stack] CALLEE THIS ARG0
8229 return false;
8232 if (cone.wantSpreadIteration()) {
8233 if (!emitSpreadIntoArray(spreadNode)) {
8234 // [stack] CALLEE THIS ARR
8235 return false;
8239 if (!cone.emitSpreadArgumentsTestEnd()) {
8240 // [stack] CALLEE THIS ARR
8241 return false;
8243 } else {
8244 if (!cone.prepareForSpreadArguments()) {
8245 // [stack] CALLEE THIS
8246 return false;
8248 if (!emitArray(argsList)) {
8249 // [stack] CALLEE THIS ARR
8250 return false;
8254 return true;
8257 bool BytecodeEmitter::emitOptionalCall(CallNode* callNode, OptionalEmitter& oe,
8258 ValueUsage valueUsage) {
8260 * A modified version of emitCallOrNew that handles optional calls.
8262 * These include the following:
8263 * a?.()
8264 * a.b?.()
8265 * a.["b"]?.()
8266 * (a?.b)?.()
8268 * See CallOrNewEmitter for more context.
8270 ParseNode* calleeNode = callNode->callee();
8271 ListNode* argsList = callNode->args();
8272 bool isSpread = IsSpreadOp(callNode->callOp());
8273 JSOp op = callNode->callOp();
8274 uint32_t argc = argsList->count();
8275 bool isOptimizableSpread = isSpread && argc == 1;
8277 CallOrNewEmitter cone(this, op,
8278 isOptimizableSpread
8279 ? CallOrNewEmitter::ArgumentsKind::SingleSpread
8280 : CallOrNewEmitter::ArgumentsKind::Other,
8281 valueUsage);
8283 ParseNode* coordNode = getCoordNode(callNode, calleeNode, op, argsList);
8285 if (!emitOptionalCalleeAndThis(calleeNode, callNode, cone, oe)) {
8286 // [stack] CALLEE THIS
8287 return false;
8290 if (callNode->isKind(ParseNodeKind::OptionalCallExpr)) {
8291 if (!oe.emitJumpShortCircuitForCall()) {
8292 // [stack] CALLEE THIS
8293 return false;
8297 if (!emitArguments(argsList, /* isCall = */ true, isSpread, cone)) {
8298 // [stack] CALLEE THIS ARGS...
8299 return false;
8302 if (!cone.emitEnd(argc, coordNode->pn_pos.begin)) {
8303 // [stack] RVAL
8304 return false;
8307 return true;
8310 bool BytecodeEmitter::emitCallOrNew(CallNode* callNode, ValueUsage valueUsage) {
8312 * Emit callable invocation or operator new (constructor call) code.
8313 * First, emit code for the left operand to evaluate the callable or
8314 * constructable object expression.
8316 * Then (or in a call case that has no explicit reference-base
8317 * object) we emit JSOp::Undefined to produce the undefined |this|
8318 * value required for calls (which non-strict mode functions
8319 * will box into the global object).
8321 bool isCall = callNode->isKind(ParseNodeKind::CallExpr) ||
8322 callNode->isKind(ParseNodeKind::TaggedTemplateExpr);
8323 ParseNode* calleeNode = callNode->callee();
8324 ListNode* argsList = callNode->args();
8325 JSOp op = callNode->callOp();
8327 if (calleeNode->isKind(ParseNodeKind::Name) &&
8328 emitterMode == BytecodeEmitter::SelfHosting && op == JSOp::Call) {
8329 // Calls to "forceInterpreter", "callFunction",
8330 // "callContentFunction", or "resumeGenerator" in self-hosted
8331 // code generate inline bytecode.
8333 // NOTE: The list of special instruction names has to be kept in sync with
8334 // "js/src/builtin/.eslintrc.js".
8335 auto calleeName = calleeNode->as<NameNode>().name();
8336 if (calleeName == TaggedParserAtomIndex::WellKnown::callFunction()) {
8337 return emitSelfHostedCallFunction(callNode, JSOp::Call);
8339 if (calleeName == TaggedParserAtomIndex::WellKnown::callContentFunction()) {
8340 return emitSelfHostedCallFunction(callNode, JSOp::CallContent);
8342 if (calleeName ==
8343 TaggedParserAtomIndex::WellKnown::constructContentFunction()) {
8344 return emitSelfHostedCallFunction(callNode, JSOp::NewContent);
8346 if (calleeName == TaggedParserAtomIndex::WellKnown::resumeGenerator()) {
8347 return emitSelfHostedResumeGenerator(callNode);
8349 if (calleeName == TaggedParserAtomIndex::WellKnown::forceInterpreter()) {
8350 return emitSelfHostedForceInterpreter();
8352 if (calleeName == TaggedParserAtomIndex::WellKnown::allowContentIter()) {
8353 return emitSelfHostedAllowContentIter(callNode);
8355 if (calleeName ==
8356 TaggedParserAtomIndex::WellKnown::allowContentIterWith()) {
8357 return emitSelfHostedAllowContentIterWith(callNode);
8359 if (calleeName ==
8360 TaggedParserAtomIndex::WellKnown::allowContentIterWithNext()) {
8361 return emitSelfHostedAllowContentIterWithNext(callNode);
8363 if (calleeName == TaggedParserAtomIndex::WellKnown::DefineDataProperty() &&
8364 argsList->count() == 3) {
8365 return emitSelfHostedDefineDataProperty(callNode);
8367 if (calleeName == TaggedParserAtomIndex::WellKnown::hasOwn()) {
8368 return emitSelfHostedHasOwn(callNode);
8370 if (calleeName == TaggedParserAtomIndex::WellKnown::getPropertySuper()) {
8371 return emitSelfHostedGetPropertySuper(callNode);
8373 if (calleeName == TaggedParserAtomIndex::WellKnown::ToNumeric()) {
8374 return emitSelfHostedToNumeric(callNode);
8376 if (calleeName == TaggedParserAtomIndex::WellKnown::ToString()) {
8377 return emitSelfHostedToString(callNode);
8379 if (calleeName ==
8380 TaggedParserAtomIndex::WellKnown::GetBuiltinConstructor()) {
8381 return emitSelfHostedGetBuiltinConstructor(callNode);
8383 if (calleeName == TaggedParserAtomIndex::WellKnown::GetBuiltinPrototype()) {
8384 return emitSelfHostedGetBuiltinPrototype(callNode);
8386 if (calleeName == TaggedParserAtomIndex::WellKnown::GetBuiltinSymbol()) {
8387 return emitSelfHostedGetBuiltinSymbol(callNode);
8389 if (calleeName == TaggedParserAtomIndex::WellKnown::ArgumentsLength()) {
8390 return emitSelfHostedArgumentsLength(callNode);
8392 if (calleeName == TaggedParserAtomIndex::WellKnown::GetArgument()) {
8393 return emitSelfHostedGetArgument(callNode);
8395 if (calleeName ==
8396 TaggedParserAtomIndex::WellKnown::SetIsInlinableLargeFunction()) {
8397 return emitSelfHostedSetIsInlinableLargeFunction(callNode);
8399 if (calleeName == TaggedParserAtomIndex::WellKnown::SetCanonicalName()) {
8400 return emitSelfHostedSetCanonicalName(callNode);
8402 if (calleeName == TaggedParserAtomIndex::WellKnown::IsNullOrUndefined()) {
8403 return emitSelfHostedIsNullOrUndefined(callNode);
8405 if (calleeName == TaggedParserAtomIndex::WellKnown::IteratorClose()) {
8406 return emitSelfHostedIteratorClose(callNode);
8408 #ifdef DEBUG
8409 if (calleeName ==
8410 TaggedParserAtomIndex::WellKnown::UnsafeGetReservedSlot() ||
8411 calleeName == TaggedParserAtomIndex::WellKnown::
8412 UnsafeGetObjectFromReservedSlot() ||
8413 calleeName == TaggedParserAtomIndex::WellKnown::
8414 UnsafeGetInt32FromReservedSlot() ||
8415 calleeName == TaggedParserAtomIndex::WellKnown::
8416 UnsafeGetStringFromReservedSlot()) {
8417 // Make sure that this call is correct, but don't emit any special code.
8418 assertSelfHostedUnsafeGetReservedSlot(argsList);
8420 if (calleeName ==
8421 TaggedParserAtomIndex::WellKnown::UnsafeSetReservedSlot()) {
8422 // Make sure that this call is correct, but don't emit any special code.
8423 assertSelfHostedUnsafeSetReservedSlot(argsList);
8425 #endif
8426 // Fall through
8429 uint32_t argc = argsList->count();
8430 bool isSpread = IsSpreadOp(op);
8431 bool isOptimizableSpread = isSpread && argc == 1;
8432 bool isDefaultDerivedClassConstructor =
8433 sc->isFunctionBox() && sc->asFunctionBox()->isDerivedClassConstructor() &&
8434 sc->asFunctionBox()->isSyntheticFunction();
8435 MOZ_ASSERT_IF(isDefaultDerivedClassConstructor, isOptimizableSpread);
8436 CallOrNewEmitter cone(
8437 this, op,
8438 isOptimizableSpread
8439 ? isDefaultDerivedClassConstructor
8440 ? CallOrNewEmitter::ArgumentsKind::PassthroughRest
8441 : CallOrNewEmitter::ArgumentsKind::SingleSpread
8442 : CallOrNewEmitter::ArgumentsKind::Other,
8443 valueUsage);
8445 if (!emitCalleeAndThis(calleeNode, callNode, cone)) {
8446 // [stack] CALLEE THIS
8447 return false;
8449 if (!emitArguments(argsList, isCall, isSpread, cone)) {
8450 // [stack] CALLEE THIS ARGS...
8451 return false;
8454 // Push new.target for construct calls.
8455 if (IsConstructOp(op)) {
8456 if (op == JSOp::SuperCall || op == JSOp::SpreadSuperCall) {
8457 if (!emitNewTarget(callNode)) {
8458 // [stack] CALLEE THIS ARGS.. NEW.TARGET
8459 return false;
8461 } else {
8462 // Repush the callee as new.target
8463 uint32_t effectiveArgc = isSpread ? 1 : argc;
8464 if (!emitDupAt(effectiveArgc + 1)) {
8465 // [stack] CALLEE THIS ARGS.. CALLEE
8466 return false;
8471 ParseNode* coordNode = getCoordNode(callNode, calleeNode, op, argsList);
8473 if (!cone.emitEnd(argc, coordNode->pn_pos.begin)) {
8474 // [stack] RVAL
8475 return false;
8478 return true;
8481 // This list must be kept in the same order in several places:
8482 // - The binary operators in ParseNode.h ,
8483 // - the binary operators in TokenKind.h
8484 // - the precedence list in Parser.cpp
8485 static const JSOp ParseNodeKindToJSOp[] = {
8486 // Some binary ops require special code generation (PrivateIn);
8487 // these should not use BinaryOpParseNodeKindToJSOp. This table fills those
8488 // slots with Nops to make the rest of the table lookup work.
8489 JSOp::Coalesce, JSOp::Or, JSOp::And, JSOp::BitOr, JSOp::BitXor,
8490 JSOp::BitAnd, JSOp::StrictEq, JSOp::Eq, JSOp::StrictNe, JSOp::Ne,
8491 JSOp::Lt, JSOp::Le, JSOp::Gt, JSOp::Ge, JSOp::Instanceof,
8492 JSOp::In, JSOp::Nop, JSOp::Lsh, JSOp::Rsh, JSOp::Ursh,
8493 JSOp::Add, JSOp::Sub, JSOp::Mul, JSOp::Div, JSOp::Mod,
8494 JSOp::Pow};
8496 static inline JSOp BinaryOpParseNodeKindToJSOp(ParseNodeKind pnk) {
8497 MOZ_ASSERT(pnk >= ParseNodeKind::BinOpFirst);
8498 MOZ_ASSERT(pnk <= ParseNodeKind::BinOpLast);
8499 int parseNodeFirst = size_t(ParseNodeKind::BinOpFirst);
8500 #ifdef DEBUG
8501 int jsopArraySize = std::size(ParseNodeKindToJSOp);
8502 int parseNodeKindListSize =
8503 size_t(ParseNodeKind::BinOpLast) - parseNodeFirst + 1;
8504 MOZ_ASSERT(jsopArraySize == parseNodeKindListSize);
8505 // Ensure we don't use this to find an op for a parse node
8506 // requiring special emission rules.
8507 MOZ_ASSERT(ParseNodeKindToJSOp[size_t(pnk) - parseNodeFirst] != JSOp::Nop);
8508 #endif
8509 return ParseNodeKindToJSOp[size_t(pnk) - parseNodeFirst];
8512 bool BytecodeEmitter::emitRightAssociative(ListNode* node) {
8513 // ** is the only right-associative operator.
8514 MOZ_ASSERT(node->isKind(ParseNodeKind::PowExpr));
8516 // Right-associative operator chain.
8517 for (ParseNode* subexpr : node->contents()) {
8518 if (!updateSourceCoordNotesIfNonLiteral(subexpr)) {
8519 return false;
8521 if (!emitTree(subexpr)) {
8522 return false;
8525 for (uint32_t i = 0; i < node->count() - 1; i++) {
8526 if (!emit1(JSOp::Pow)) {
8527 return false;
8530 return true;
8533 bool BytecodeEmitter::emitLeftAssociative(ListNode* node) {
8534 // Left-associative operator chain.
8535 if (!emitTree(node->head())) {
8536 return false;
8538 JSOp op = BinaryOpParseNodeKindToJSOp(node->getKind());
8539 ParseNode* nextExpr = node->head()->pn_next;
8540 do {
8541 if (!updateSourceCoordNotesIfNonLiteral(nextExpr)) {
8542 return false;
8544 if (!emitTree(nextExpr)) {
8545 return false;
8547 if (!emit1(op)) {
8548 return false;
8550 } while ((nextExpr = nextExpr->pn_next));
8551 return true;
8554 bool BytecodeEmitter::emitPrivateInExpr(ListNode* node) {
8555 MOZ_ASSERT(node->head()->isKind(ParseNodeKind::PrivateName));
8557 NameNode& privateNameNode = node->head()->as<NameNode>();
8558 TaggedParserAtomIndex privateName = privateNameNode.name();
8560 PrivateOpEmitter xoe(this, PrivateOpEmitter::Kind::ErgonomicBrandCheck,
8561 privateName);
8563 ParseNode* valueNode = node->head()->pn_next;
8564 MOZ_ASSERT(valueNode->pn_next == nullptr);
8566 if (!emitTree(valueNode)) {
8567 // [stack] OBJ
8568 return false;
8571 if (!xoe.emitReference()) {
8572 // [stack] OBJ BRAND if private method
8573 // [stack] OBJ NAME if private field or accessor.
8574 return false;
8577 if (!xoe.emitBrandCheck()) {
8578 // [stack] OBJ BRAND BOOL if private method
8579 // [stack] OBJ NAME BOOL if private field or accessor.
8580 return false;
8583 if (!emitUnpickN(2)) {
8584 // [stack] BOOL OBJ BRAND if private method
8585 // [stack] BOOL OBJ NAME if private field or accessor.
8586 return false;
8589 if (!emitPopN(2)) {
8590 // [stack] BOOL
8591 return false;
8594 return true;
8598 * Special `emitTree` for Optional Chaining case.
8599 * Examples of this are `emitOptionalChain`, `emitDeleteOptionalChain` and
8600 * `emitCalleeAndThisForOptionalChain`.
8602 bool BytecodeEmitter::emitOptionalTree(
8603 ParseNode* pn, OptionalEmitter& oe,
8604 ValueUsage valueUsage /* = ValueUsage::WantValue */) {
8605 AutoCheckRecursionLimit recursion(fc);
8606 if (!recursion.check(fc)) {
8607 return false;
8609 ParseNodeKind kind = pn->getKind();
8610 switch (kind) {
8611 case ParseNodeKind::OptionalDotExpr: {
8612 OptionalPropertyAccess* prop = &pn->as<OptionalPropertyAccess>();
8613 bool isSuper = false;
8614 PropOpEmitter poe(this, PropOpEmitter::Kind::Get,
8615 PropOpEmitter::ObjKind::Other);
8616 if (!emitOptionalDotExpression(prop, poe, isSuper, oe)) {
8617 return false;
8619 break;
8621 case ParseNodeKind::DotExpr: {
8622 PropertyAccess* prop = &pn->as<PropertyAccess>();
8623 bool isSuper = prop->isSuper();
8624 PropOpEmitter poe(this, PropOpEmitter::Kind::Get,
8625 isSuper ? PropOpEmitter::ObjKind::Super
8626 : PropOpEmitter::ObjKind::Other);
8627 if (!emitOptionalDotExpression(prop, poe, isSuper, oe)) {
8628 return false;
8630 break;
8633 case ParseNodeKind::OptionalElemExpr: {
8634 OptionalPropertyByValue* elem = &pn->as<OptionalPropertyByValue>();
8635 bool isSuper = false;
8636 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
8637 ElemOpEmitter eoe(this, ElemOpEmitter::Kind::Get,
8638 ElemOpEmitter::ObjKind::Other);
8640 if (!emitOptionalElemExpression(elem, eoe, isSuper, oe)) {
8641 return false;
8643 break;
8645 case ParseNodeKind::ElemExpr: {
8646 PropertyByValue* elem = &pn->as<PropertyByValue>();
8647 bool isSuper = elem->isSuper();
8648 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
8649 ElemOpEmitter eoe(this, ElemOpEmitter::Kind::Get,
8650 isSuper ? ElemOpEmitter::ObjKind::Super
8651 : ElemOpEmitter::ObjKind::Other);
8653 if (!emitOptionalElemExpression(elem, eoe, isSuper, oe)) {
8654 return false;
8656 break;
8658 case ParseNodeKind::PrivateMemberExpr:
8659 case ParseNodeKind::OptionalPrivateMemberExpr: {
8660 PrivateMemberAccessBase* privateExpr = &pn->as<PrivateMemberAccessBase>();
8661 PrivateOpEmitter xoe(this, PrivateOpEmitter::Kind::Get,
8662 privateExpr->privateName().name());
8663 if (!emitOptionalPrivateExpression(privateExpr, xoe, oe)) {
8664 return false;
8666 break;
8668 case ParseNodeKind::CallExpr:
8669 case ParseNodeKind::OptionalCallExpr:
8670 if (!emitOptionalCall(&pn->as<CallNode>(), oe, valueUsage)) {
8671 return false;
8673 break;
8674 // List of accepted ParseNodeKinds that might appear only at the beginning
8675 // of an Optional Chain.
8676 // For example, a taggedTemplateExpr node might occur if we have
8677 // `test`?.b, with `test` as the taggedTemplateExpr ParseNode.
8678 default:
8679 #ifdef DEBUG
8680 // https://tc39.es/ecma262/#sec-primary-expression
8681 bool isPrimaryExpression =
8682 kind == ParseNodeKind::ThisExpr || kind == ParseNodeKind::Name ||
8683 kind == ParseNodeKind::PrivateName ||
8684 kind == ParseNodeKind::NullExpr || kind == ParseNodeKind::TrueExpr ||
8685 kind == ParseNodeKind::FalseExpr ||
8686 kind == ParseNodeKind::NumberExpr ||
8687 kind == ParseNodeKind::BigIntExpr ||
8688 kind == ParseNodeKind::StringExpr ||
8689 kind == ParseNodeKind::ArrayExpr ||
8690 kind == ParseNodeKind::ObjectExpr ||
8691 kind == ParseNodeKind::Function || kind == ParseNodeKind::ClassDecl ||
8692 kind == ParseNodeKind::RegExpExpr ||
8693 kind == ParseNodeKind::TemplateStringExpr ||
8694 kind == ParseNodeKind::TemplateStringListExpr ||
8695 kind == ParseNodeKind::RawUndefinedExpr || pn->isInParens();
8697 // https://tc39.es/ecma262/#sec-left-hand-side-expressions
8698 bool isMemberExpression = isPrimaryExpression ||
8699 kind == ParseNodeKind::TaggedTemplateExpr ||
8700 kind == ParseNodeKind::NewExpr ||
8701 kind == ParseNodeKind::NewTargetExpr ||
8702 kind == ParseNodeKind::ImportMetaExpr;
8704 bool isCallExpression = kind == ParseNodeKind::SetThis ||
8705 kind == ParseNodeKind::CallImportExpr;
8707 MOZ_ASSERT(isMemberExpression || isCallExpression,
8708 "Unknown ParseNodeKind for OptionalChain");
8709 #endif
8710 return emitTree(pn);
8712 return true;
8715 // Handle the case of a call made on a OptionalChainParseNode.
8716 // For example `(a?.b)()` and `(a?.b)?.()`.
8717 bool BytecodeEmitter::emitCalleeAndThisForOptionalChain(
8718 UnaryNode* optionalChain, CallNode* callNode, CallOrNewEmitter& cone) {
8719 ParseNode* calleeNode = optionalChain->kid();
8721 // Create a new OptionalEmitter, in order to emit the right bytecode
8722 // in isolation.
8723 OptionalEmitter oe(this, bytecodeSection().stackDepth());
8725 if (!emitOptionalCalleeAndThis(calleeNode, callNode, cone, oe)) {
8726 // [stack] CALLEE THIS
8727 return false;
8730 // complete the jump if necessary. This will set both the "this" value
8731 // and the "callee" value to undefined, if the callee is undefined. It
8732 // does not matter much what the this value is, the function call will
8733 // fail if it is not optional, and be set to undefined otherwise.
8734 if (!oe.emitOptionalJumpTarget(JSOp::Undefined,
8735 OptionalEmitter::Kind::Reference)) {
8736 // [stack] # If shortcircuit
8737 // [stack] UNDEFINED UNDEFINED
8738 // [stack] # otherwise
8739 // [stack] CALLEE THIS
8740 return false;
8742 return true;
8745 bool BytecodeEmitter::emitOptionalChain(UnaryNode* optionalChain,
8746 ValueUsage valueUsage) {
8747 ParseNode* expr = optionalChain->kid();
8749 OptionalEmitter oe(this, bytecodeSection().stackDepth());
8751 if (!emitOptionalTree(expr, oe, valueUsage)) {
8752 // [stack] VAL
8753 return false;
8756 if (!oe.emitOptionalJumpTarget(JSOp::Undefined)) {
8757 // [stack] # If shortcircuit
8758 // [stack] UNDEFINED
8759 // [stack] # otherwise
8760 // [stack] VAL
8761 return false;
8764 return true;
8767 bool BytecodeEmitter::emitOptionalDotExpression(PropertyAccessBase* prop,
8768 PropOpEmitter& poe,
8769 bool isSuper,
8770 OptionalEmitter& oe) {
8771 if (!poe.prepareForObj()) {
8772 // [stack]
8773 return false;
8776 if (isSuper) {
8777 UnaryNode* base = &prop->expression().as<UnaryNode>();
8778 if (!emitGetThisForSuperBase(base)) {
8779 // [stack] OBJ
8780 return false;
8782 } else {
8783 if (!emitOptionalTree(&prop->expression(), oe)) {
8784 // [stack] OBJ
8785 return false;
8789 if (prop->isKind(ParseNodeKind::OptionalDotExpr)) {
8790 MOZ_ASSERT(!isSuper);
8791 if (!oe.emitJumpShortCircuit()) {
8792 // [stack] # if Jump
8793 // [stack] UNDEFINED-OR-NULL
8794 // [stack] # otherwise
8795 // [stack] OBJ
8796 return false;
8800 if (!poe.emitGet(prop->key().atom())) {
8801 // [stack] PROP
8802 return false;
8805 return true;
8808 bool BytecodeEmitter::emitOptionalElemExpression(PropertyByValueBase* elem,
8809 ElemOpEmitter& eoe,
8810 bool isSuper,
8811 OptionalEmitter& oe) {
8812 if (!eoe.prepareForObj()) {
8813 // [stack]
8814 return false;
8817 if (isSuper) {
8818 UnaryNode* base = &elem->expression().as<UnaryNode>();
8819 if (!emitGetThisForSuperBase(base)) {
8820 // [stack] OBJ
8821 return false;
8823 } else {
8824 if (!emitOptionalTree(&elem->expression(), oe)) {
8825 // [stack] OBJ
8826 return false;
8830 if (elem->isKind(ParseNodeKind::OptionalElemExpr)) {
8831 MOZ_ASSERT(!isSuper);
8832 if (!oe.emitJumpShortCircuit()) {
8833 // [stack] # if Jump
8834 // [stack] UNDEFINED-OR-NULL
8835 // [stack] # otherwise
8836 // [stack] OBJ
8837 return false;
8841 if (!eoe.prepareForKey()) {
8842 // [stack] OBJ? OBJ
8843 return false;
8846 if (!emitTree(&elem->key())) {
8847 // [stack] OBJ? OBJ KEY
8848 return false;
8851 if (!eoe.emitGet()) {
8852 // [stack] ELEM
8853 return false;
8856 return true;
8859 bool BytecodeEmitter::emitOptionalPrivateExpression(
8860 PrivateMemberAccessBase* privateExpr, PrivateOpEmitter& xoe,
8861 OptionalEmitter& oe) {
8862 if (!emitOptionalTree(&privateExpr->expression(), oe)) {
8863 // [stack] OBJ
8864 return false;
8867 if (privateExpr->isKind(ParseNodeKind::OptionalPrivateMemberExpr)) {
8868 if (!oe.emitJumpShortCircuit()) {
8869 // [stack] # if Jump
8870 // [stack] UNDEFINED-OR-NULL
8871 // [stack] # otherwise
8872 // [stack] OBJ
8873 return false;
8877 if (!xoe.emitReference()) {
8878 // [stack] OBJ NAME
8879 return false;
8881 if (!xoe.emitGet()) {
8882 // [stack] CALLEE THIS # if call
8883 // [stack] VALUE # otherwise
8884 return false;
8887 return true;
8890 bool BytecodeEmitter::emitShortCircuit(ListNode* node, ValueUsage valueUsage) {
8891 MOZ_ASSERT(node->isKind(ParseNodeKind::OrExpr) ||
8892 node->isKind(ParseNodeKind::CoalesceExpr) ||
8893 node->isKind(ParseNodeKind::AndExpr));
8896 * JSOp::Or converts the operand on the stack to boolean, leaves the original
8897 * value on the stack and jumps if true; otherwise it falls into the next
8898 * bytecode, which pops the left operand and then evaluates the right operand.
8899 * The jump goes around the right operand evaluation.
8901 * JSOp::And converts the operand on the stack to boolean and jumps if false;
8902 * otherwise it falls into the right operand's bytecode.
8905 TDZCheckCache tdzCache(this);
8907 JSOp op;
8908 switch (node->getKind()) {
8909 case ParseNodeKind::OrExpr:
8910 op = JSOp::Or;
8911 break;
8912 case ParseNodeKind::CoalesceExpr:
8913 op = JSOp::Coalesce;
8914 break;
8915 case ParseNodeKind::AndExpr:
8916 op = JSOp::And;
8917 break;
8918 default:
8919 MOZ_CRASH("Unexpected ParseNodeKind");
8922 JumpList jump;
8924 // Left-associative operator chain: avoid too much recursion.
8926 // Emit all nodes but the last.
8927 for (ParseNode* expr : node->contentsTo(node->last())) {
8928 if (!emitTree(expr)) {
8929 return false;
8931 if (!emitJump(op, &jump)) {
8932 return false;
8934 if (!emit1(JSOp::Pop)) {
8935 return false;
8939 // Emit the last node
8940 if (!emitTree(node->last(), valueUsage)) {
8941 return false;
8944 if (!emitJumpTargetAndPatch(jump)) {
8945 return false;
8947 return true;
8950 bool BytecodeEmitter::emitSequenceExpr(ListNode* node, ValueUsage valueUsage) {
8951 for (ParseNode* child : node->contentsTo(node->last())) {
8952 if (!updateSourceCoordNotes(child->pn_pos.begin)) {
8953 return false;
8955 if (!emitTree(child, ValueUsage::IgnoreValue)) {
8956 return false;
8958 if (!emit1(JSOp::Pop)) {
8959 return false;
8963 ParseNode* child = node->last();
8964 if (!updateSourceCoordNotes(child->pn_pos.begin)) {
8965 return false;
8967 if (!emitTree(child, valueUsage)) {
8968 return false;
8970 return true;
8973 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
8974 // the comment on emitSwitch.
8975 MOZ_NEVER_INLINE bool BytecodeEmitter::emitIncOrDec(UnaryNode* incDec,
8976 ValueUsage valueUsage) {
8977 switch (incDec->kid()->getKind()) {
8978 case ParseNodeKind::DotExpr:
8979 return emitPropIncDec(incDec, valueUsage);
8980 case ParseNodeKind::ElemExpr:
8981 return emitElemIncDec(incDec, valueUsage);
8982 case ParseNodeKind::PrivateMemberExpr:
8983 return emitPrivateIncDec(incDec, valueUsage);
8984 case ParseNodeKind::CallExpr:
8985 return emitCallIncDec(incDec);
8986 default:
8987 return emitNameIncDec(incDec, valueUsage);
8991 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
8992 // the comment on emitSwitch.
8993 MOZ_NEVER_INLINE bool BytecodeEmitter::emitLabeledStatement(
8994 const LabeledStatement* labeledStmt) {
8995 auto name = labeledStmt->label();
8996 LabelEmitter label(this);
8998 label.emitLabel(name);
9000 if (!emitTree(labeledStmt->statement())) {
9001 return false;
9003 if (!label.emitEnd()) {
9004 return false;
9007 return true;
9010 bool BytecodeEmitter::emitConditionalExpression(
9011 ConditionalExpression& conditional, ValueUsage valueUsage) {
9012 CondEmitter cond(this);
9013 if (!cond.emitCond()) {
9014 return false;
9017 ParseNode* conditionNode = &conditional.condition();
9018 auto conditionKind = IfEmitter::ConditionKind::Positive;
9019 if (conditionNode->isKind(ParseNodeKind::NotExpr)) {
9020 conditionNode = conditionNode->as<UnaryNode>().kid();
9021 conditionKind = IfEmitter::ConditionKind::Negative;
9024 // NOTE: NotExpr of conditionNode may be unwrapped, and in that case the
9025 // negation is handled by conditionKind.
9026 if (!emitTree(conditionNode)) {
9027 return false;
9030 if (!cond.emitThenElse(conditionKind)) {
9031 return false;
9034 if (!emitTree(&conditional.thenExpression(), valueUsage)) {
9035 return false;
9038 if (!cond.emitElse()) {
9039 return false;
9042 if (!emitTree(&conditional.elseExpression(), valueUsage)) {
9043 return false;
9046 if (!cond.emitEnd()) {
9047 return false;
9049 MOZ_ASSERT(cond.pushed() == 1);
9051 return true;
9054 // Check for an object-literal property list that can be handled by the
9055 // ObjLiteral writer. We ensure that for each `prop: value` pair, the key is a
9056 // constant name or numeric index, there is no accessor specified, and the value
9057 // can be encoded by an ObjLiteral instruction (constant number, string,
9058 // boolean, null/undefined).
9059 void BytecodeEmitter::isPropertyListObjLiteralCompatible(ListNode* obj,
9060 bool* withValues,
9061 bool* withoutValues) {
9062 bool keysOK = true;
9063 bool valuesOK = true;
9064 uint32_t propCount = 0;
9066 for (ParseNode* propdef : obj->contents()) {
9067 if (!propdef->is<BinaryNode>()) {
9068 keysOK = false;
9069 break;
9071 propCount++;
9073 BinaryNode* prop = &propdef->as<BinaryNode>();
9074 ParseNode* key = prop->left();
9075 ParseNode* value = prop->right();
9077 // Computed keys not OK (ObjLiteral data stores constant keys).
9078 if (key->isKind(ParseNodeKind::ComputedName)) {
9079 keysOK = false;
9080 break;
9083 // BigIntExprs should have been lowered to computed names at parse
9084 // time, and so should be excluded above.
9085 MOZ_ASSERT(!key->isKind(ParseNodeKind::BigIntExpr));
9087 // Numeric keys OK as long as they are integers and in range.
9088 if (key->isKind(ParseNodeKind::NumberExpr)) {
9089 double numValue = key->as<NumericLiteral>().value();
9090 int32_t i = 0;
9091 if (!NumberIsInt32(numValue, &i)) {
9092 keysOK = false;
9093 break;
9095 if (!ObjLiteralWriter::arrayIndexInRange(i)) {
9096 keysOK = false;
9097 break;
9101 MOZ_ASSERT(key->isKind(ParseNodeKind::ObjectPropertyName) ||
9102 key->isKind(ParseNodeKind::StringExpr) ||
9103 key->isKind(ParseNodeKind::NumberExpr));
9105 AccessorType accessorType =
9106 prop->is<PropertyDefinition>()
9107 ? prop->as<PropertyDefinition>().accessorType()
9108 : AccessorType::None;
9109 if (accessorType != AccessorType::None) {
9110 keysOK = false;
9111 break;
9114 if (!isRHSObjLiteralCompatible(value)) {
9115 valuesOK = false;
9119 if (propCount > SharedPropMap::MaxPropsForNonDictionary) {
9120 // JSOp::NewObject cannot accept dictionary-mode objects.
9121 keysOK = false;
9124 *withValues = keysOK && valuesOK;
9125 *withoutValues = keysOK;
9128 bool BytecodeEmitter::isArrayObjLiteralCompatible(ListNode* array) {
9129 for (ParseNode* elem : array->contents()) {
9130 if (elem->isKind(ParseNodeKind::Spread)) {
9131 return false;
9133 if (!isRHSObjLiteralCompatible(elem)) {
9134 return false;
9137 return true;
9140 bool BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe,
9141 PropListType type) {
9142 // [stack] CTOR? OBJ
9144 size_t curFieldKeyIndex = 0;
9145 size_t curStaticFieldKeyIndex = 0;
9146 for (ParseNode* propdef : obj->contents()) {
9147 if (propdef->is<ClassField>()) {
9148 MOZ_ASSERT(type == ClassBody);
9149 // Only handle computing field keys here: the .initializers lambda array
9150 // is created elsewhere.
9151 ClassField* field = &propdef->as<ClassField>();
9152 if (field->name().getKind() == ParseNodeKind::ComputedName) {
9153 auto fieldKeys =
9154 field->isStatic()
9155 ? TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_()
9156 : TaggedParserAtomIndex::WellKnown::dot_fieldKeys_();
9157 if (!emitGetName(fieldKeys)) {
9158 // [stack] CTOR OBJ ARRAY
9159 return false;
9162 ParseNode* nameExpr = field->name().as<UnaryNode>().kid();
9164 if (!emitTree(nameExpr, ValueUsage::WantValue)) {
9165 // [stack] CTOR OBJ ARRAY KEY
9166 return false;
9169 if (!emit1(JSOp::ToPropertyKey)) {
9170 // [stack] CTOR OBJ ARRAY KEY
9171 return false;
9174 size_t fieldKeysIndex;
9175 if (field->isStatic()) {
9176 fieldKeysIndex = curStaticFieldKeyIndex++;
9177 } else {
9178 fieldKeysIndex = curFieldKeyIndex++;
9181 if (!emitUint32Operand(JSOp::InitElemArray, fieldKeysIndex)) {
9182 // [stack] CTOR OBJ ARRAY
9183 return false;
9186 if (!emit1(JSOp::Pop)) {
9187 // [stack] CTOR OBJ
9188 return false;
9191 continue;
9194 if (propdef->isKind(ParseNodeKind::StaticClassBlock)) {
9195 // Static class blocks are emitted as part of
9196 // emitCreateMemberInitializers.
9197 continue;
9200 if (propdef->is<LexicalScopeNode>()) {
9201 // Constructors are sometimes wrapped in LexicalScopeNodes. As we
9202 // already handled emitting the constructor, skip it.
9203 MOZ_ASSERT(
9204 propdef->as<LexicalScopeNode>().scopeBody()->is<ClassMethod>());
9205 continue;
9208 // Handle __proto__: v specially because *only* this form, and no other
9209 // involving "__proto__", performs [[Prototype]] mutation.
9210 if (propdef->isKind(ParseNodeKind::MutateProto)) {
9211 // [stack] OBJ
9212 MOZ_ASSERT(type == ObjectLiteral);
9213 if (!pe.prepareForProtoValue(propdef->pn_pos.begin)) {
9214 // [stack] OBJ
9215 return false;
9217 if (!emitTree(propdef->as<UnaryNode>().kid())) {
9218 // [stack] OBJ PROTO
9219 return false;
9221 if (!pe.emitMutateProto()) {
9222 // [stack] OBJ
9223 return false;
9225 continue;
9228 if (propdef->isKind(ParseNodeKind::Spread)) {
9229 MOZ_ASSERT(type == ObjectLiteral);
9230 // [stack] OBJ
9231 if (!pe.prepareForSpreadOperand(propdef->pn_pos.begin)) {
9232 // [stack] OBJ OBJ
9233 return false;
9235 if (!emitTree(propdef->as<UnaryNode>().kid())) {
9236 // [stack] OBJ OBJ VAL
9237 return false;
9239 if (!pe.emitSpread()) {
9240 // [stack] OBJ
9241 return false;
9243 continue;
9246 BinaryNode* prop = &propdef->as<BinaryNode>();
9248 ParseNode* key = prop->left();
9249 AccessorType accessorType;
9250 if (prop->is<ClassMethod>()) {
9251 ClassMethod& method = prop->as<ClassMethod>();
9252 accessorType = method.accessorType();
9254 if (!method.isStatic() && key->isKind(ParseNodeKind::PrivateName) &&
9255 accessorType != AccessorType::None) {
9256 // Private non-static accessors are stamped onto instances from
9257 // initializers; see emitCreateMemberInitializers.
9258 continue;
9260 } else if (prop->is<PropertyDefinition>()) {
9261 accessorType = prop->as<PropertyDefinition>().accessorType();
9262 } else {
9263 accessorType = AccessorType::None;
9266 auto emitValue = [this, &key, &prop, accessorType, &pe]() {
9267 // [stack] CTOR? OBJ CTOR? KEY?
9269 ParseNode* propVal = prop->right();
9270 if (propVal->isDirectRHSAnonFunction()) {
9271 // The following branches except for the last `else` clause emit the
9272 // cases handled in NameResolver::resolveFun (see NameFunctions.cpp)
9273 if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
9274 key->isKind(ParseNodeKind::PrivateName) ||
9275 key->isKind(ParseNodeKind::StringExpr)) {
9276 auto keyAtom = key->as<NameNode>().atom();
9277 if (!emitAnonymousFunctionWithName(propVal, keyAtom)) {
9278 // [stack] CTOR? OBJ CTOR? VAL
9279 return false;
9281 } else if (key->isKind(ParseNodeKind::NumberExpr)) {
9282 MOZ_ASSERT(accessorType == AccessorType::None);
9284 auto keyAtom = key->as<NumericLiteral>().toAtom(fc, parserAtoms());
9285 if (!keyAtom) {
9286 return false;
9288 if (!emitAnonymousFunctionWithName(propVal, keyAtom)) {
9289 // [stack] CTOR? OBJ CTOR? KEY VAL
9290 return false;
9292 } else if (key->isKind(ParseNodeKind::ComputedName) &&
9293 (key->as<UnaryNode>().kid()->isKind(
9294 ParseNodeKind::NumberExpr) ||
9295 key->as<UnaryNode>().kid()->isKind(
9296 ParseNodeKind::StringExpr)) &&
9297 accessorType == AccessorType::None) {
9298 ParseNode* keyKid = key->as<UnaryNode>().kid();
9299 if (keyKid->isKind(ParseNodeKind::NumberExpr)) {
9300 auto keyAtom =
9301 keyKid->as<NumericLiteral>().toAtom(fc, parserAtoms());
9302 if (!keyAtom) {
9303 return false;
9305 if (!emitAnonymousFunctionWithName(propVal, keyAtom)) {
9306 // [stack] CTOR? OBJ CTOR? KEY VAL
9307 return false;
9309 } else {
9310 MOZ_ASSERT(keyKid->isKind(ParseNodeKind::StringExpr));
9311 auto keyAtom = keyKid->as<NameNode>().atom();
9312 if (!emitAnonymousFunctionWithName(propVal, keyAtom)) {
9313 // [stack] CTOR? OBJ CTOR? KEY VAL
9314 return false;
9317 } else {
9318 // Either a proper computed property name or a synthetic computed
9319 // property name for BigInt keys.
9320 MOZ_ASSERT(key->isKind(ParseNodeKind::ComputedName));
9322 FunctionPrefixKind prefix =
9323 accessorType == AccessorType::None ? FunctionPrefixKind::None
9324 : accessorType == AccessorType::Getter ? FunctionPrefixKind::Get
9325 : FunctionPrefixKind::Set;
9327 if (!emitAnonymousFunctionWithComputedName(propVal, prefix)) {
9328 // [stack] CTOR? OBJ CTOR? KEY VAL
9329 return false;
9332 } else {
9333 if (!emitTree(propVal)) {
9334 // [stack] CTOR? OBJ CTOR? KEY? VAL
9335 return false;
9339 if (propVal->is<FunctionNode>() &&
9340 propVal->as<FunctionNode>().funbox()->needsHomeObject()) {
9341 if (!pe.emitInitHomeObject()) {
9342 // [stack] CTOR? OBJ CTOR? KEY? FUN
9343 return false;
9347 #ifdef ENABLE_DECORATORS
9348 if (prop->is<ClassMethod>()) {
9349 ClassMethod& method = prop->as<ClassMethod>();
9350 if (method.decorators() && !method.decorators()->empty()) {
9351 DecoratorEmitter::Kind kind;
9352 switch (method.accessorType()) {
9353 case AccessorType::Getter:
9354 kind = DecoratorEmitter::Getter;
9355 break;
9356 case AccessorType::Setter:
9357 kind = DecoratorEmitter::Setter;
9358 break;
9359 case AccessorType::None:
9360 kind = DecoratorEmitter::Method;
9361 break;
9364 // The decorators are applied to the current value on the stack,
9365 // possibly replacing it.
9366 DecoratorEmitter de(this);
9367 if (!de.emitApplyDecoratorsToElementDefinition(
9368 kind, key, method.decorators(), method.isStatic())) {
9369 // [stack] CTOR? OBJ CTOR? KEY? VAL
9370 return false;
9374 #endif
9376 return true;
9379 PropertyEmitter::Kind kind =
9380 (type == ClassBody && propdef->as<ClassMethod>().isStatic())
9381 ? PropertyEmitter::Kind::Static
9382 : PropertyEmitter::Kind::Prototype;
9383 if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
9384 key->isKind(ParseNodeKind::StringExpr)) {
9385 // [stack] CTOR? OBJ
9387 auto keyAtom = key->as<NameNode>().atom();
9389 // emitClass took care of constructor already.
9390 if (type == ClassBody &&
9391 keyAtom == TaggedParserAtomIndex::WellKnown::constructor() &&
9392 !propdef->as<ClassMethod>().isStatic()) {
9393 continue;
9396 if (!pe.prepareForPropValue(propdef->pn_pos.begin, kind)) {
9397 // [stack] CTOR? OBJ CTOR?
9398 return false;
9401 if (!emitValue()) {
9402 // [stack] CTOR? OBJ CTOR? VAL
9403 return false;
9406 if (!pe.emitInit(accessorType, keyAtom)) {
9407 // [stack] CTOR? OBJ
9408 return false;
9411 continue;
9414 if (key->isKind(ParseNodeKind::NumberExpr)) {
9415 // [stack] CTOR? OBJ
9416 if (!pe.prepareForIndexPropKey(propdef->pn_pos.begin, kind)) {
9417 // [stack] CTOR? OBJ CTOR?
9418 return false;
9420 if (!emitNumberOp(key->as<NumericLiteral>().value())) {
9421 // [stack] CTOR? OBJ CTOR? KEY
9422 return false;
9424 if (!pe.prepareForIndexPropValue()) {
9425 // [stack] CTOR? OBJ CTOR? KEY
9426 return false;
9428 if (!emitValue()) {
9429 // [stack] CTOR? OBJ CTOR? KEY VAL
9430 return false;
9433 if (!pe.emitInitIndexOrComputed(accessorType)) {
9434 // [stack] CTOR? OBJ
9435 return false;
9438 continue;
9441 if (key->isKind(ParseNodeKind::ComputedName)) {
9442 // Either a proper computed property name or a synthetic computed property
9443 // name for BigInt keys.
9445 // [stack] CTOR? OBJ
9447 if (!pe.prepareForComputedPropKey(propdef->pn_pos.begin, kind)) {
9448 // [stack] CTOR? OBJ CTOR?
9449 return false;
9451 if (!emitTree(key->as<UnaryNode>().kid())) {
9452 // [stack] CTOR? OBJ CTOR? KEY
9453 return false;
9455 if (!pe.prepareForComputedPropValue()) {
9456 // [stack] CTOR? OBJ CTOR? KEY
9457 return false;
9459 if (!emitValue()) {
9460 // [stack] CTOR? OBJ CTOR? KEY VAL
9461 return false;
9464 if (!pe.emitInitIndexOrComputed(accessorType)) {
9465 // [stack] CTOR? OBJ
9466 return false;
9469 continue;
9472 MOZ_ASSERT(key->isKind(ParseNodeKind::PrivateName));
9473 MOZ_ASSERT(type == ClassBody);
9475 auto* privateName = &key->as<NameNode>();
9477 if (kind == PropertyEmitter::Kind::Prototype) {
9478 MOZ_ASSERT(accessorType == AccessorType::None);
9479 if (!pe.prepareForPrivateMethod()) {
9480 // [stack] CTOR OBJ
9481 return false;
9483 NameOpEmitter noe(this, privateName->atom(),
9484 NameOpEmitter::Kind::SimpleAssignment);
9486 // Ensure the NameOp emitter doesn't push an environment onto the stack,
9487 // because that would change the stack location of the home object.
9488 MOZ_ASSERT(noe.loc().kind() == NameLocation::Kind::FrameSlot ||
9489 noe.loc().kind() == NameLocation::Kind::EnvironmentCoordinate);
9491 if (!noe.prepareForRhs()) {
9492 // [stack] CTOR OBJ
9493 return false;
9495 if (!emitValue()) {
9496 // [stack] CTOR OBJ METHOD
9497 return false;
9499 if (!noe.emitAssignment()) {
9500 // [stack] CTOR OBJ METHOD
9501 return false;
9503 if (!emit1(JSOp::Pop)) {
9504 // [stack] CTOR OBJ
9505 return false;
9507 if (!pe.skipInit()) {
9508 // [stack] CTOR OBJ
9509 return false;
9511 continue;
9514 MOZ_ASSERT(kind == PropertyEmitter::Kind::Static);
9516 // [stack] CTOR OBJ
9518 if (!pe.prepareForPrivateStaticMethod(propdef->pn_pos.begin)) {
9519 // [stack] CTOR OBJ CTOR
9520 return false;
9522 if (!emitGetPrivateName(privateName)) {
9523 // [stack] CTOR OBJ CTOR KEY
9524 return false;
9526 if (!emitValue()) {
9527 // [stack] CTOR OBJ CTOR KEY VAL
9528 return false;
9531 if (!pe.emitPrivateStaticMethod(accessorType)) {
9532 // [stack] CTOR OBJ
9533 return false;
9536 if (privateName->privateNameKind() == PrivateNameKind::Setter) {
9537 if (!emitDupAt(1)) {
9538 // [stack] CTOR OBJ CTOR
9539 return false;
9541 if (!emitGetPrivateName(privateName)) {
9542 // [stack] CTOR OBJ CTOR NAME
9543 return false;
9545 if (!emitAtomOp(JSOp::GetIntrinsic,
9546 TaggedParserAtomIndex::WellKnown::NoPrivateGetter())) {
9547 // [stack] CTOR OBJ CTOR NAME FUN
9548 return false;
9550 if (!emit1(JSOp::InitHiddenElemGetter)) {
9551 // [stack] CTOR OBJ CTOR
9552 return false;
9554 if (!emit1(JSOp::Pop)) {
9555 // [stack] CTOR OBJ
9556 return false;
9561 return true;
9564 bool BytecodeEmitter::emitPropertyListObjLiteral(ListNode* obj, JSOp op,
9565 bool useObjLiteralValues) {
9566 ObjLiteralWriter writer;
9568 #ifdef DEBUG
9569 // In self-hosted JS, we check duplication only on debug build.
9570 mozilla::Maybe<mozilla::HashSet<frontend::TaggedParserAtomIndex,
9571 frontend::TaggedParserAtomIndexHasher>>
9572 selfHostedPropNames;
9573 if (emitterMode == BytecodeEmitter::SelfHosting) {
9574 selfHostedPropNames.emplace();
9576 #endif
9578 if (op == JSOp::Object) {
9579 writer.beginObject(op);
9580 } else {
9581 MOZ_ASSERT(op == JSOp::NewObject);
9582 writer.beginShape(op);
9585 for (ParseNode* propdef : obj->contents()) {
9586 BinaryNode* prop = &propdef->as<BinaryNode>();
9587 ParseNode* key = prop->left();
9589 if (key->is<NameNode>()) {
9590 if (emitterMode == BytecodeEmitter::SelfHosting) {
9591 auto propName = key->as<NameNode>().atom();
9592 #ifdef DEBUG
9593 // Self-hosted JS shouldn't contain duplicate properties.
9594 auto p = selfHostedPropNames->lookupForAdd(propName);
9595 MOZ_ASSERT(!p);
9596 if (!selfHostedPropNames->add(p, propName)) {
9597 js::ReportOutOfMemory(fc);
9598 return false;
9600 #endif
9601 writer.setPropNameNoDuplicateCheck(parserAtoms(), propName);
9602 } else {
9603 if (!writer.setPropName(parserAtoms(), key->as<NameNode>().atom())) {
9604 return false;
9607 } else {
9608 double numValue = key->as<NumericLiteral>().value();
9609 int32_t i = 0;
9610 DebugOnly<bool> numIsInt =
9611 NumberIsInt32(numValue, &i); // checked previously.
9612 MOZ_ASSERT(numIsInt);
9613 MOZ_ASSERT(
9614 ObjLiteralWriter::arrayIndexInRange(i)); // checked previously.
9616 // Ignore indexed properties if we're not storing property values, and
9617 // rely on InitElem ops to define those. These properties will be either
9618 // dense elements (not possible to represent in the literal's shape) or
9619 // sparse elements (enumerated separately, so this doesn't affect property
9620 // iteration order).
9621 if (!useObjLiteralValues) {
9622 continue;
9625 writer.setPropIndex(i);
9628 if (useObjLiteralValues) {
9629 MOZ_ASSERT(op == JSOp::Object);
9630 ParseNode* value = prop->right();
9631 if (!emitObjLiteralValue(writer, value)) {
9632 return false;
9634 } else {
9635 if (!writer.propWithUndefinedValue(fc)) {
9636 return false;
9641 GCThingIndex index;
9642 if (!addObjLiteralData(writer, &index)) {
9643 return false;
9646 // JSOp::Object may only be used by (top-level) run-once scripts.
9647 MOZ_ASSERT_IF(op == JSOp::Object,
9648 sc->isTopLevelContext() && sc->treatAsRunOnce());
9650 if (!emitGCIndexOp(op, index)) {
9651 // [stack] OBJ
9652 return false;
9655 return true;
9658 bool BytecodeEmitter::emitDestructuringRestExclusionSetObjLiteral(
9659 ListNode* pattern) {
9660 // Note: if we want to squeeze out a little more performance, we could switch
9661 // to the `JSOp::Object` opcode, because the exclusion set object is never
9662 // exposed to the user, so it's safe to bake the object into the bytecode.
9663 constexpr JSOp op = JSOp::NewObject;
9665 ObjLiteralWriter writer;
9666 writer.beginShape(op);
9668 for (ParseNode* member : pattern->contents()) {
9669 if (member->isKind(ParseNodeKind::Spread)) {
9670 MOZ_ASSERT(!member->pn_next, "unexpected trailing element after spread");
9671 break;
9674 TaggedParserAtomIndex atom;
9675 if (member->isKind(ParseNodeKind::MutateProto)) {
9676 atom = TaggedParserAtomIndex::WellKnown::proto_();
9677 } else {
9678 ParseNode* key = member->as<BinaryNode>().left();
9679 atom = key->as<NameNode>().atom();
9682 if (!writer.setPropName(parserAtoms(), atom)) {
9683 return false;
9686 if (!writer.propWithUndefinedValue(fc)) {
9687 return false;
9691 GCThingIndex index;
9692 if (!addObjLiteralData(writer, &index)) {
9693 return false;
9696 if (!emitGCIndexOp(op, index)) {
9697 // [stack] OBJ
9698 return false;
9701 return true;
9704 bool BytecodeEmitter::emitObjLiteralArray(ListNode* array) {
9705 MOZ_ASSERT(checkSingletonContext());
9707 constexpr JSOp op = JSOp::Object;
9709 ObjLiteralWriter writer;
9710 writer.beginArray(op);
9712 writer.beginDenseArrayElements();
9713 for (ParseNode* elem : array->contents()) {
9714 if (!emitObjLiteralValue(writer, elem)) {
9715 return false;
9719 GCThingIndex index;
9720 if (!addObjLiteralData(writer, &index)) {
9721 return false;
9724 if (!emitGCIndexOp(op, index)) {
9725 // [stack] OBJ
9726 return false;
9729 return true;
9732 bool BytecodeEmitter::isRHSObjLiteralCompatible(ParseNode* value) {
9733 return value->isKind(ParseNodeKind::NumberExpr) ||
9734 value->isKind(ParseNodeKind::TrueExpr) ||
9735 value->isKind(ParseNodeKind::FalseExpr) ||
9736 value->isKind(ParseNodeKind::NullExpr) ||
9737 value->isKind(ParseNodeKind::RawUndefinedExpr) ||
9738 value->isKind(ParseNodeKind::StringExpr) ||
9739 value->isKind(ParseNodeKind::TemplateStringExpr);
9742 bool BytecodeEmitter::emitObjLiteralValue(ObjLiteralWriter& writer,
9743 ParseNode* value) {
9744 MOZ_ASSERT(isRHSObjLiteralCompatible(value));
9745 if (value->isKind(ParseNodeKind::NumberExpr)) {
9746 double numValue = value->as<NumericLiteral>().value();
9747 int32_t i = 0;
9748 js::Value v;
9749 if (NumberIsInt32(numValue, &i)) {
9750 v.setInt32(i);
9751 } else {
9752 v.setDouble(numValue);
9754 if (!writer.propWithConstNumericValue(fc, v)) {
9755 return false;
9757 } else if (value->isKind(ParseNodeKind::TrueExpr)) {
9758 if (!writer.propWithTrueValue(fc)) {
9759 return false;
9761 } else if (value->isKind(ParseNodeKind::FalseExpr)) {
9762 if (!writer.propWithFalseValue(fc)) {
9763 return false;
9765 } else if (value->isKind(ParseNodeKind::NullExpr)) {
9766 if (!writer.propWithNullValue(fc)) {
9767 return false;
9769 } else if (value->isKind(ParseNodeKind::RawUndefinedExpr)) {
9770 if (!writer.propWithUndefinedValue(fc)) {
9771 return false;
9773 } else if (value->isKind(ParseNodeKind::StringExpr) ||
9774 value->isKind(ParseNodeKind::TemplateStringExpr)) {
9775 if (!writer.propWithAtomValue(fc, parserAtoms(),
9776 value->as<NameNode>().atom())) {
9777 return false;
9779 } else {
9780 MOZ_CRASH("Unexpected parse node");
9782 return true;
9785 static bool NeedsPrivateBrand(ParseNode* member) {
9786 return member->is<ClassMethod>() &&
9787 member->as<ClassMethod>().name().isKind(ParseNodeKind::PrivateName) &&
9788 !member->as<ClassMethod>().isStatic();
9791 mozilla::Maybe<MemberInitializers> BytecodeEmitter::setupMemberInitializers(
9792 ListNode* classMembers, FieldPlacement placement) {
9793 bool isStatic = placement == FieldPlacement::Static;
9795 size_t numFields = 0;
9796 size_t numPrivateInitializers = 0;
9797 bool hasPrivateBrand = false;
9798 for (ParseNode* member : classMembers->contents()) {
9799 if (NeedsFieldInitializer(member, isStatic)) {
9800 numFields++;
9801 } else if (NeedsAccessorInitializer(member, isStatic)) {
9802 numPrivateInitializers++;
9803 hasPrivateBrand = true;
9804 } else if (NeedsPrivateBrand(member)) {
9805 hasPrivateBrand = true;
9809 // If there are more initializers than can be represented, return invalid.
9810 if (numFields + numPrivateInitializers >
9811 MemberInitializers::MaxInitializers) {
9812 return Nothing();
9814 return Some(
9815 MemberInitializers(hasPrivateBrand, numFields + numPrivateInitializers));
9818 // Purpose of .fieldKeys:
9819 // Computed field names (`["x"] = 2;`) must be ran at class-evaluation time,
9820 // not object construction time. The transformation to do so is roughly as
9821 // follows:
9823 // class C {
9824 // [keyExpr] = valueExpr;
9825 // }
9826 // -->
9827 // let .fieldKeys = [keyExpr];
9828 // let .initializers = [
9829 // () => {
9830 // this[.fieldKeys[0]] = valueExpr;
9831 // }
9832 // ];
9833 // class C {
9834 // constructor() {
9835 // .initializers[0]();
9836 // }
9837 // }
9839 // BytecodeEmitter::emitCreateFieldKeys does `let .fieldKeys = [...];`
9840 // BytecodeEmitter::emitPropertyList fills in the elements of the array.
9841 // See GeneralParser::fieldInitializer for the `this[.fieldKeys[0]]` part.
9842 bool BytecodeEmitter::emitCreateFieldKeys(ListNode* obj,
9843 FieldPlacement placement) {
9844 bool isStatic = placement == FieldPlacement::Static;
9845 auto isFieldWithComputedName = [isStatic](ParseNode* propdef) {
9846 return propdef->is<ClassField>() &&
9847 propdef->as<ClassField>().isStatic() == isStatic &&
9848 propdef->as<ClassField>().name().getKind() ==
9849 ParseNodeKind::ComputedName;
9852 size_t numFieldKeys = std::count_if(
9853 obj->contents().begin(), obj->contents().end(), isFieldWithComputedName);
9854 if (numFieldKeys == 0) {
9855 return true;
9858 auto fieldKeys =
9859 isStatic ? TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_()
9860 : TaggedParserAtomIndex::WellKnown::dot_fieldKeys_();
9861 NameOpEmitter noe(this, fieldKeys, NameOpEmitter::Kind::Initialize);
9862 if (!noe.prepareForRhs()) {
9863 return false;
9866 if (!emitUint32Operand(JSOp::NewArray, numFieldKeys)) {
9867 // [stack] ARRAY
9868 return false;
9871 if (!noe.emitAssignment()) {
9872 // [stack] ARRAY
9873 return false;
9876 if (!emit1(JSOp::Pop)) {
9877 // [stack]
9878 return false;
9881 return true;
9884 static bool HasInitializer(ParseNode* node, bool isStaticContext) {
9885 return (node->is<ClassField>() &&
9886 node->as<ClassField>().isStatic() == isStaticContext) ||
9887 (isStaticContext && node->is<StaticClassBlock>());
9890 static FunctionNode* GetInitializer(ParseNode* node, bool isStaticContext) {
9891 MOZ_ASSERT(HasInitializer(node, isStaticContext));
9892 MOZ_ASSERT_IF(!node->is<ClassField>(), isStaticContext);
9893 return node->is<ClassField>() ? node->as<ClassField>().initializer()
9894 : node->as<StaticClassBlock>().function();
9897 static bool IsPrivateInstanceAccessor(const ClassMethod* classMethod) {
9898 return !classMethod->isStatic() &&
9899 classMethod->name().isKind(ParseNodeKind::PrivateName) &&
9900 classMethod->accessorType() != AccessorType::None;
9903 bool BytecodeEmitter::emitCreateMemberInitializers(ClassEmitter& ce,
9904 ListNode* obj,
9905 FieldPlacement placement
9906 #ifdef ENABLE_DECORATORS
9908 bool hasHeritage
9909 #endif
9911 // FieldPlacement::Instance, hasHeritage == false
9912 // [stack] HOMEOBJ
9914 // FieldPlacement::Instance, hasHeritage == true
9915 // [stack] HOMEOBJ HERITAGE
9917 // FieldPlacement::Static
9918 // [stack] CTOR HOMEOBJ
9919 #ifdef ENABLE_DECORATORS
9920 MOZ_ASSERT_IF(placement == FieldPlacement::Static, !hasHeritage);
9921 #endif
9922 mozilla::Maybe<MemberInitializers> memberInitializers =
9923 setupMemberInitializers(obj, placement);
9924 if (!memberInitializers) {
9925 ReportAllocationOverflow(fc);
9926 return false;
9929 size_t numInitializers = memberInitializers->numMemberInitializers;
9930 if (numInitializers == 0) {
9931 return true;
9934 bool isStatic = placement == FieldPlacement::Static;
9935 if (!ce.prepareForMemberInitializers(numInitializers, isStatic)) {
9936 // [stack] HOMEOBJ HERITAGE? ARRAY
9937 // or:
9938 // [stack] CTOR HOMEOBJ ARRAY
9939 return false;
9942 // Private accessors could be used in the field initializers, so make sure
9943 // accessor initializers appear earlier in the .initializers array so they
9944 // run first. Static private methods are not initialized using initializers
9945 // (emitPropertyList emits bytecode to stamp them onto the constructor), so
9946 // skip this step if isStatic.
9947 if (!isStatic) {
9948 if (!emitPrivateMethodInitializers(ce, obj)) {
9949 return false;
9953 for (ParseNode* propdef : obj->contents()) {
9954 if (!HasInitializer(propdef, isStatic)) {
9955 continue;
9958 FunctionNode* initializer = GetInitializer(propdef, isStatic);
9960 if (!ce.prepareForMemberInitializer()) {
9961 return false;
9963 if (!emitTree(initializer)) {
9964 // [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA
9965 // or:
9966 // [stack] CTOR HOMEOBJ ARRAY LAMBDA
9967 return false;
9969 if (initializer->funbox()->needsHomeObject()) {
9970 MOZ_ASSERT(initializer->funbox()->allowSuperProperty());
9971 if (!ce.emitMemberInitializerHomeObject(isStatic)) {
9972 // [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA
9973 // or:
9974 // [stack] CTOR HOMEOBJ ARRAY LAMBDA
9975 return false;
9978 if (!ce.emitStoreMemberInitializer()) {
9979 // [stack] HOMEOBJ HERITAGE? ARRAY
9980 // or:
9981 // [stack] CTOR HOMEOBJ ARRAY
9982 return false;
9986 #ifdef ENABLE_DECORATORS
9987 // Index to use to append new initializers returned by decorators to the array
9988 if (!emitNumberOp(numInitializers)) {
9989 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX
9990 // or:
9991 // [stack] CTOR HOMEOBJ ARRAY INDEX
9992 return false;
9995 for (ParseNode* propdef : obj->contents()) {
9996 if (!propdef->is<ClassField>()) {
9997 continue;
9999 ClassField* field = &propdef->as<ClassField>();
10000 if (field->isStatic() != isStatic) {
10001 continue;
10003 if (field->decorators() && !field->decorators()->empty()) {
10004 DecoratorEmitter de(this);
10005 if (!field->hasAccessor()) {
10006 if (!de.emitApplyDecoratorsToFieldDefinition(
10007 &field->name(), field->decorators(), field->isStatic())) {
10008 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS
10009 // or:
10010 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS
10011 return false;
10013 } else {
10014 ClassMethod* accessorGetterNode = field->accessorGetterNode();
10015 auto accessorGetterKeyAtom =
10016 accessorGetterNode->left()->as<NameNode>().atom();
10017 ClassMethod* accessorSetterNode = field->accessorSetterNode();
10018 auto accessorSetterKeyAtom =
10019 accessorSetterNode->left()->as<NameNode>().atom();
10020 if (!IsPrivateInstanceAccessor(accessorGetterNode)) {
10021 if (!emitTree(&accessorGetterNode->method())) {
10022 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER
10023 // or:
10024 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER
10025 return false;
10027 if (!emitTree(&accessorSetterNode->method())) {
10028 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER SETTER
10029 // or:
10030 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER SETTER
10031 return false;
10033 } else {
10034 MOZ_ASSERT(IsPrivateInstanceAccessor(accessorSetterNode));
10035 auto getAccessor = [this](
10036 ClassMethod* classMethod,
10037 TaggedParserAtomIndex& updatedAtom) -> bool {
10038 // [stack]
10040 // Synthesize a name for the lexical variable that will store the
10041 // private method body.
10042 TaggedParserAtomIndex name =
10043 classMethod->name().as<NameNode>().atom();
10044 AccessorType accessorType = classMethod->accessorType();
10045 StringBuffer storedMethodName(fc);
10046 if (!storedMethodName.append(parserAtoms(), name)) {
10047 return false;
10049 if (!storedMethodName.append(accessorType == AccessorType::Getter
10050 ? ".getter"
10051 : ".setter")) {
10052 return false;
10054 updatedAtom = storedMethodName.finishParserAtom(parserAtoms(), fc);
10055 if (!updatedAtom) {
10056 return false;
10059 return emitGetName(updatedAtom);
10060 // [stack] ACCESSOR
10063 if (!getAccessor(accessorGetterNode, accessorGetterKeyAtom)) {
10064 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER
10065 // or:
10066 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER
10067 return false;
10070 if (!getAccessor(accessorSetterNode, accessorSetterKeyAtom)) {
10071 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER SETTER
10072 // or:
10073 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER SETTER
10074 return false;
10078 if (!de.emitApplyDecoratorsToAccessorDefinition(
10079 &field->name(), field->decorators(), field->isStatic())) {
10080 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER SETTER INITS
10081 // or:
10082 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER SETTER INITS
10083 return false;
10086 if (!emitUnpickN(2)) {
10087 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER SETTER
10088 // or:
10089 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER SETTER
10090 return false;
10093 if (!IsPrivateInstanceAccessor(accessorGetterNode)) {
10094 if (!isStatic) {
10095 if (!emitPickN(hasHeritage ? 6 : 5)) {
10096 // [stack] HERITAGE? ARRAY INDEX INITS GETTER SETTER HOMEOBJ
10097 return false;
10099 } else {
10100 if (!emitPickN(6)) {
10101 // [stack] HOMEOBJ ARRAY INDEX INITS GETTER SETTER CTOR
10102 return false;
10104 if (!emitPickN(6)) {
10105 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ
10106 return false;
10110 PropertyEmitter::Kind kind = field->isStatic()
10111 ? PropertyEmitter::Kind::Static
10112 : PropertyEmitter::Kind::Prototype;
10113 if (!accessorGetterNode->name().isKind(ParseNodeKind::PrivateName)) {
10114 MOZ_ASSERT(
10115 !accessorSetterNode->name().isKind(ParseNodeKind::PrivateName));
10117 if (!ce.prepareForPropValue(propdef->pn_pos.begin, kind)) {
10118 // [stack] HERITAGE? ARRAY INDEX INITS GETTER SETTER HOMEOBJ
10119 // or:
10120 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ CTOR
10121 return false;
10123 if (!emitPickN(isStatic ? 3 : 1)) {
10124 // [stack] HERITAGE? ARRAY INDEX INITS GETTER HOMEOBJ SETTER
10125 // or:
10126 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR SETTER
10127 return false;
10129 if (!ce.emitInit(AccessorType::Setter, accessorSetterKeyAtom)) {
10130 // [stack] HERITAGE? ARRAY INDEX INITS GETTER HOMEOBJ
10131 // or:
10132 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ
10133 return false;
10136 if (!ce.prepareForPropValue(propdef->pn_pos.begin, kind)) {
10137 // [stack] HERITAGE? ARRAY INDEX INITS GETTER HOMEOBJ
10138 // or:
10139 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR
10140 return false;
10142 if (!emitPickN(isStatic ? 3 : 1)) {
10143 // [stack] HERITAGE? ARRAY INDEX INITS HOMEOBJ GETTER
10144 // or:
10145 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ CTOR GETTER
10146 return false;
10148 if (!ce.emitInit(AccessorType::Getter, accessorGetterKeyAtom)) {
10149 // [stack] HERITAGE? ARRAY INDEX INITS HOMEOBJ
10150 // or:
10151 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ
10152 return false;
10154 } else {
10155 MOZ_ASSERT(isStatic);
10156 // The getter and setter share the same name.
10157 if (!emitNewPrivateName(accessorSetterKeyAtom,
10158 accessorSetterKeyAtom)) {
10159 return false;
10161 if (!ce.prepareForPrivateStaticMethod(propdef->pn_pos.begin)) {
10162 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ CTOR
10163 return false;
10165 if (!emitGetPrivateName(
10166 &accessorSetterNode->name().as<NameNode>())) {
10167 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ CTOR
10168 // KEY
10169 return false;
10171 if (!emitPickN(4)) {
10172 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR KEY
10173 // SETTER
10174 return false;
10176 if (!ce.emitPrivateStaticMethod(AccessorType::Setter)) {
10177 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ
10178 return false;
10181 if (!ce.prepareForPrivateStaticMethod(propdef->pn_pos.begin)) {
10182 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR
10183 return false;
10185 if (!emitGetPrivateName(
10186 &accessorGetterNode->name().as<NameNode>())) {
10187 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR KEY
10188 return false;
10190 if (!emitPickN(4)) {
10191 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ CTOR KEY GETTER
10192 return false;
10194 if (!ce.emitPrivateStaticMethod(AccessorType::Getter)) {
10195 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ
10196 return false;
10200 if (!isStatic) {
10201 if (!emitUnpickN(hasHeritage ? 4 : 3)) {
10202 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS
10203 return false;
10205 } else {
10206 if (!emitUnpickN(4)) {
10207 // [stack] HOMEOBJ ARRAY INDEX INITS CTOR
10208 return false;
10210 if (!emitUnpickN(4)) {
10211 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS
10212 return false;
10215 } else {
10216 MOZ_ASSERT(IsPrivateInstanceAccessor(accessorSetterNode));
10218 if (!emitLexicalInitialization(accessorSetterKeyAtom)) {
10219 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER SETTER
10220 // or:
10221 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER SETTER
10222 return false;
10225 if (!emitPopN(1)) {
10226 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER
10227 // or:
10228 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER
10229 return false;
10232 if (!emitLexicalInitialization(accessorGetterKeyAtom)) {
10233 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER
10234 // or:
10235 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER
10236 return false;
10239 if (!emitPopN(1)) {
10240 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS
10241 // or:
10242 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS
10243 return false;
10247 if (!emit1(JSOp::InitElemInc)) {
10248 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX
10249 // or:
10250 // [stack] CTOR HOMEOBJ ARRAY INDEX
10251 return false;
10256 // Pop INDEX
10257 if (!emitPopN(1)) {
10258 // [stack] HOMEOBJ HERITAGE? ARRAY
10259 // or:
10260 // [stack] CTOR HOMEOBJ ARRAY
10261 return false;
10263 #endif
10265 if (!ce.emitMemberInitializersEnd()) {
10266 // [stack] HOMEOBJ HERITAGE?
10267 // or:
10268 // [stack] CTOR HOMEOBJ
10269 return false;
10272 return true;
10275 bool BytecodeEmitter::emitPrivateMethodInitializers(ClassEmitter& ce,
10276 ListNode* obj) {
10277 for (ParseNode* propdef : obj->contents()) {
10278 if (!propdef->is<ClassMethod>()) {
10279 continue;
10281 auto* classMethod = &propdef->as<ClassMethod>();
10283 // Skip over anything which isn't a private instance accessor.
10284 if (!IsPrivateInstanceAccessor(classMethod)) {
10285 continue;
10288 if (!ce.prepareForMemberInitializer()) {
10289 // [stack] HOMEOBJ HERITAGE? ARRAY
10290 // or:
10291 // [stack] CTOR HOMEOBJ ARRAY
10292 return false;
10295 // Synthesize a name for the lexical variable that will store the
10296 // private method body.
10297 TaggedParserAtomIndex name = classMethod->name().as<NameNode>().atom();
10298 AccessorType accessorType = classMethod->accessorType();
10299 StringBuffer storedMethodName(fc);
10300 if (!storedMethodName.append(parserAtoms(), name)) {
10301 return false;
10303 if (!storedMethodName.append(
10304 accessorType == AccessorType::Getter ? ".getter" : ".setter")) {
10305 return false;
10307 auto storedMethodAtom =
10308 storedMethodName.finishParserAtom(parserAtoms(), fc);
10310 // Emit the private method body and store it as a lexical var.
10311 if (!emitFunction(&classMethod->method())) {
10312 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
10313 // or:
10314 // [stack] CTOR HOMEOBJ ARRAY METHOD
10315 return false;
10317 // The private method body needs to access the home object,
10318 // and the CE knows where that is on the stack.
10319 if (classMethod->method().funbox()->needsHomeObject()) {
10320 if (!ce.emitMemberInitializerHomeObject(false)) {
10321 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
10322 // or:
10323 // [stack] CTOR HOMEOBJ ARRAY METHOD
10324 return false;
10327 if (!emitLexicalInitialization(storedMethodAtom)) {
10328 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
10329 // or:
10330 // [stack] CTOR HOMEOBJ ARRAY METHOD
10331 return false;
10333 if (!emit1(JSOp::Pop)) {
10334 // [stack] HOMEOBJ HERITAGE? ARRAY
10335 // or:
10336 // [stack] CTOR HOMEOBJ ARRAY
10337 return false;
10340 if (!emitPrivateMethodInitializer(classMethod, storedMethodAtom)) {
10341 // [stack] HOMEOBJ HERITAGE? ARRAY
10342 // or:
10343 // [stack] CTOR HOMEOBJ ARRAY
10344 return false;
10347 // Store the emitted initializer function into the .initializers array.
10348 if (!ce.emitStoreMemberInitializer()) {
10349 // [stack] HOMEOBJ HERITAGE? ARRAY
10350 // or:
10351 // [stack] CTOR HOMEOBJ ARRAY
10352 return false;
10356 return true;
10359 bool BytecodeEmitter::emitPrivateMethodInitializer(
10360 ClassMethod* classMethod, TaggedParserAtomIndex storedMethodAtom) {
10361 MOZ_ASSERT(IsPrivateInstanceAccessor(classMethod));
10363 auto* name = &classMethod->name().as<NameNode>();
10365 // Emit the synthesized initializer function.
10366 FunctionNode* funNode = classMethod->initializerIfPrivate();
10367 MOZ_ASSERT(funNode);
10368 FunctionBox* funbox = funNode->funbox();
10369 FunctionEmitter fe(this, funbox, funNode->syntaxKind(),
10370 FunctionEmitter::IsHoisted::No);
10371 if (!fe.prepareForNonLazy()) {
10372 // [stack]
10373 return false;
10376 BytecodeEmitter bce2(this, funbox);
10377 if (!bce2.init(funNode->pn_pos)) {
10378 return false;
10380 ParamsBodyNode* paramsBody = funNode->body();
10381 FunctionScriptEmitter fse(&bce2, funbox, Nothing(), Nothing());
10382 if (!fse.prepareForParameters()) {
10383 // [stack]
10384 return false;
10386 if (!bce2.emitFunctionFormalParameters(paramsBody)) {
10387 // [stack]
10388 return false;
10390 if (!fse.prepareForBody()) {
10391 // [stack]
10392 return false;
10395 if (!bce2.emit1(JSOp::FunctionThis)) {
10396 // [stack] THIS
10397 return false;
10399 if (!bce2.emitGetPrivateName(name)) {
10400 // [stack] THIS NAME
10401 return false;
10403 if (!bce2.emitGetName(storedMethodAtom)) {
10404 // [stack] THIS NAME METHOD
10405 return false;
10408 switch (name->privateNameKind()) {
10409 case PrivateNameKind::Setter:
10410 if (!bce2.emit1(JSOp::InitHiddenElemSetter)) {
10411 // [stack] THIS
10412 return false;
10414 if (!bce2.emitGetPrivateName(name)) {
10415 // [stack] THIS NAME
10416 return false;
10418 if (!bce2.emitAtomOp(
10419 JSOp::GetIntrinsic,
10420 TaggedParserAtomIndex::WellKnown::NoPrivateGetter())) {
10421 // [stack] THIS NAME FUN
10422 return false;
10424 if (!bce2.emit1(JSOp::InitHiddenElemGetter)) {
10425 // [stack] THIS
10426 return false;
10428 break;
10429 case PrivateNameKind::Getter:
10430 case PrivateNameKind::GetterSetter:
10431 if (classMethod->accessorType() == AccessorType::Getter) {
10432 if (!bce2.emit1(JSOp::InitHiddenElemGetter)) {
10433 // [stack] THIS
10434 return false;
10436 } else {
10437 if (!bce2.emit1(JSOp::InitHiddenElemSetter)) {
10438 // [stack] THIS
10439 return false;
10442 break;
10443 default:
10444 MOZ_CRASH("Invalid op");
10447 // Pop remaining THIS.
10448 if (!bce2.emit1(JSOp::Pop)) {
10449 // [stack]
10450 return false;
10453 if (!fse.emitEndBody()) {
10454 // [stack]
10455 return false;
10457 if (!fse.intoStencil()) {
10458 return false;
10461 if (!fe.emitNonLazyEnd()) {
10462 // [stack] HOMEOBJ HERITAGE? ARRAY FUN
10463 // or:
10464 // [stack] CTOR HOMEOBJ ARRAY FUN
10465 return false;
10468 return true;
10471 const MemberInitializers& BytecodeEmitter::findMemberInitializersForCall() {
10472 for (BytecodeEmitter* current = this; current; current = current->parent) {
10473 if (current->sc->isFunctionBox()) {
10474 FunctionBox* funbox = current->sc->asFunctionBox();
10476 if (funbox->isArrow()) {
10477 continue;
10480 // If we found a non-arrow / non-constructor we were never allowed to
10481 // expect fields in the first place.
10482 MOZ_RELEASE_ASSERT(funbox->isClassConstructor());
10484 return funbox->useMemberInitializers() ? funbox->memberInitializers()
10485 : MemberInitializers::Empty();
10489 MOZ_RELEASE_ASSERT(compilationState.scopeContext.memberInitializers);
10490 return *compilationState.scopeContext.memberInitializers;
10493 bool BytecodeEmitter::emitInitializeInstanceMembers(
10494 bool isDerivedClassConstructor) {
10495 const MemberInitializers& memberInitializers =
10496 findMemberInitializersForCall();
10497 MOZ_ASSERT(memberInitializers.valid);
10499 if (memberInitializers.hasPrivateBrand) {
10500 // This is guaranteed to run after super(), so we don't need TDZ checks.
10501 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
10502 // [stack] THIS
10503 return false;
10505 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_privateBrand_())) {
10506 // [stack] THIS BRAND
10507 return false;
10509 if (isDerivedClassConstructor) {
10510 if (!emitCheckPrivateField(ThrowCondition::ThrowHas,
10511 ThrowMsgKind::PrivateBrandDoubleInit)) {
10512 // [stack] THIS BRAND BOOL
10513 return false;
10515 if (!emit1(JSOp::Pop)) {
10516 // [stack] THIS BRAND
10517 return false;
10520 if (!emit1(JSOp::Null)) {
10521 // [stack] THIS BRAND NULL
10522 return false;
10524 if (!emit1(JSOp::InitHiddenElem)) {
10525 // [stack] THIS
10526 return false;
10528 if (!emit1(JSOp::Pop)) {
10529 // [stack]
10530 return false;
10534 size_t numInitializers = memberInitializers.numMemberInitializers;
10535 if (numInitializers > 0) {
10536 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) {
10537 // [stack] ARRAY
10538 return false;
10541 for (size_t index = 0; index < numInitializers; index++) {
10542 if (index < numInitializers - 1) {
10543 // We Dup to keep the array around (it is consumed in the bytecode
10544 // below) for next iterations of this loop, except for the last
10545 // iteration, which avoids an extra Pop at the end of the loop.
10546 if (!emit1(JSOp::Dup)) {
10547 // [stack] ARRAY ARRAY
10548 return false;
10552 if (!emitNumberOp(index)) {
10553 // [stack] ARRAY? ARRAY INDEX
10554 return false;
10557 if (!emit1(JSOp::GetElem)) {
10558 // [stack] ARRAY? FUNC
10559 return false;
10562 // This is guaranteed to run after super(), so we don't need TDZ checks.
10563 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
10564 // [stack] ARRAY? FUNC THIS
10565 return false;
10568 // Callee is always internal function.
10569 if (!emitCall(JSOp::CallIgnoresRv, 0)) {
10570 // [stack] ARRAY? RVAL
10571 return false;
10574 if (!emit1(JSOp::Pop)) {
10575 // [stack] ARRAY?
10576 return false;
10579 #ifdef ENABLE_DECORATORS
10580 // Decorators Proposal
10581 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-initializeinstanceelements
10582 // 4. For each element e of elements, do
10583 // 4.a. If elementRecord.[[Kind]] is field or accessor, then
10584 // 4.a.i. Perform ? InitializeFieldOrAccessor(O, elementRecord).
10587 // TODO: (See Bug 1817993) At the moment, we're applying the initialization
10588 // logic in two steps. The pre-decorator initialization code runs, stores
10589 // the initial value, and then we retrieve it here and apply the
10590 // initializers added by decorators. We should unify these two steps.
10591 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) {
10592 // [stack] ARRAY
10593 return false;
10596 if (!emit1(JSOp::Dup)) {
10597 // [stack] ARRAY ARRAY
10598 return false;
10601 if (!emitAtomOp(JSOp::GetProp,
10602 TaggedParserAtomIndex::WellKnown::length())) {
10603 // [stack] ARRAY LENGTH
10604 return false;
10607 if (!emitNumberOp(static_cast<double>(numInitializers))) {
10608 // [stack] ARRAY LENGTH INDEX
10609 return false;
10612 InternalWhileEmitter wh(this);
10613 // At this point, we have no context to determine offsets in the
10614 // code for this while statement. Ideally, it would correspond to
10615 // the field we're initializing.
10616 if (!wh.emitCond()) {
10617 // [stack] ARRAY LENGTH INDEX
10618 return false;
10621 if (!emit1(JSOp::Dup)) {
10622 // [stack] ARRAY LENGTH INDEX INDEX
10623 return false;
10626 if (!emitDupAt(2)) {
10627 // [stack] ARRAY LENGTH INDEX INDEX LENGTH
10628 return false;
10631 if (!emit1(JSOp::Lt)) {
10632 // [stack] ARRAY LENGTH INDEX BOOL
10633 return false;
10636 if (!wh.emitBody()) {
10637 // [stack] ARRAY LENGTH INDEX
10638 return false;
10641 if (!emitDupAt(2)) {
10642 // [stack] ARRAY LENGTH INDEX ARRAY
10643 return false;
10646 if (!emitDupAt(1)) {
10647 // [stack] ARRAY LENGTH INDEX ARRAY INDEX
10648 return false;
10651 // Retrieve initializers for this field
10652 if (!emit1(JSOp::GetElem)) {
10653 // [stack] ARRAY LENGTH INDEX INITIALIZERS
10654 return false;
10657 // This is guaranteed to run after super(), so we don't need TDZ checks.
10658 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
10659 // [stack] ARRAY LENGTH INDEX INITIALIZERS THIS
10660 return false;
10663 if (!emit1(JSOp::Swap)) {
10664 // [stack] ARRAY LENGTH INDEX THIS INITIALIZERS
10665 return false;
10668 DecoratorEmitter de(this);
10669 if (!de.emitInitializeFieldOrAccessor()) {
10670 // [stack] ARRAY LENGTH INDEX
10671 return false;
10674 if (!emit1(JSOp::Inc)) {
10675 // [stack] ARRAY LENGTH INDEX
10676 return false;
10679 if (!wh.emitEnd()) {
10680 // [stack] ARRAY LENGTH INDEX
10681 return false;
10684 if (!emitPopN(3)) {
10685 // [stack]
10686 return false;
10688 // 5. Return unused.
10689 #endif
10691 return true;
10694 bool BytecodeEmitter::emitInitializeStaticFields(ListNode* classMembers) {
10695 auto isStaticField = [](ParseNode* propdef) {
10696 return HasInitializer(propdef, true);
10698 size_t numFields =
10699 std::count_if(classMembers->contents().begin(),
10700 classMembers->contents().end(), isStaticField);
10702 if (numFields == 0) {
10703 return true;
10706 if (!emitGetName(
10707 TaggedParserAtomIndex::WellKnown::dot_staticInitializers_())) {
10708 // [stack] CTOR ARRAY
10709 return false;
10712 for (size_t fieldIndex = 0; fieldIndex < numFields; fieldIndex++) {
10713 bool hasNext = fieldIndex < numFields - 1;
10714 if (hasNext) {
10715 // We Dup to keep the array around (it is consumed in the bytecode below)
10716 // for next iterations of this loop, except for the last iteration, which
10717 // avoids an extra Pop at the end of the loop.
10718 if (!emit1(JSOp::Dup)) {
10719 // [stack] CTOR ARRAY ARRAY
10720 return false;
10724 if (!emitNumberOp(fieldIndex)) {
10725 // [stack] CTOR ARRAY? ARRAY INDEX
10726 return false;
10729 if (!emit1(JSOp::GetElem)) {
10730 // [stack] CTOR ARRAY? FUNC
10731 return false;
10734 if (!emitDupAt(1 + hasNext)) {
10735 // [stack] CTOR ARRAY? FUNC CTOR
10736 return false;
10739 // Callee is always internal function.
10740 if (!emitCall(JSOp::CallIgnoresRv, 0)) {
10741 // [stack] CTOR ARRAY? RVAL
10742 return false;
10745 if (!emit1(JSOp::Pop)) {
10746 // [stack] CTOR ARRAY?
10747 return false;
10751 #ifdef ENABLE_DECORATORS
10752 // Decorators Proposal
10753 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-initializeinstanceelements
10754 // 4. For each element e of elements, do
10755 // 4.a. If elementRecord.[[Kind]] is field or accessor, then
10756 // 4.a.i. Perform ? InitializeFieldOrAccessor(O, elementRecord).
10759 // TODO: (See Bug 1817993) At the moment, we're applying the initialization
10760 // logic in two steps. The pre-decorator initialization code runs, stores
10761 // the initial value, and then we retrieve it here and apply the
10762 // initializers added by decorators. We should unify these two steps.
10763 if (!emitGetName(
10764 TaggedParserAtomIndex::WellKnown::dot_staticInitializers_())) {
10765 // [stack] CTOR ARRAY
10766 return false;
10769 if (!emit1(JSOp::Dup)) {
10770 // [stack] CTOR ARRAY ARRAY
10771 return false;
10774 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::length())) {
10775 // [stack] CTOR ARRAY LENGTH
10776 return false;
10779 if (!emitNumberOp(static_cast<double>(numFields))) {
10780 // [stack] CTOR ARRAY LENGTH INDEX
10781 return false;
10784 InternalWhileEmitter wh(this);
10785 // At this point, we have no context to determine offsets in the
10786 // code for this while statement. Ideally, it would correspond to
10787 // the field we're initializing.
10788 if (!wh.emitCond()) {
10789 // [stack] CTOR ARRAY LENGTH INDEX
10790 return false;
10793 if (!emit1(JSOp::Dup)) {
10794 // [stack] CTOR ARRAY LENGTH INDEX INDEX
10795 return false;
10798 if (!emitDupAt(2)) {
10799 // [stack] CTOR ARRAY LENGTH INDEX INDEX LENGTH
10800 return false;
10803 if (!emit1(JSOp::Lt)) {
10804 // [stack] CTOR ARRAY LENGTH INDEX BOOL
10805 return false;
10808 if (!wh.emitBody()) {
10809 // [stack] CTOR ARRAY LENGTH INDEX
10810 return false;
10813 if (!emitDupAt(2)) {
10814 // [stack] CTOR ARRAY LENGTH INDEX ARRAY
10815 return false;
10818 if (!emitDupAt(1)) {
10819 // [stack] CTOR ARRAY LENGTH INDEX ARRAY INDEX
10820 return false;
10823 // Retrieve initializers for this field
10824 if (!emit1(JSOp::GetElem)) {
10825 // [stack] CTOR ARRAY LENGTH INDEX INITIALIZERS
10826 return false;
10829 if (!emitDupAt(4)) {
10830 // [stack] CTOR ARRAY LENGTH INDEX INITIALIZERS CTOR
10831 return false;
10834 if (!emit1(JSOp::Swap)) {
10835 // [stack] CTOR ARRAY LENGTH INDEX CTOR INITIALIZERS
10836 return false;
10839 DecoratorEmitter de(this);
10840 if (!de.emitInitializeFieldOrAccessor()) {
10841 // [stack] CTOR ARRAY LENGTH INDEX
10842 return false;
10845 if (!emit1(JSOp::Inc)) {
10846 // [stack] CTOR ARRAY LENGTH INDEX
10847 return false;
10850 if (!wh.emitEnd()) {
10851 // [stack] CTOR ARRAY LENGTH INDEX
10852 return false;
10855 if (!emitPopN(3)) {
10856 // [stack] CTOR
10857 return false;
10859 // 5. Return unused.
10860 #endif
10862 // Overwrite |.staticInitializers| and |.staticFieldKeys| with undefined to
10863 // avoid keeping the arrays alive indefinitely.
10864 auto clearStaticFieldSlot = [&](TaggedParserAtomIndex name) {
10865 NameOpEmitter noe(this, name, NameOpEmitter::Kind::SimpleAssignment);
10866 if (!noe.prepareForRhs()) {
10867 // [stack] ENV? VAL?
10868 return false;
10871 if (!emit1(JSOp::Undefined)) {
10872 // [stack] ENV? VAL? UNDEFINED
10873 return false;
10876 if (!noe.emitAssignment()) {
10877 // [stack] VAL
10878 return false;
10881 if (!emit1(JSOp::Pop)) {
10882 // [stack]
10883 return false;
10886 return true;
10889 if (!clearStaticFieldSlot(
10890 TaggedParserAtomIndex::WellKnown::dot_staticInitializers_())) {
10891 return false;
10894 auto isStaticFieldWithComputedName = [](ParseNode* propdef) {
10895 return propdef->is<ClassField>() && propdef->as<ClassField>().isStatic() &&
10896 propdef->as<ClassField>().name().getKind() ==
10897 ParseNodeKind::ComputedName;
10900 if (std::any_of(classMembers->contents().begin(),
10901 classMembers->contents().end(),
10902 isStaticFieldWithComputedName)) {
10903 if (!clearStaticFieldSlot(
10904 TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_())) {
10905 return false;
10909 return true;
10912 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
10913 // the comment on emitSwitch.
10914 MOZ_NEVER_INLINE bool BytecodeEmitter::emitObject(ListNode* objNode) {
10915 // Note: this method uses the ObjLiteralWriter and emits ObjLiteralStencil
10916 // objects into the GCThingList, which will evaluate them into real GC objects
10917 // or shapes during JSScript::fullyInitFromEmitter. Eventually we want
10918 // JSOp::Object to be a real opcode, but for now, performance constraints
10919 // limit us to evaluating object literals at the end of parse, when we're
10920 // allowed to allocate GC things.
10922 // There are four cases here, in descending order of preference:
10924 // 1. The list of property names is "normal" and constant (no computed
10925 // values, no integer indices), the values are all simple constants
10926 // (numbers, booleans, strings), *and* this occurs in a run-once
10927 // (singleton) context. In this case, we can emit ObjLiteral
10928 // instructions to build an object with values, and the object will be
10929 // attached to a JSOp::Object opcode, whose semantics are for the backend
10930 // to simply steal the object from the script.
10932 // 2. The list of property names is "normal" and constant as above, *and* this
10933 // occurs in a run-once (singleton) context, but some values are complex
10934 // (computed expressions, sub-objects, functions, etc.). In this case, we
10935 // can still use JSOp::Object (because singleton context), but the object
10936 // has |undefined| property values and InitProp ops are emitted to set the
10937 // values.
10939 // 3. The list of property names is "normal" and constant as above, but this
10940 // occurs in a non-run-once (non-singleton) context. In this case, we can
10941 // use the ObjLiteral functionality to describe an *empty* object (all
10942 // values left undefined) with the right fields, which will become a
10943 // JSOp::NewObject opcode using the object's shape to speed up the creation
10944 // of the object each time it executes. The emitted bytecode still needs
10945 // InitProp ops to set the values in this case.
10947 // 4. Any other case. As a fallback, we use NewInit to create a new, empty
10948 // object (i.e., `{}`) and then emit bytecode to initialize its properties
10949 // one-by-one.
10951 bool useObjLiteral = false;
10952 bool useObjLiteralValues = false;
10953 isPropertyListObjLiteralCompatible(objNode, &useObjLiteralValues,
10954 &useObjLiteral);
10956 // [stack]
10958 ObjectEmitter oe(this);
10959 if (useObjLiteral) {
10960 bool singleton = checkSingletonContext() &&
10961 !objNode->hasNonConstInitializer() && objNode->head();
10962 JSOp op;
10963 if (singleton) {
10964 // Case 1 or 2.
10965 op = JSOp::Object;
10966 } else {
10967 // Case 3.
10968 useObjLiteralValues = false;
10969 op = JSOp::NewObject;
10972 // Use an ObjLiteral op. This will record ObjLiteral insns in the
10973 // objLiteralWriter's buffer and add a fixup to the list of ObjLiteral
10974 // fixups so that at GC-publish time at the end of parse, the full object
10975 // (case 1 or 2) or shape (case 3) can be allocated and the bytecode can be
10976 // patched to refer to it.
10977 if (!emitPropertyListObjLiteral(objNode, op, useObjLiteralValues)) {
10978 // [stack] OBJ
10979 return false;
10981 // Put the ObjectEmitter in the right state. This tells it that there will
10982 // already be an object on the stack as a result of the (eventual)
10983 // NewObject or Object op, and prepares it to emit values if needed.
10984 if (!oe.emitObjectWithTemplateOnStack()) {
10985 // [stack] OBJ
10986 return false;
10988 if (!useObjLiteralValues) {
10989 // Case 2 or 3 above: we still need to emit bytecode to fill in the
10990 // object's property values.
10991 if (!emitPropertyList(objNode, oe, ObjectLiteral)) {
10992 // [stack] OBJ
10993 return false;
10996 } else {
10997 // Case 4 above: no ObjLiteral use, just bytecode to build the object from
10998 // scratch.
10999 if (!oe.emitObject(objNode->count())) {
11000 // [stack] OBJ
11001 return false;
11003 if (!emitPropertyList(objNode, oe, ObjectLiteral)) {
11004 // [stack] OBJ
11005 return false;
11009 if (!oe.emitEnd()) {
11010 // [stack] OBJ
11011 return false;
11014 return true;
11017 bool BytecodeEmitter::emitArrayLiteral(ListNode* array) {
11018 // Emit JSOp::Object if the array consists entirely of primitive values and we
11019 // are in a singleton context.
11020 if (checkSingletonContext() && !array->hasNonConstInitializer() &&
11021 !array->empty() && isArrayObjLiteralCompatible(array)) {
11022 return emitObjLiteralArray(array);
11025 return emitArray(array);
11028 bool BytecodeEmitter::emitArray(ListNode* array) {
11030 * Emit code for [a, b, c] that is equivalent to constructing a new
11031 * array and in source order evaluating each element value and adding
11032 * it to the array, without invoking latent setters. We use the
11033 * JSOp::NewInit and JSOp::InitElemArray bytecodes to ignore setters and
11034 * to avoid dup'ing and popping the array as each element is added, as
11035 * JSOp::SetElem/JSOp::SetProp would do.
11038 uint32_t nspread = 0;
11039 for (ParseNode* elem : array->contents()) {
11040 if (elem->isKind(ParseNodeKind::Spread)) {
11041 nspread++;
11045 // Array literal's length is limited to NELEMENTS_LIMIT in parser.
11046 static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT <= INT32_MAX,
11047 "array literals' maximum length must not exceed limits "
11048 "required by BaselineCompiler::emit_NewArray, "
11049 "BaselineCompiler::emit_InitElemArray, "
11050 "and DoSetElemFallback's handling of JSOp::InitElemArray");
11052 uint32_t count = array->count();
11053 MOZ_ASSERT(count >= nspread);
11054 MOZ_ASSERT(count <= NativeObject::MAX_DENSE_ELEMENTS_COUNT,
11055 "the parser must throw an error if the array exceeds maximum "
11056 "length");
11058 // For arrays with spread, this is a very pessimistic allocation, the
11059 // minimum possible final size.
11060 if (!emitUint32Operand(JSOp::NewArray, count - nspread)) {
11061 // [stack] ARRAY
11062 return false;
11065 uint32_t index = 0;
11066 bool afterSpread = false;
11067 for (ParseNode* elem : array->contents()) {
11068 if (elem->isKind(ParseNodeKind::Spread)) {
11069 if (!afterSpread) {
11070 afterSpread = true;
11071 if (!emitNumberOp(index)) {
11072 // [stack] ARRAY INDEX
11073 return false;
11077 ParseNode* expr = elem->as<UnaryNode>().kid();
11078 SelfHostedIter selfHostedIter = getSelfHostedIterFor(expr);
11080 if (!updateSourceCoordNotes(elem->pn_pos.begin)) {
11081 return false;
11083 if (!emitIterable(expr, selfHostedIter)) {
11084 // [stack] ARRAY INDEX ITERABLE
11085 return false;
11087 if (!emitIterator(selfHostedIter)) {
11088 // [stack] ARRAY INDEX NEXT ITER
11089 return false;
11091 if (!emit2(JSOp::Pick, 3)) {
11092 // [stack] INDEX NEXT ITER ARRAY
11093 return false;
11095 if (!emit2(JSOp::Pick, 3)) {
11096 // [stack] NEXT ITER ARRAY INDEX
11097 return false;
11099 if (!emitSpread(selfHostedIter)) {
11100 // [stack] ARRAY INDEX
11101 return false;
11103 } else {
11104 if (!updateSourceCoordNotesIfNonLiteral(elem)) {
11105 return false;
11107 if (elem->isKind(ParseNodeKind::Elision)) {
11108 if (!emit1(JSOp::Hole)) {
11109 return false;
11111 } else {
11112 if (!emitTree(elem, ValueUsage::WantValue)) {
11113 // [stack] ARRAY INDEX? VALUE
11114 return false;
11118 if (afterSpread) {
11119 if (!emit1(JSOp::InitElemInc)) {
11120 // [stack] ARRAY (INDEX+1)
11121 return false;
11123 } else {
11124 if (!emitUint32Operand(JSOp::InitElemArray, index)) {
11125 // [stack] ARRAY
11126 return false;
11131 index++;
11133 MOZ_ASSERT(index == count);
11134 if (afterSpread) {
11135 if (!emit1(JSOp::Pop)) {
11136 // [stack] ARRAY
11137 return false;
11140 return true;
11143 bool BytecodeEmitter::emitSpreadIntoArray(UnaryNode* elem) {
11144 MOZ_ASSERT(elem->isKind(ParseNodeKind::Spread));
11146 if (!updateSourceCoordNotes(elem->pn_pos.begin)) {
11147 // [stack] VALUE
11148 return false;
11151 SelfHostedIter selfHostedIter = getSelfHostedIterFor(elem->kid());
11152 MOZ_ASSERT(selfHostedIter == SelfHostedIter::Deny ||
11153 selfHostedIter == SelfHostedIter::AllowContent);
11155 if (!emitIterator(selfHostedIter)) {
11156 // [stack] NEXT ITER
11157 return false;
11160 if (!emitUint32Operand(JSOp::NewArray, 0)) {
11161 // [stack] NEXT ITER ARRAY
11162 return false;
11165 if (!emitNumberOp(0)) {
11166 // [stack] NEXT ITER ARRAY INDEX
11167 return false;
11170 if (!emitSpread(selfHostedIter)) {
11171 // [stack] ARRAY INDEX
11172 return false;
11175 if (!emit1(JSOp::Pop)) {
11176 // [stack] ARRAY
11177 return false;
11179 return true;
11182 #ifdef ENABLE_RECORD_TUPLE
11183 bool BytecodeEmitter::emitRecordLiteral(ListNode* record) {
11184 if (!emitUint32Operand(JSOp::InitRecord, record->count())) {
11185 // [stack] RECORD
11186 return false;
11189 for (ParseNode* propdef : record->contents()) {
11190 if (propdef->isKind(ParseNodeKind::Spread)) {
11191 if (!emitTree(propdef->as<UnaryNode>().kid())) {
11192 // [stack] RECORD SPREADEE
11193 return false;
11195 if (!emit1(JSOp::AddRecordSpread)) {
11196 // [stack] RECORD
11197 return false;
11199 } else {
11200 BinaryNode* prop = &propdef->as<BinaryNode>();
11202 ParseNode* key = prop->left();
11203 ParseNode* value = prop->right();
11205 switch (key->getKind()) {
11206 case ParseNodeKind::ObjectPropertyName:
11207 if (!emitStringOp(JSOp::String, key->as<NameNode>().atom())) {
11208 return false;
11210 break;
11211 case ParseNodeKind::ComputedName:
11212 if (!emitTree(key->as<UnaryNode>().kid())) {
11213 return false;
11215 break;
11216 default:
11217 MOZ_ASSERT(key->isKind(ParseNodeKind::StringExpr) ||
11218 key->isKind(ParseNodeKind::NumberExpr) ||
11219 key->isKind(ParseNodeKind::BigIntExpr));
11220 if (!emitTree(key)) {
11221 return false;
11223 break;
11225 // [stack] RECORD KEY
11227 if (!emitTree(value)) {
11228 // [stack] RECORD KEY VALUE
11229 return false;
11232 if (!emit1(JSOp::AddRecordProperty)) {
11233 // [stack] RECORD
11234 return false;
11239 if (!emit1(JSOp::FinishRecord)) {
11240 // [stack] RECORD
11241 return false;
11244 return true;
11247 bool BytecodeEmitter::emitTupleLiteral(ListNode* tuple) {
11248 if (!emitUint32Operand(JSOp::InitTuple, tuple->count())) {
11249 // [stack] TUPLE
11250 return false;
11253 for (ParseNode* elt : tuple->contents()) {
11254 if (elt->isKind(ParseNodeKind::Spread)) {
11255 ParseNode* expr = elt->as<UnaryNode>().kid();
11256 auto selfHostedIter = getSelfHostedIterFor(expr);
11258 if (!emitIterable(expr, selfHostedIter)) {
11259 // [stack] TUPLE ITERABLE
11260 return false;
11262 if (!emitIterator(selfHostedIter)) {
11263 // [stack] TUPLE NEXT ITER
11264 return false;
11266 if (!emit2(JSOp::Pick, 2)) {
11267 // [stack] NEXT ITER TUPLE
11268 return false;
11270 if (!emitSpread(selfHostedIter, /* spreadeeStackItems = */ 1,
11271 JSOp::AddTupleElement)) {
11272 // [stack] TUPLE
11273 return false;
11275 } else {
11276 // Update location to throw errors about non-primitive elements
11277 // in the correct position.
11278 if (!updateSourceCoordNotesIfNonLiteral(elt)) {
11279 return false;
11282 if (!emitTree(elt)) {
11283 // [stack] TUPLE VALUE
11284 return false;
11287 if (!emit1(JSOp::AddTupleElement)) {
11288 // [stack] TUPLE
11289 return false;
11294 if (!emit1(JSOp::FinishTuple)) {
11295 // [stack] TUPLE
11296 return false;
11299 return true;
11301 #endif
11303 static inline JSOp UnaryOpParseNodeKindToJSOp(ParseNodeKind pnk) {
11304 switch (pnk) {
11305 case ParseNodeKind::ThrowStmt:
11306 return JSOp::Throw;
11307 case ParseNodeKind::VoidExpr:
11308 return JSOp::Void;
11309 case ParseNodeKind::NotExpr:
11310 return JSOp::Not;
11311 case ParseNodeKind::BitNotExpr:
11312 return JSOp::BitNot;
11313 case ParseNodeKind::PosExpr:
11314 return JSOp::Pos;
11315 case ParseNodeKind::NegExpr:
11316 return JSOp::Neg;
11317 default:
11318 MOZ_CRASH("unexpected unary op");
11322 bool BytecodeEmitter::emitUnary(UnaryNode* unaryNode) {
11323 if (!updateSourceCoordNotes(unaryNode->pn_pos.begin)) {
11324 return false;
11327 JSOp op = UnaryOpParseNodeKindToJSOp(unaryNode->getKind());
11328 ValueUsage valueUsage =
11329 op == JSOp::Void ? ValueUsage::IgnoreValue : ValueUsage::WantValue;
11330 if (!emitTree(unaryNode->kid(), valueUsage)) {
11331 return false;
11333 return emit1(op);
11336 bool BytecodeEmitter::emitTypeof(UnaryNode* typeofNode, JSOp op) {
11337 MOZ_ASSERT(op == JSOp::Typeof || op == JSOp::TypeofExpr);
11339 if (!updateSourceCoordNotes(typeofNode->pn_pos.begin)) {
11340 return false;
11343 if (!emitTree(typeofNode->kid())) {
11344 return false;
11347 return emit1(op);
11350 bool BytecodeEmitter::emitFunctionFormalParameters(ParamsBodyNode* paramsBody) {
11351 FunctionBox* funbox = sc->asFunctionBox();
11353 bool hasRest = funbox->hasRest();
11355 FunctionParamsEmitter fpe(this, funbox);
11356 for (ParseNode* arg : paramsBody->parameters()) {
11357 ParseNode* bindingElement = arg;
11358 ParseNode* initializer = nullptr;
11359 if (arg->isKind(ParseNodeKind::AssignExpr)) {
11360 bindingElement = arg->as<BinaryNode>().left();
11361 initializer = arg->as<BinaryNode>().right();
11363 bool hasInitializer = !!initializer;
11364 bool isRest =
11365 hasRest && arg->pn_next == *std::end(paramsBody->parameters());
11366 bool isDestructuring = !bindingElement->isKind(ParseNodeKind::Name);
11368 // Left-hand sides are either simple names or destructuring patterns.
11369 MOZ_ASSERT(bindingElement->isKind(ParseNodeKind::Name) ||
11370 bindingElement->isKind(ParseNodeKind::ArrayExpr) ||
11371 bindingElement->isKind(ParseNodeKind::ObjectExpr));
11373 auto emitDefaultInitializer = [this, &initializer, &bindingElement]() {
11374 // [stack]
11376 if (!this->emitInitializer(initializer, bindingElement)) {
11377 // [stack] DEFAULT
11378 return false;
11380 return true;
11383 auto emitDestructuring = [this, &bindingElement]() {
11384 // [stack] ARG
11386 if (!this->emitDestructuringOps(&bindingElement->as<ListNode>(),
11387 DestructuringFlavor::Declaration)) {
11388 // [stack] ARG
11389 return false;
11392 return true;
11395 if (isRest) {
11396 if (isDestructuring) {
11397 if (!fpe.prepareForDestructuringRest()) {
11398 // [stack]
11399 return false;
11401 if (!emitDestructuring()) {
11402 // [stack]
11403 return false;
11405 if (!fpe.emitDestructuringRestEnd()) {
11406 // [stack]
11407 return false;
11409 } else {
11410 auto paramName = bindingElement->as<NameNode>().name();
11411 if (!fpe.emitRest(paramName)) {
11412 // [stack]
11413 return false;
11417 continue;
11420 if (isDestructuring) {
11421 if (hasInitializer) {
11422 if (!fpe.prepareForDestructuringDefaultInitializer()) {
11423 // [stack]
11424 return false;
11426 if (!emitDefaultInitializer()) {
11427 // [stack]
11428 return false;
11430 if (!fpe.prepareForDestructuringDefault()) {
11431 // [stack]
11432 return false;
11434 if (!emitDestructuring()) {
11435 // [stack]
11436 return false;
11438 if (!fpe.emitDestructuringDefaultEnd()) {
11439 // [stack]
11440 return false;
11442 } else {
11443 if (!fpe.prepareForDestructuring()) {
11444 // [stack]
11445 return false;
11447 if (!emitDestructuring()) {
11448 // [stack]
11449 return false;
11451 if (!fpe.emitDestructuringEnd()) {
11452 // [stack]
11453 return false;
11457 continue;
11460 if (hasInitializer) {
11461 if (!fpe.prepareForDefault()) {
11462 // [stack]
11463 return false;
11465 if (!emitDefaultInitializer()) {
11466 // [stack]
11467 return false;
11469 auto paramName = bindingElement->as<NameNode>().name();
11470 if (!fpe.emitDefaultEnd(paramName)) {
11471 // [stack]
11472 return false;
11475 continue;
11478 auto paramName = bindingElement->as<NameNode>().name();
11479 if (!fpe.emitSimple(paramName)) {
11480 // [stack]
11481 return false;
11485 return true;
11488 bool BytecodeEmitter::emitInitializeFunctionSpecialNames() {
11489 FunctionBox* funbox = sc->asFunctionBox();
11491 // [stack]
11493 auto emitInitializeFunctionSpecialName =
11494 [](BytecodeEmitter* bce, TaggedParserAtomIndex name, JSOp op) {
11495 // A special name must be slotful, either on the frame or on the
11496 // call environment.
11497 MOZ_ASSERT(bce->lookupName(name).hasKnownSlot());
11499 NameOpEmitter noe(bce, name, NameOpEmitter::Kind::Initialize);
11500 if (!noe.prepareForRhs()) {
11501 // [stack]
11502 return false;
11504 if (!bce->emit1(op)) {
11505 // [stack] THIS/ARGUMENTS/NEW.TARGET
11506 return false;
11508 if (!noe.emitAssignment()) {
11509 // [stack] THIS/ARGUMENTS/NEW.TARGET
11510 return false;
11512 if (!bce->emit1(JSOp::Pop)) {
11513 // [stack]
11514 return false;
11517 return true;
11520 // Do nothing if the function doesn't have an arguments binding.
11521 if (funbox->needsArgsObj()) {
11522 // Self-hosted code should use the more efficient ArgumentsLength and
11523 // GetArgument intrinsics instead of `arguments`.
11524 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
11525 if (!emitInitializeFunctionSpecialName(
11526 this, TaggedParserAtomIndex::WellKnown::arguments(),
11527 JSOp::Arguments)) {
11528 // [stack]
11529 return false;
11533 // Do nothing if the function doesn't have a this-binding (this
11534 // happens for instance if it doesn't use this/eval or if it's an
11535 // arrow function).
11536 if (funbox->functionHasThisBinding()) {
11537 if (!emitInitializeFunctionSpecialName(
11538 this, TaggedParserAtomIndex::WellKnown::dot_this_(),
11539 JSOp::FunctionThis)) {
11540 return false;
11544 // Do nothing if the function doesn't have a new.target-binding (this happens
11545 // for instance if it doesn't use new.target/eval or if it's an arrow
11546 // function).
11547 if (funbox->functionHasNewTargetBinding()) {
11548 if (!emitInitializeFunctionSpecialName(
11549 this, TaggedParserAtomIndex::WellKnown::dot_newTarget_(),
11550 JSOp::NewTarget)) {
11551 return false;
11555 // Do nothing if the function doesn't implicitly return a promise result.
11556 if (funbox->needsPromiseResult()) {
11557 if (!emitInitializeFunctionSpecialName(
11558 this, TaggedParserAtomIndex::WellKnown::dot_generator_(),
11559 JSOp::Generator)) {
11560 // [stack]
11561 return false;
11564 return true;
11567 bool BytecodeEmitter::emitLexicalInitialization(NameNode* name) {
11568 return emitLexicalInitialization(name->name());
11571 bool BytecodeEmitter::emitLexicalInitialization(TaggedParserAtomIndex name) {
11572 NameOpEmitter noe(this, name, NameOpEmitter::Kind::Initialize);
11573 if (!noe.prepareForRhs()) {
11574 return false;
11577 // The caller has pushed the RHS to the top of the stack. Assert that the
11578 // binding can be initialized without a binding object on the stack, and that
11579 // no JSOp::BindName or JSOp::BindGName ops were emitted.
11580 MOZ_ASSERT(noe.loc().isLexical() || noe.loc().isSynthetic() ||
11581 noe.loc().isPrivateMethod());
11582 MOZ_ASSERT(!noe.emittedBindOp());
11584 if (!noe.emitAssignment()) {
11585 return false;
11588 return true;
11591 static MOZ_ALWAYS_INLINE ParseNode* FindConstructor(ListNode* classMethods) {
11592 for (ParseNode* classElement : classMethods->contents()) {
11593 ParseNode* unwrappedElement = classElement;
11594 if (unwrappedElement->is<LexicalScopeNode>()) {
11595 unwrappedElement = unwrappedElement->as<LexicalScopeNode>().scopeBody();
11597 if (unwrappedElement->is<ClassMethod>()) {
11598 ClassMethod& method = unwrappedElement->as<ClassMethod>();
11599 ParseNode& methodName = method.name();
11600 if (!method.isStatic() &&
11601 (methodName.isKind(ParseNodeKind::ObjectPropertyName) ||
11602 methodName.isKind(ParseNodeKind::StringExpr)) &&
11603 methodName.as<NameNode>().atom() ==
11604 TaggedParserAtomIndex::WellKnown::constructor()) {
11605 return classElement;
11609 return nullptr;
11612 bool BytecodeEmitter::emitNewPrivateName(TaggedParserAtomIndex bindingName,
11613 TaggedParserAtomIndex symbolName) {
11614 if (!emitAtomOp(JSOp::NewPrivateName, symbolName)) {
11615 // [stack] HERITAGE PRIVATENAME
11616 return false;
11619 // Add a binding for #name => privatename
11620 if (!emitLexicalInitialization(bindingName)) {
11621 // [stack] HERITAGE PRIVATENAME
11622 return false;
11625 // Pop Private name off the stack.
11626 if (!emit1(JSOp::Pop)) {
11627 // [stack] HERITAGE
11628 return false;
11631 return true;
11634 bool BytecodeEmitter::emitNewPrivateNames(
11635 TaggedParserAtomIndex privateBrandName, ListNode* classMembers) {
11636 bool hasPrivateBrand = false;
11638 for (ParseNode* classElement : classMembers->contents()) {
11639 ParseNode* elementName;
11640 if (classElement->is<ClassMethod>()) {
11641 elementName = &classElement->as<ClassMethod>().name();
11642 } else if (classElement->is<ClassField>()) {
11643 elementName = &classElement->as<ClassField>().name();
11644 } else {
11645 continue;
11648 if (!elementName->isKind(ParseNodeKind::PrivateName)) {
11649 continue;
11652 // Non-static private methods' private names are optimized away.
11653 bool isOptimized = false;
11654 if (classElement->is<ClassMethod>() &&
11655 !classElement->as<ClassMethod>().isStatic()) {
11656 hasPrivateBrand = true;
11657 if (classElement->as<ClassMethod>().accessorType() ==
11658 AccessorType::None) {
11659 isOptimized = true;
11663 if (!isOptimized) {
11664 auto privateName = elementName->as<NameNode>().name();
11665 if (!emitNewPrivateName(privateName, privateName)) {
11666 return false;
11671 if (hasPrivateBrand) {
11672 // We don't make a private name for every optimized method, but we need one
11673 // private name per class, the `.privateBrand`.
11674 if (!emitNewPrivateName(
11675 TaggedParserAtomIndex::WellKnown::dot_privateBrand_(),
11676 privateBrandName)) {
11677 return false;
11680 return true;
11683 // This follows ES6 14.5.14 (ClassDefinitionEvaluation) and ES6 14.5.15
11684 // (BindingClassDeclarationEvaluation).
11685 bool BytecodeEmitter::emitClass(
11686 ClassNode* classNode,
11687 ClassNameKind nameKind /* = ClassNameKind::BindingName */,
11688 TaggedParserAtomIndex
11689 nameForAnonymousClass /* = TaggedParserAtomIndex::null() */) {
11690 MOZ_ASSERT((nameKind == ClassNameKind::InferredName) ==
11691 bool(nameForAnonymousClass));
11693 ParseNode* heritageExpression = classNode->heritage();
11694 ListNode* classMembers = classNode->memberList();
11695 ParseNode* constructor = FindConstructor(classMembers);
11697 // If |nameKind != ClassNameKind::ComputedName|
11698 // [stack]
11699 // Else
11700 // [stack] NAME
11702 ClassEmitter ce(this);
11703 TaggedParserAtomIndex innerName;
11704 ClassEmitter::Kind kind = ClassEmitter::Kind::Expression;
11705 if (ClassNames* names = classNode->names()) {
11706 MOZ_ASSERT(nameKind == ClassNameKind::BindingName);
11707 innerName = names->innerBinding()->name();
11708 MOZ_ASSERT(innerName);
11710 if (names->outerBinding()) {
11711 MOZ_ASSERT(names->outerBinding()->name());
11712 MOZ_ASSERT(names->outerBinding()->name() == innerName);
11713 kind = ClassEmitter::Kind::Declaration;
11717 if (LexicalScopeNode* scopeBindings = classNode->scopeBindings()) {
11718 if (!ce.emitScope(scopeBindings->scopeBindings())) {
11719 // [stack]
11720 return false;
11724 bool isDerived = !!heritageExpression;
11725 if (isDerived) {
11726 if (!updateSourceCoordNotes(classNode->pn_pos.begin)) {
11727 return false;
11729 if (!markStepBreakpoint()) {
11730 return false;
11732 if (!emitTree(heritageExpression)) {
11733 // [stack] HERITAGE
11734 return false;
11738 // The class body scope holds any private names. Those mustn't be visible in
11739 // the heritage expression and hence the scope must be emitted after the
11740 // heritage expression.
11741 if (ClassBodyScopeNode* bodyScopeBindings = classNode->bodyScopeBindings()) {
11742 if (!ce.emitBodyScope(bodyScopeBindings->scopeBindings())) {
11743 // [stack] HERITAGE
11744 return false;
11747 // The spec does not say anything about private brands being symbols. It's
11748 // an implementation detail. So we can give the special private brand
11749 // symbol any description we want and users won't normally see it. For
11750 // debugging, use the class name.
11751 auto privateBrandName = innerName;
11752 if (!innerName) {
11753 privateBrandName = nameForAnonymousClass
11754 ? nameForAnonymousClass
11755 : TaggedParserAtomIndex::WellKnown::anonymous();
11757 if (!emitNewPrivateNames(privateBrandName, classMembers)) {
11758 return false;
11762 bool hasNameOnStack = nameKind == ClassNameKind::ComputedName;
11763 if (isDerived) {
11764 if (!ce.emitDerivedClass(innerName, nameForAnonymousClass,
11765 hasNameOnStack)) {
11766 // [stack] HERITAGE HOMEOBJ
11767 return false;
11769 } else {
11770 if (!ce.emitClass(innerName, nameForAnonymousClass, hasNameOnStack)) {
11771 // [stack] HOMEOBJ
11772 return false;
11776 // Stack currently has HOMEOBJ followed by optional HERITAGE. When HERITAGE
11777 // is not used, an implicit value of %FunctionPrototype% is implied.
11779 // See |Parser::classMember(...)| for the reason why |.initializers| is
11780 // created within its own scope.
11781 Maybe<LexicalScopeEmitter> lse;
11782 FunctionNode* ctor;
11783 if (constructor->is<LexicalScopeNode>()) {
11784 LexicalScopeNode* constructorScope = &constructor->as<LexicalScopeNode>();
11786 // The constructor scope should only contain the |.initializers| binding.
11787 MOZ_ASSERT(!constructorScope->isEmptyScope());
11788 MOZ_ASSERT(constructorScope->scopeBindings()->length == 1);
11789 MOZ_ASSERT(GetScopeDataTrailingNames(constructorScope->scopeBindings())[0]
11790 .name() ==
11791 TaggedParserAtomIndex::WellKnown::dot_initializers_());
11793 auto needsInitializer = [](ParseNode* propdef) {
11794 return NeedsFieldInitializer(propdef, false) ||
11795 NeedsAccessorInitializer(propdef, false);
11798 // As an optimization omit the |.initializers| binding when no instance
11799 // fields or private methods are present.
11800 bool needsInitializers =
11801 std::any_of(classMembers->contents().begin(),
11802 classMembers->contents().end(), needsInitializer);
11803 if (needsInitializers) {
11804 lse.emplace(this);
11805 if (!lse->emitScope(ScopeKind::Lexical,
11806 constructorScope->scopeBindings())) {
11807 return false;
11810 // Any class with field initializers will have a constructor
11811 if (!emitCreateMemberInitializers(ce, classMembers,
11812 FieldPlacement::Instance
11813 #ifdef ENABLE_DECORATORS
11815 isDerived
11816 #endif
11817 )) {
11818 return false;
11822 ctor = &constructorScope->scopeBody()->as<ClassMethod>().method();
11823 } else {
11824 // The |.initializers| binding is never emitted when in self-hosting mode.
11825 MOZ_ASSERT(emitterMode == BytecodeEmitter::SelfHosting);
11826 ctor = &constructor->as<ClassMethod>().method();
11829 bool needsHomeObject = ctor->funbox()->needsHomeObject();
11830 // HERITAGE is consumed inside emitFunction.
11831 if (nameKind == ClassNameKind::InferredName) {
11832 if (!setFunName(ctor->funbox(), nameForAnonymousClass)) {
11833 return false;
11836 if (!emitFunction(ctor, isDerived)) {
11837 // [stack] HOMEOBJ CTOR
11838 return false;
11840 if (lse.isSome()) {
11841 if (!lse->emitEnd()) {
11842 return false;
11844 lse.reset();
11846 if (!ce.emitInitConstructor(needsHomeObject)) {
11847 // [stack] CTOR HOMEOBJ
11848 return false;
11851 if (!emitCreateFieldKeys(classMembers, FieldPlacement::Instance)) {
11852 return false;
11855 if (!emitCreateMemberInitializers(ce, classMembers, FieldPlacement::Static
11856 #ifdef ENABLE_DECORATORS
11858 false
11859 #endif
11860 )) {
11861 return false;
11864 if (!emitCreateFieldKeys(classMembers, FieldPlacement::Static)) {
11865 return false;
11868 if (!emitPropertyList(classMembers, ce, ClassBody)) {
11869 // [stack] CTOR HOMEOBJ
11870 return false;
11873 if (!ce.emitBinding()) {
11874 // [stack] CTOR
11875 return false;
11878 if (!emitInitializeStaticFields(classMembers)) {
11879 // [stack] CTOR
11880 return false;
11883 #if ENABLE_DECORATORS
11884 if (classNode->decorators() != nullptr) {
11885 DecoratorEmitter de(this);
11886 NameNode* className =
11887 classNode->names() ? classNode->names()->innerBinding() : nullptr;
11888 if (!de.emitApplyDecoratorsToClassDefinition(className,
11889 classNode->decorators())) {
11890 // [stack] CTOR
11891 return false;
11894 #endif
11896 if (!ce.emitEnd(kind)) {
11897 // [stack] # class declaration
11898 // [stack]
11899 // [stack] # class expression
11900 // [stack] CTOR
11901 return false;
11904 return true;
11907 bool BytecodeEmitter::emitExportDefault(BinaryNode* exportNode) {
11908 MOZ_ASSERT(exportNode->isKind(ParseNodeKind::ExportDefaultStmt));
11910 ParseNode* valueNode = exportNode->left();
11911 if (valueNode->isDirectRHSAnonFunction()) {
11912 MOZ_ASSERT(exportNode->right());
11914 if (!emitAnonymousFunctionWithName(
11915 valueNode, TaggedParserAtomIndex::WellKnown::default_())) {
11916 return false;
11918 } else {
11919 if (!emitTree(valueNode)) {
11920 return false;
11924 if (ParseNode* binding = exportNode->right()) {
11925 if (!emitLexicalInitialization(&binding->as<NameNode>())) {
11926 return false;
11929 if (!emit1(JSOp::Pop)) {
11930 return false;
11934 return true;
11937 bool BytecodeEmitter::emitTree(
11938 ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */,
11939 EmitLineNumberNote emitLineNote /* = EMIT_LINENOTE */) {
11940 AutoCheckRecursionLimit recursion(fc);
11941 if (!recursion.check(fc)) {
11942 return false;
11945 /* Emit notes to tell the current bytecode's source line number.
11946 However, a couple trees require special treatment; see the
11947 relevant emitter functions for details. */
11948 if (emitLineNote == EMIT_LINENOTE &&
11949 !ParseNodeRequiresSpecialLineNumberNotes(pn)) {
11950 if (!updateLineNumberNotes(pn->pn_pos.begin)) {
11951 return false;
11955 switch (pn->getKind()) {
11956 case ParseNodeKind::Function:
11957 if (!emitFunction(&pn->as<FunctionNode>())) {
11958 return false;
11960 break;
11962 case ParseNodeKind::ParamsBody:
11963 MOZ_ASSERT_UNREACHABLE(
11964 "ParamsBody should be handled in emitFunctionScript.");
11965 break;
11967 case ParseNodeKind::IfStmt:
11968 if (!emitIf(&pn->as<TernaryNode>())) {
11969 return false;
11971 break;
11973 case ParseNodeKind::SwitchStmt:
11974 if (!emitSwitch(&pn->as<SwitchStatement>())) {
11975 return false;
11977 break;
11979 case ParseNodeKind::WhileStmt:
11980 if (!emitWhile(&pn->as<BinaryNode>())) {
11981 return false;
11983 break;
11985 case ParseNodeKind::DoWhileStmt:
11986 if (!emitDo(&pn->as<BinaryNode>())) {
11987 return false;
11989 break;
11991 case ParseNodeKind::ForStmt:
11992 if (!emitFor(&pn->as<ForNode>())) {
11993 return false;
11995 break;
11997 case ParseNodeKind::BreakStmt:
11998 // Ensure that the column of the 'break' is set properly.
11999 if (!updateSourceCoordNotes(pn->pn_pos.begin)) {
12000 return false;
12002 if (!markStepBreakpoint()) {
12003 return false;
12006 if (!emitBreak(pn->as<BreakStatement>().label())) {
12007 return false;
12009 break;
12011 case ParseNodeKind::ContinueStmt:
12012 // Ensure that the column of the 'continue' is set properly.
12013 if (!updateSourceCoordNotes(pn->pn_pos.begin)) {
12014 return false;
12016 if (!markStepBreakpoint()) {
12017 return false;
12020 if (!emitContinue(pn->as<ContinueStatement>().label())) {
12021 return false;
12023 break;
12025 case ParseNodeKind::WithStmt:
12026 if (!emitWith(&pn->as<BinaryNode>())) {
12027 return false;
12029 break;
12031 case ParseNodeKind::TryStmt:
12032 if (!emitTry(&pn->as<TryNode>())) {
12033 return false;
12035 break;
12037 case ParseNodeKind::Catch:
12038 if (!emitCatch(&pn->as<BinaryNode>())) {
12039 return false;
12041 break;
12043 case ParseNodeKind::VarStmt:
12044 if (!emitDeclarationList(&pn->as<ListNode>())) {
12045 return false;
12047 break;
12049 case ParseNodeKind::ReturnStmt:
12050 if (!emitReturn(&pn->as<UnaryNode>())) {
12051 return false;
12053 break;
12055 case ParseNodeKind::YieldStarExpr:
12056 if (!emitYieldStar(pn->as<UnaryNode>().kid())) {
12057 return false;
12059 break;
12061 case ParseNodeKind::Generator:
12062 if (!emit1(JSOp::Generator)) {
12063 return false;
12065 break;
12067 case ParseNodeKind::InitialYield:
12068 if (!emitInitialYield(&pn->as<UnaryNode>())) {
12069 return false;
12071 break;
12073 case ParseNodeKind::YieldExpr:
12074 if (!emitYield(&pn->as<UnaryNode>())) {
12075 return false;
12077 break;
12079 case ParseNodeKind::AwaitExpr:
12080 if (!emitAwaitInInnermostScope(&pn->as<UnaryNode>())) {
12081 return false;
12083 break;
12085 case ParseNodeKind::StatementList:
12086 if (!emitStatementList(&pn->as<ListNode>())) {
12087 return false;
12089 break;
12091 case ParseNodeKind::EmptyStmt:
12092 break;
12094 case ParseNodeKind::ExpressionStmt:
12095 if (!emitExpressionStatement(&pn->as<UnaryNode>())) {
12096 return false;
12098 break;
12100 case ParseNodeKind::LabelStmt:
12101 if (!emitLabeledStatement(&pn->as<LabeledStatement>())) {
12102 return false;
12104 break;
12106 case ParseNodeKind::CommaExpr:
12107 if (!emitSequenceExpr(&pn->as<ListNode>(), valueUsage)) {
12108 return false;
12110 break;
12112 case ParseNodeKind::InitExpr:
12113 case ParseNodeKind::AssignExpr:
12114 case ParseNodeKind::AddAssignExpr:
12115 case ParseNodeKind::SubAssignExpr:
12116 case ParseNodeKind::BitOrAssignExpr:
12117 case ParseNodeKind::BitXorAssignExpr:
12118 case ParseNodeKind::BitAndAssignExpr:
12119 case ParseNodeKind::LshAssignExpr:
12120 case ParseNodeKind::RshAssignExpr:
12121 case ParseNodeKind::UrshAssignExpr:
12122 case ParseNodeKind::MulAssignExpr:
12123 case ParseNodeKind::DivAssignExpr:
12124 case ParseNodeKind::ModAssignExpr:
12125 case ParseNodeKind::PowAssignExpr: {
12126 BinaryNode* assignNode = &pn->as<BinaryNode>();
12127 if (!emitAssignmentOrInit(assignNode->getKind(), assignNode->left(),
12128 assignNode->right())) {
12129 return false;
12131 break;
12134 case ParseNodeKind::CoalesceAssignExpr:
12135 case ParseNodeKind::OrAssignExpr:
12136 case ParseNodeKind::AndAssignExpr:
12137 if (!emitShortCircuitAssignment(&pn->as<AssignmentNode>())) {
12138 return false;
12140 break;
12142 case ParseNodeKind::ConditionalExpr:
12143 if (!emitConditionalExpression(pn->as<ConditionalExpression>(),
12144 valueUsage)) {
12145 return false;
12147 break;
12149 case ParseNodeKind::OrExpr:
12150 case ParseNodeKind::CoalesceExpr:
12151 case ParseNodeKind::AndExpr:
12152 if (!emitShortCircuit(&pn->as<ListNode>(), valueUsage)) {
12153 return false;
12155 break;
12157 case ParseNodeKind::AddExpr:
12158 case ParseNodeKind::SubExpr:
12159 case ParseNodeKind::BitOrExpr:
12160 case ParseNodeKind::BitXorExpr:
12161 case ParseNodeKind::BitAndExpr:
12162 case ParseNodeKind::StrictEqExpr:
12163 case ParseNodeKind::EqExpr:
12164 case ParseNodeKind::StrictNeExpr:
12165 case ParseNodeKind::NeExpr:
12166 case ParseNodeKind::LtExpr:
12167 case ParseNodeKind::LeExpr:
12168 case ParseNodeKind::GtExpr:
12169 case ParseNodeKind::GeExpr:
12170 case ParseNodeKind::InExpr:
12171 case ParseNodeKind::InstanceOfExpr:
12172 case ParseNodeKind::LshExpr:
12173 case ParseNodeKind::RshExpr:
12174 case ParseNodeKind::UrshExpr:
12175 case ParseNodeKind::MulExpr:
12176 case ParseNodeKind::DivExpr:
12177 case ParseNodeKind::ModExpr:
12178 if (!emitLeftAssociative(&pn->as<ListNode>())) {
12179 return false;
12181 break;
12183 case ParseNodeKind::PrivateInExpr:
12184 if (!emitPrivateInExpr(&pn->as<ListNode>())) {
12185 return false;
12187 break;
12189 case ParseNodeKind::PowExpr:
12190 if (!emitRightAssociative(&pn->as<ListNode>())) {
12191 return false;
12193 break;
12195 case ParseNodeKind::TypeOfNameExpr:
12196 if (!emitTypeof(&pn->as<UnaryNode>(), JSOp::Typeof)) {
12197 return false;
12199 break;
12201 case ParseNodeKind::TypeOfExpr:
12202 if (!emitTypeof(&pn->as<UnaryNode>(), JSOp::TypeofExpr)) {
12203 return false;
12205 break;
12207 case ParseNodeKind::ThrowStmt:
12208 if (!updateSourceCoordNotes(pn->pn_pos.begin)) {
12209 return false;
12211 if (!markStepBreakpoint()) {
12212 return false;
12214 [[fallthrough]];
12215 case ParseNodeKind::VoidExpr:
12216 case ParseNodeKind::NotExpr:
12217 case ParseNodeKind::BitNotExpr:
12218 case ParseNodeKind::PosExpr:
12219 case ParseNodeKind::NegExpr:
12220 if (!emitUnary(&pn->as<UnaryNode>())) {
12221 return false;
12223 break;
12225 case ParseNodeKind::PreIncrementExpr:
12226 case ParseNodeKind::PreDecrementExpr:
12227 case ParseNodeKind::PostIncrementExpr:
12228 case ParseNodeKind::PostDecrementExpr:
12229 if (!emitIncOrDec(&pn->as<UnaryNode>(), valueUsage)) {
12230 return false;
12232 break;
12234 case ParseNodeKind::DeleteNameExpr:
12235 if (!emitDeleteName(&pn->as<UnaryNode>())) {
12236 return false;
12238 break;
12240 case ParseNodeKind::DeletePropExpr:
12241 if (!emitDeleteProperty(&pn->as<UnaryNode>())) {
12242 return false;
12244 break;
12246 case ParseNodeKind::DeleteElemExpr:
12247 if (!emitDeleteElement(&pn->as<UnaryNode>())) {
12248 return false;
12250 break;
12252 case ParseNodeKind::DeleteExpr:
12253 if (!emitDeleteExpression(&pn->as<UnaryNode>())) {
12254 return false;
12256 break;
12258 case ParseNodeKind::DeleteOptionalChainExpr:
12259 if (!emitDeleteOptionalChain(&pn->as<UnaryNode>())) {
12260 return false;
12262 break;
12264 case ParseNodeKind::OptionalChain:
12265 if (!emitOptionalChain(&pn->as<UnaryNode>(), valueUsage)) {
12266 return false;
12268 break;
12270 case ParseNodeKind::DotExpr: {
12271 PropertyAccess* prop = &pn->as<PropertyAccess>();
12272 bool isSuper = prop->isSuper();
12273 PropOpEmitter poe(this, PropOpEmitter::Kind::Get,
12274 isSuper ? PropOpEmitter::ObjKind::Super
12275 : PropOpEmitter::ObjKind::Other);
12276 if (!poe.prepareForObj()) {
12277 return false;
12279 if (isSuper) {
12280 UnaryNode* base = &prop->expression().as<UnaryNode>();
12281 if (!emitGetThisForSuperBase(base)) {
12282 // [stack] THIS
12283 return false;
12285 } else {
12286 if (!emitPropLHS(prop)) {
12287 // [stack] OBJ
12288 return false;
12291 if (!poe.emitGet(prop->key().atom())) {
12292 // [stack] PROP
12293 return false;
12295 break;
12298 case ParseNodeKind::ElemExpr: {
12299 PropertyByValue* elem = &pn->as<PropertyByValue>();
12300 bool isSuper = elem->isSuper();
12301 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
12302 ElemOpEmitter eoe(this, ElemOpEmitter::Kind::Get,
12303 isSuper ? ElemOpEmitter::ObjKind::Super
12304 : ElemOpEmitter::ObjKind::Other);
12305 if (!emitElemObjAndKey(elem, isSuper, eoe)) {
12306 // [stack] # if Super
12307 // [stack] THIS KEY
12308 // [stack] # otherwise
12309 // [stack] OBJ KEY
12310 return false;
12312 if (!eoe.emitGet()) {
12313 // [stack] ELEM
12314 return false;
12317 break;
12320 case ParseNodeKind::PrivateMemberExpr: {
12321 PrivateMemberAccess* privateExpr = &pn->as<PrivateMemberAccess>();
12322 PrivateOpEmitter xoe(this, PrivateOpEmitter::Kind::Get,
12323 privateExpr->privateName().name());
12324 if (!emitTree(&privateExpr->expression())) {
12325 // [stack] OBJ
12326 return false;
12328 if (!xoe.emitReference()) {
12329 // [stack] OBJ NAME
12330 return false;
12332 if (!xoe.emitGet()) {
12333 // [stack] VALUE
12334 return false;
12337 break;
12340 case ParseNodeKind::NewExpr:
12341 case ParseNodeKind::TaggedTemplateExpr:
12342 case ParseNodeKind::CallExpr:
12343 case ParseNodeKind::SuperCallExpr:
12344 if (!emitCallOrNew(&pn->as<CallNode>(), valueUsage)) {
12345 return false;
12347 break;
12349 case ParseNodeKind::LexicalScope:
12350 if (!emitLexicalScope(&pn->as<LexicalScopeNode>())) {
12351 return false;
12353 break;
12355 case ParseNodeKind::ConstDecl:
12356 case ParseNodeKind::LetDecl:
12357 if (!emitDeclarationList(&pn->as<ListNode>())) {
12358 return false;
12360 break;
12362 case ParseNodeKind::ImportDecl:
12363 MOZ_ASSERT(sc->isModuleContext());
12364 break;
12366 case ParseNodeKind::ExportStmt: {
12367 MOZ_ASSERT(sc->isModuleContext());
12368 UnaryNode* node = &pn->as<UnaryNode>();
12369 ParseNode* decl = node->kid();
12370 if (decl->getKind() != ParseNodeKind::ExportSpecList) {
12371 if (!emitTree(decl)) {
12372 return false;
12375 break;
12378 case ParseNodeKind::ExportDefaultStmt:
12379 MOZ_ASSERT(sc->isModuleContext());
12380 if (!emitExportDefault(&pn->as<BinaryNode>())) {
12381 return false;
12383 break;
12385 case ParseNodeKind::ExportFromStmt:
12386 MOZ_ASSERT(sc->isModuleContext());
12387 break;
12389 case ParseNodeKind::CallSiteObj:
12390 if (!emitCallSiteObject(&pn->as<CallSiteNode>())) {
12391 return false;
12393 break;
12395 case ParseNodeKind::ArrayExpr:
12396 if (!emitArrayLiteral(&pn->as<ListNode>())) {
12397 return false;
12399 break;
12401 case ParseNodeKind::ObjectExpr:
12402 if (!emitObject(&pn->as<ListNode>())) {
12403 return false;
12405 break;
12407 case ParseNodeKind::Name:
12408 if (!emitGetName(&pn->as<NameNode>())) {
12409 return false;
12411 break;
12413 case ParseNodeKind::PrivateName:
12414 if (!emitGetPrivateName(&pn->as<NameNode>())) {
12415 return false;
12417 break;
12419 case ParseNodeKind::TemplateStringListExpr:
12420 if (!emitTemplateString(&pn->as<ListNode>())) {
12421 return false;
12423 break;
12425 case ParseNodeKind::TemplateStringExpr:
12426 case ParseNodeKind::StringExpr:
12427 if (!emitStringOp(JSOp::String, pn->as<NameNode>().atom())) {
12428 return false;
12430 break;
12432 case ParseNodeKind::NumberExpr:
12433 if (!emitNumberOp(pn->as<NumericLiteral>().value())) {
12434 return false;
12436 break;
12438 case ParseNodeKind::BigIntExpr:
12439 if (!emitBigIntOp(&pn->as<BigIntLiteral>())) {
12440 return false;
12442 break;
12444 case ParseNodeKind::RegExpExpr: {
12445 GCThingIndex index;
12446 if (!perScriptData().gcThingList().append(&pn->as<RegExpLiteral>(),
12447 &index)) {
12448 return false;
12450 if (!emitRegExp(index)) {
12451 return false;
12453 break;
12456 case ParseNodeKind::TrueExpr:
12457 if (!emit1(JSOp::True)) {
12458 return false;
12460 break;
12461 case ParseNodeKind::FalseExpr:
12462 if (!emit1(JSOp::False)) {
12463 return false;
12465 break;
12466 case ParseNodeKind::NullExpr:
12467 if (!emit1(JSOp::Null)) {
12468 return false;
12470 break;
12471 case ParseNodeKind::RawUndefinedExpr:
12472 if (!emit1(JSOp::Undefined)) {
12473 return false;
12475 break;
12477 case ParseNodeKind::ThisExpr:
12478 if (!emitThisLiteral(&pn->as<ThisLiteral>())) {
12479 return false;
12481 break;
12483 case ParseNodeKind::DebuggerStmt:
12484 if (!updateSourceCoordNotes(pn->pn_pos.begin)) {
12485 return false;
12487 if (!markStepBreakpoint()) {
12488 return false;
12490 if (!emit1(JSOp::Debugger)) {
12491 return false;
12493 break;
12495 case ParseNodeKind::ClassDecl:
12496 if (!emitClass(&pn->as<ClassNode>())) {
12497 return false;
12499 break;
12501 case ParseNodeKind::NewTargetExpr:
12502 if (!emitNewTarget(&pn->as<NewTargetNode>())) {
12503 return false;
12505 break;
12507 case ParseNodeKind::ImportMetaExpr:
12508 if (!emit1(JSOp::ImportMeta)) {
12509 return false;
12511 break;
12513 case ParseNodeKind::CallImportExpr: {
12514 BinaryNode* spec = &pn->as<BinaryNode>().right()->as<BinaryNode>();
12516 if (!emitTree(spec->left())) {
12517 // [stack] specifier
12518 return false;
12521 if (!spec->right()->isKind(ParseNodeKind::PosHolder)) {
12522 // [stack] specifier options
12523 if (!emitTree(spec->right())) {
12524 return false;
12526 } else {
12527 // [stack] specifier undefined
12528 if (!emit1(JSOp::Undefined)) {
12529 return false;
12533 if (!emit1(JSOp::DynamicImport)) {
12534 return false;
12537 break;
12540 case ParseNodeKind::SetThis:
12541 if (!emitSetThis(&pn->as<BinaryNode>())) {
12542 return false;
12544 break;
12546 #ifdef ENABLE_RECORD_TUPLE
12547 case ParseNodeKind::RecordExpr:
12548 if (!emitRecordLiteral(&pn->as<ListNode>())) {
12549 return false;
12551 break;
12553 case ParseNodeKind::TupleExpr:
12554 if (!emitTupleLiteral(&pn->as<ListNode>())) {
12555 return false;
12557 break;
12558 #endif
12560 case ParseNodeKind::PropertyNameExpr:
12561 case ParseNodeKind::PosHolder:
12562 MOZ_FALLTHROUGH_ASSERT(
12563 "Should never try to emit ParseNodeKind::PosHolder or ::Property");
12565 default:
12566 MOZ_ASSERT(0);
12569 return true;
12572 static bool AllocSrcNote(FrontendContext* fc, SrcNotesVector& notes,
12573 unsigned size, unsigned* index) {
12574 size_t oldLength = notes.length();
12576 if (MOZ_UNLIKELY(oldLength + size > MaxSrcNotesLength)) {
12577 ReportAllocationOverflow(fc);
12578 return false;
12581 if (!notes.growByUninitialized(size)) {
12582 return false;
12585 *index = oldLength;
12586 return true;
12589 bool BytecodeEmitter::addTryNote(TryNoteKind kind, uint32_t stackDepth,
12590 BytecodeOffset start, BytecodeOffset end) {
12591 MOZ_ASSERT(!inPrologue());
12592 return bytecodeSection().tryNoteList().append(kind, stackDepth, start, end);
12595 bool BytecodeEmitter::newSrcNote(SrcNoteType type, unsigned* indexp) {
12596 SrcNotesVector& notes = bytecodeSection().notes();
12597 unsigned index;
12600 * Compute delta from the last annotated bytecode's offset. If it's too
12601 * big to fit in sn, allocate one or more xdelta notes and reset sn.
12603 BytecodeOffset offset = bytecodeSection().offset();
12604 ptrdiff_t delta = (offset - bytecodeSection().lastNoteOffset()).value();
12605 bytecodeSection().setLastNoteOffset(offset);
12607 auto allocator = [&](unsigned size) -> SrcNote* {
12608 if (!AllocSrcNote(fc, notes, size, &index)) {
12609 return nullptr;
12611 return &notes[index];
12614 if (!SrcNoteWriter::writeNote(type, delta, allocator)) {
12615 return false;
12618 if (indexp) {
12619 *indexp = index;
12622 if (type == SrcNoteType::NewLine || type == SrcNoteType::SetLine) {
12623 lastLineOnlySrcNoteIndex = index;
12624 } else {
12625 lastLineOnlySrcNoteIndex = LastSrcNoteIsNotLineOnly;
12628 return true;
12631 bool BytecodeEmitter::newSrcNote2(SrcNoteType type, ptrdiff_t offset,
12632 unsigned* indexp) {
12633 unsigned index;
12634 if (!newSrcNote(type, &index)) {
12635 return false;
12637 if (!newSrcNoteOperand(offset)) {
12638 return false;
12640 if (indexp) {
12641 *indexp = index;
12643 return true;
12646 bool BytecodeEmitter::convertLastNewLineToNewLineColumn(
12647 JS::LimitedColumnNumberZeroOrigin column) {
12648 SrcNotesVector& notes = bytecodeSection().notes();
12649 MOZ_ASSERT(lastLineOnlySrcNoteIndex == notes.length() - 1);
12650 SrcNote* sn = &notes[lastLineOnlySrcNoteIndex];
12651 MOZ_ASSERT(sn->type() == SrcNoteType::NewLine);
12653 SrcNoteWriter::convertNote(sn, SrcNoteType::NewLineColumn);
12654 if (!newSrcNoteOperand(SrcNote::NewLineColumn::toOperand(column))) {
12655 return false;
12658 lastLineOnlySrcNoteIndex = LastSrcNoteIsNotLineOnly;
12659 return true;
12662 bool BytecodeEmitter::convertLastSetLineToSetLineColumn(
12663 JS::LimitedColumnNumberZeroOrigin column) {
12664 SrcNotesVector& notes = bytecodeSection().notes();
12665 // The Line operand is either 1 byte or 4 bytes.
12666 MOZ_ASSERT(lastLineOnlySrcNoteIndex == notes.length() - 1 - 1 ||
12667 lastLineOnlySrcNoteIndex == notes.length() - 1 - 4);
12668 SrcNote* sn = &notes[lastLineOnlySrcNoteIndex];
12669 MOZ_ASSERT(sn->type() == SrcNoteType::SetLine);
12671 SrcNoteWriter::convertNote(sn, SrcNoteType::SetLineColumn);
12672 if (!newSrcNoteOperand(SrcNote::SetLineColumn::columnToOperand(column))) {
12673 return false;
12676 lastLineOnlySrcNoteIndex = LastSrcNoteIsNotLineOnly;
12677 return true;
12680 bool BytecodeEmitter::newSrcNoteOperand(ptrdiff_t operand) {
12681 if (!SrcNote::isRepresentableOperand(operand)) {
12682 reportError(nullptr, JSMSG_NEED_DIET, "script");
12683 return false;
12686 SrcNotesVector& notes = bytecodeSection().notes();
12688 auto allocator = [&](unsigned size) -> SrcNote* {
12689 unsigned index;
12690 if (!AllocSrcNote(fc, notes, size, &index)) {
12691 return nullptr;
12693 return &notes[index];
12696 return SrcNoteWriter::writeOperand(operand, allocator);
12699 bool BytecodeEmitter::intoScriptStencil(ScriptIndex scriptIndex) {
12700 js::UniquePtr<ImmutableScriptData> immutableScriptData =
12701 createImmutableScriptData();
12702 if (!immutableScriptData) {
12703 return false;
12706 MOZ_ASSERT(outermostScope().hasNonSyntacticScopeOnChain() ==
12707 sc->hasNonSyntacticScope());
12709 auto& things = perScriptData().gcThingList().objects();
12710 if (!compilationState.appendGCThings(fc, scriptIndex, things)) {
12711 return false;
12714 // Hand over the ImmutableScriptData instance generated by BCE.
12715 auto* sharedData =
12716 SharedImmutableScriptData::createWith(fc, std::move(immutableScriptData));
12717 if (!sharedData) {
12718 return false;
12721 // De-duplicate the bytecode within the runtime.
12722 if (!compilationState.sharedData.addAndShare(fc, scriptIndex, sharedData)) {
12723 return false;
12726 ScriptStencil& script = compilationState.scriptData[scriptIndex];
12727 script.setHasSharedData();
12729 // Update flags specific to functions.
12730 if (sc->isFunctionBox()) {
12731 FunctionBox* funbox = sc->asFunctionBox();
12732 MOZ_ASSERT(&script == &funbox->functionStencil());
12733 funbox->copyUpdatedImmutableFlags();
12734 MOZ_ASSERT(script.isFunction());
12735 } else {
12736 ScriptStencilExtra& scriptExtra = compilationState.scriptExtra[scriptIndex];
12737 sc->copyScriptExtraFields(scriptExtra);
12740 return true;
12743 SelfHostedIter BytecodeEmitter::getSelfHostedIterFor(ParseNode* parseNode) {
12744 if (emitterMode == BytecodeEmitter::SelfHosting &&
12745 parseNode->isKind(ParseNodeKind::CallExpr)) {
12746 auto* callee = parseNode->as<CallNode>().callee();
12747 if (callee->isName(TaggedParserAtomIndex::WellKnown::allowContentIter())) {
12748 return SelfHostedIter::AllowContent;
12750 if (callee->isName(
12751 TaggedParserAtomIndex::WellKnown::allowContentIterWith())) {
12752 return SelfHostedIter::AllowContentWith;
12754 if (callee->isName(
12755 TaggedParserAtomIndex::WellKnown::allowContentIterWithNext())) {
12756 return SelfHostedIter::AllowContentWithNext;
12760 return SelfHostedIter::Deny;
12763 #if defined(DEBUG) || defined(JS_JITSPEW)
12764 void BytecodeEmitter::dumpAtom(TaggedParserAtomIndex index) const {
12765 parserAtoms().dump(index);
12767 #endif