Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / BytecodeEmitter.cpp
bloba6a6cf916a7736a01a94f9e6cbfb2e016eb5f065
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::LimitedColumnNumberOneOrigin, 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,
143 JS::LimitedColumnNumberOneOrigin(sc->extent().column)),
144 perScriptData_(fc, compilationState),
145 errorReporter_(errorReporter),
146 compilationState(compilationState),
147 suppressBreakpointsAndSourceNotes(
148 ShouldSuppressBreakpointsAndSourceNotes(sc, emitterMode)),
149 emitterMode(emitterMode) {
150 MOZ_ASSERT_IF(parent, fc == parent->fc);
153 BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent, SharedContext* sc)
154 : BytecodeEmitter(parent, parent->fc, sc, parent->errorReporter_,
155 parent->compilationState, parent->emitterMode) {}
157 BytecodeEmitter::BytecodeEmitter(FrontendContext* fc,
158 const EitherParser& parser, SharedContext* sc,
159 CompilationState& compilationState,
160 EmitterMode emitterMode)
161 : BytecodeEmitter(nullptr, fc, sc, parser.errorReporter(), compilationState,
162 emitterMode) {
163 ep_.emplace(parser);
166 void BytecodeEmitter::initFromBodyPosition(TokenPos bodyPosition) {
167 setScriptStartOffsetIfUnset(bodyPosition.begin);
168 setFunctionBodyEndPos(bodyPosition.end);
171 bool BytecodeEmitter::init() {
172 if (!parent) {
173 if (!compilationState.prepareSharedDataStorage(fc)) {
174 return false;
177 return perScriptData_.init(fc);
180 bool BytecodeEmitter::init(TokenPos bodyPosition) {
181 initFromBodyPosition(bodyPosition);
182 return init();
185 template <typename T>
186 T* BytecodeEmitter::findInnermostNestableControl() const {
187 return NestableControl::findNearest<T>(innermostNestableControl);
190 template <typename T, typename Predicate /* (T*) -> bool */>
191 T* BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const {
192 return NestableControl::findNearest<T>(innermostNestableControl, predicate);
195 NameLocation BytecodeEmitter::lookupName(TaggedParserAtomIndex name) {
196 return innermostEmitterScope()->lookup(this, name);
199 void BytecodeEmitter::lookupPrivate(TaggedParserAtomIndex name,
200 NameLocation& loc,
201 Maybe<NameLocation>& brandLoc) {
202 innermostEmitterScope()->lookupPrivate(this, name, loc, brandLoc);
205 Maybe<NameLocation> BytecodeEmitter::locationOfNameBoundInScope(
206 TaggedParserAtomIndex name, EmitterScope* target) {
207 return innermostEmitterScope()->locationBoundInScope(name, target);
210 template <typename T>
211 Maybe<NameLocation> BytecodeEmitter::locationOfNameBoundInScopeType(
212 TaggedParserAtomIndex name, EmitterScope* source) {
213 EmitterScope* aScope = source;
214 while (!aScope->scope(this).is<T>()) {
215 aScope = aScope->enclosingInFrame();
217 return source->locationBoundInScope(name, aScope);
220 bool BytecodeEmitter::markStepBreakpoint() {
221 if (skipBreakpointSrcNotes()) {
222 return true;
225 if (!newSrcNote(SrcNoteType::BreakpointStepSep)) {
226 return false;
229 // We track the location of the most recent separator for use in
230 // markSimpleBreakpoint. Note that this means that the position must already
231 // be set before markStepBreakpoint is called.
232 bytecodeSection().updateSeparatorPosition();
234 return true;
237 bool BytecodeEmitter::markSimpleBreakpoint() {
238 if (skipBreakpointSrcNotes()) {
239 return true;
242 // If a breakable call ends up being the same location as the most recent
243 // expression start, we need to skip marking it breakable in order to avoid
244 // having two breakpoints with the same line/column position.
245 // Note: This assumes that the position for the call has already been set.
246 if (!bytecodeSection().isDuplicateLocation()) {
247 if (!newSrcNote(SrcNoteType::Breakpoint)) {
248 return false;
252 return true;
255 bool BytecodeEmitter::emitCheck(JSOp op, ptrdiff_t delta,
256 BytecodeOffset* offset) {
257 size_t oldLength = bytecodeSection().code().length();
258 *offset = BytecodeOffset(oldLength);
260 size_t newLength = oldLength + size_t(delta);
261 if (MOZ_UNLIKELY(newLength > MaxBytecodeLength)) {
262 ReportAllocationOverflow(fc);
263 return false;
266 if (!bytecodeSection().code().growByUninitialized(delta)) {
267 return false;
270 if (BytecodeOpHasIC(op)) {
271 // Even if every bytecode op is a JOF_IC op and the function has ARGC_LIMIT
272 // arguments, numICEntries cannot overflow.
273 static_assert(MaxBytecodeLength + 1 /* this */ + ARGC_LIMIT <= UINT32_MAX,
274 "numICEntries must not overflow");
275 bytecodeSection().incrementNumICEntries();
278 return true;
281 #ifdef DEBUG
282 bool BytecodeEmitter::checkStrictOrSloppy(JSOp op) {
283 if (IsCheckStrictOp(op) && !sc->strict()) {
284 return false;
286 if (IsCheckSloppyOp(op) && sc->strict()) {
287 return false;
289 return true;
291 #endif
293 bool BytecodeEmitter::emit1(JSOp op) {
294 MOZ_ASSERT(checkStrictOrSloppy(op));
296 BytecodeOffset offset;
297 if (!emitCheck(op, 1, &offset)) {
298 return false;
301 jsbytecode* code = bytecodeSection().code(offset);
302 code[0] = jsbytecode(op);
303 bytecodeSection().updateDepth(op, offset);
304 return true;
307 bool BytecodeEmitter::emit2(JSOp op, uint8_t op1) {
308 MOZ_ASSERT(checkStrictOrSloppy(op));
310 BytecodeOffset offset;
311 if (!emitCheck(op, 2, &offset)) {
312 return false;
315 jsbytecode* code = bytecodeSection().code(offset);
316 code[0] = jsbytecode(op);
317 code[1] = jsbytecode(op1);
318 bytecodeSection().updateDepth(op, offset);
319 return true;
322 bool BytecodeEmitter::emit3(JSOp op, jsbytecode op1, jsbytecode op2) {
323 MOZ_ASSERT(checkStrictOrSloppy(op));
325 /* These should filter through emitVarOp. */
326 MOZ_ASSERT(!IsArgOp(op));
327 MOZ_ASSERT(!IsLocalOp(op));
329 BytecodeOffset offset;
330 if (!emitCheck(op, 3, &offset)) {
331 return false;
334 jsbytecode* code = bytecodeSection().code(offset);
335 code[0] = jsbytecode(op);
336 code[1] = op1;
337 code[2] = op2;
338 bytecodeSection().updateDepth(op, offset);
339 return true;
342 bool BytecodeEmitter::emitN(JSOp op, size_t extra, BytecodeOffset* offset) {
343 MOZ_ASSERT(checkStrictOrSloppy(op));
344 ptrdiff_t length = 1 + ptrdiff_t(extra);
346 BytecodeOffset off;
347 if (!emitCheck(op, length, &off)) {
348 return false;
351 jsbytecode* code = bytecodeSection().code(off);
352 code[0] = jsbytecode(op);
353 /* The remaining |extra| bytes are set by the caller */
356 * Don't updateDepth if op's use-count comes from the immediate
357 * operand yet to be stored in the extra bytes after op.
359 if (CodeSpec(op).nuses >= 0) {
360 bytecodeSection().updateDepth(op, off);
363 if (offset) {
364 *offset = off;
366 return true;
369 bool BytecodeEmitter::emitJumpTargetOp(JSOp op, BytecodeOffset* off) {
370 MOZ_ASSERT(BytecodeIsJumpTarget(op));
372 // Record the current IC-entry index at start of this op.
373 uint32_t numEntries = bytecodeSection().numICEntries();
375 size_t n = GetOpLength(op) - 1;
376 MOZ_ASSERT(GetOpLength(op) >= 1 + ICINDEX_LEN);
378 if (!emitN(op, n, off)) {
379 return false;
382 SET_ICINDEX(bytecodeSection().code(*off), numEntries);
383 return true;
386 bool BytecodeEmitter::emitJumpTarget(JumpTarget* target) {
387 BytecodeOffset off = bytecodeSection().offset();
389 // Alias consecutive jump targets.
390 if (bytecodeSection().lastTargetOffset().valid() &&
391 off == bytecodeSection().lastTargetOffset() +
392 BytecodeOffsetDiff(JSOpLength_JumpTarget)) {
393 target->offset = bytecodeSection().lastTargetOffset();
394 return true;
397 target->offset = off;
398 bytecodeSection().setLastTargetOffset(off);
400 BytecodeOffset opOff;
401 return emitJumpTargetOp(JSOp::JumpTarget, &opOff);
404 bool BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump) {
405 BytecodeOffset offset;
406 if (!emitCheck(op, 5, &offset)) {
407 return false;
410 jsbytecode* code = bytecodeSection().code(offset);
411 code[0] = jsbytecode(op);
412 MOZ_ASSERT(!jump->offset.valid() ||
413 (0 <= jump->offset.value() && jump->offset < offset));
414 jump->push(bytecodeSection().code(BytecodeOffset(0)), offset);
415 bytecodeSection().updateDepth(op, offset);
416 return true;
419 bool BytecodeEmitter::emitJump(JSOp op, JumpList* jump) {
420 if (!emitJumpNoFallthrough(op, jump)) {
421 return false;
423 if (BytecodeFallsThrough(op)) {
424 JumpTarget fallthrough;
425 if (!emitJumpTarget(&fallthrough)) {
426 return false;
429 return true;
432 void BytecodeEmitter::patchJumpsToTarget(JumpList jump, JumpTarget target) {
433 MOZ_ASSERT(
434 !jump.offset.valid() ||
435 (0 <= jump.offset.value() && jump.offset <= bytecodeSection().offset()));
436 MOZ_ASSERT(0 <= target.offset.value() &&
437 target.offset <= bytecodeSection().offset());
438 MOZ_ASSERT_IF(
439 jump.offset.valid() &&
440 target.offset + BytecodeOffsetDiff(4) <= bytecodeSection().offset(),
441 BytecodeIsJumpTarget(JSOp(*bytecodeSection().code(target.offset))));
442 jump.patchAll(bytecodeSection().code(BytecodeOffset(0)), target);
445 bool BytecodeEmitter::emitJumpTargetAndPatch(JumpList jump) {
446 if (!jump.offset.valid()) {
447 return true;
449 JumpTarget target;
450 if (!emitJumpTarget(&target)) {
451 return false;
453 patchJumpsToTarget(jump, target);
454 return true;
457 bool BytecodeEmitter::emitCall(JSOp op, uint16_t argc,
458 const Maybe<uint32_t>& sourceCoordOffset) {
459 if (sourceCoordOffset.isSome()) {
460 if (!updateSourceCoordNotes(*sourceCoordOffset)) {
461 return false;
464 return emit3(op, ARGC_LO(argc), ARGC_HI(argc));
467 bool BytecodeEmitter::emitCall(JSOp op, uint16_t argc, ParseNode* pn) {
468 return emitCall(op, argc, pn ? Some(pn->pn_pos.begin) : Nothing());
471 bool BytecodeEmitter::emitDupAt(unsigned slotFromTop, unsigned count) {
472 MOZ_ASSERT(slotFromTop < unsigned(bytecodeSection().stackDepth()));
473 MOZ_ASSERT(slotFromTop + 1 >= count);
475 if (slotFromTop == 0 && count == 1) {
476 return emit1(JSOp::Dup);
479 if (slotFromTop == 1 && count == 2) {
480 return emit1(JSOp::Dup2);
483 if (slotFromTop >= Bit(24)) {
484 reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
485 return false;
488 for (unsigned i = 0; i < count; i++) {
489 BytecodeOffset off;
490 if (!emitN(JSOp::DupAt, 3, &off)) {
491 return false;
494 jsbytecode* pc = bytecodeSection().code(off);
495 SET_UINT24(pc, slotFromTop);
498 return true;
501 bool BytecodeEmitter::emitPopN(unsigned n) {
502 MOZ_ASSERT(n != 0);
504 if (n == 1) {
505 return emit1(JSOp::Pop);
508 // 2 JSOp::Pop instructions (2 bytes) are shorter than JSOp::PopN (3 bytes).
509 if (n == 2) {
510 return emit1(JSOp::Pop) && emit1(JSOp::Pop);
513 return emitUint16Operand(JSOp::PopN, n);
516 bool BytecodeEmitter::emitPickN(uint8_t n) {
517 MOZ_ASSERT(n != 0);
519 if (n == 1) {
520 return emit1(JSOp::Swap);
523 return emit2(JSOp::Pick, n);
526 bool BytecodeEmitter::emitUnpickN(uint8_t n) {
527 MOZ_ASSERT(n != 0);
529 if (n == 1) {
530 return emit1(JSOp::Swap);
533 return emit2(JSOp::Unpick, n);
536 bool BytecodeEmitter::emitCheckIsObj(CheckIsObjectKind kind) {
537 return emit2(JSOp::CheckIsObj, uint8_t(kind));
540 bool BytecodeEmitter::emitBuiltinObject(BuiltinObjectKind kind) {
541 return emit2(JSOp::BuiltinObject, uint8_t(kind));
544 /* Updates line number notes, not column notes. */
545 bool BytecodeEmitter::updateLineNumberNotes(uint32_t offset) {
546 if (skipLocationSrcNotes()) {
547 return true;
550 const ErrorReporter& er = errorReporter();
551 std::optional<bool> onThisLineStatus =
552 er.isOnThisLine(offset, bytecodeSection().currentLine());
553 if (!onThisLineStatus.has_value()) {
554 er.errorNoOffset(JSMSG_OUT_OF_MEMORY);
555 return false;
558 bool onThisLine = *onThisLineStatus;
560 if (!onThisLine) {
561 unsigned line = er.lineAt(offset);
562 unsigned delta = line - bytecodeSection().currentLine();
564 // If we use a `SetLine` note below, we want it to be relative to the
565 // scripts initial line number for better chance of sharing.
566 unsigned initialLine = sc->extent().lineno;
567 MOZ_ASSERT(line >= initialLine);
570 * Encode any change in the current source line number by using
571 * either several SrcNoteType::NewLine notes or just one
572 * SrcNoteType::SetLine note, whichever consumes less space.
574 * NB: We handle backward line number deltas (possible with for
575 * loops where the update part is emitted after the body, but its
576 * line number is <= any line number in the body) here by letting
577 * unsigned delta_ wrap to a very large number, which triggers a
578 * SrcNoteType::SetLine.
580 bytecodeSection().setCurrentLine(line, offset);
581 if (delta >= SrcNote::SetLine::lengthFor(line, initialLine)) {
582 if (!newSrcNote2(SrcNoteType::SetLine,
583 SrcNote::SetLine::toOperand(line, initialLine))) {
584 return false;
586 } else {
587 do {
588 if (!newSrcNote(SrcNoteType::NewLine)) {
589 return false;
591 } while (--delta != 0);
594 bytecodeSection().updateSeparatorPositionIfPresent();
596 return true;
599 /* Updates the line number and column number information in the source notes. */
600 bool BytecodeEmitter::updateSourceCoordNotes(uint32_t offset) {
601 if (skipLocationSrcNotes()) {
602 return true;
605 if (!updateLineNumberNotes(offset)) {
606 return false;
609 JS::LimitedColumnNumberOneOrigin columnIndex =
610 errorReporter().columnAt(offset);
612 // Assert colspan is always representable.
613 static_assert((0 - ptrdiff_t(JS::LimitedColumnNumberOneOrigin::Limit)) >=
614 SrcNote::ColSpan::MinColSpan);
615 static_assert((ptrdiff_t(JS::LimitedColumnNumberOneOrigin::Limit) - 0) <=
616 SrcNote::ColSpan::MaxColSpan);
618 JS::ColumnNumberOffset colspan = columnIndex - bytecodeSection().lastColumn();
620 if (colspan != JS::ColumnNumberOffset::zero()) {
621 if (lastLineOnlySrcNoteIndex != LastSrcNoteIsNotLineOnly) {
622 MOZ_ASSERT(bytecodeSection().lastColumn() ==
623 JS::LimitedColumnNumberOneOrigin());
625 const SrcNotesVector& notes = bytecodeSection().notes();
626 SrcNoteType type = notes[lastLineOnlySrcNoteIndex].type();
627 if (type == SrcNoteType::NewLine) {
628 if (!convertLastNewLineToNewLineColumn(columnIndex)) {
629 return false;
631 } else {
632 MOZ_ASSERT(type == SrcNoteType::SetLine);
633 if (!convertLastSetLineToSetLineColumn(columnIndex)) {
634 return false;
637 } else {
638 if (!newSrcNote2(SrcNoteType::ColSpan,
639 SrcNote::ColSpan::toOperand(colspan))) {
640 return false;
643 bytecodeSection().setLastColumn(columnIndex, offset);
644 bytecodeSection().updateSeparatorPositionIfPresent();
646 return true;
649 bool BytecodeEmitter::updateSourceCoordNotesIfNonLiteral(ParseNode* node) {
650 if (node->isLiteral()) {
651 return true;
653 return updateSourceCoordNotes(node->pn_pos.begin);
656 uint32_t BytecodeEmitter::getOffsetForLoop(ParseNode* nextpn) {
657 // Try to give the JSOp::LoopHead the same line number as the next
658 // instruction. nextpn is often a block, in which case the next instruction
659 // typically comes from the first statement inside.
660 if (nextpn->is<LexicalScopeNode>()) {
661 nextpn = nextpn->as<LexicalScopeNode>().scopeBody();
663 if (nextpn->isKind(ParseNodeKind::StatementList)) {
664 if (ParseNode* firstStatement = nextpn->as<ListNode>().head()) {
665 nextpn = firstStatement;
669 return nextpn->pn_pos.begin;
672 bool BytecodeEmitter::emitUint16Operand(JSOp op, uint32_t operand) {
673 MOZ_ASSERT(operand <= UINT16_MAX);
674 if (!emit3(op, UINT16_LO(operand), UINT16_HI(operand))) {
675 return false;
677 return true;
680 bool BytecodeEmitter::emitUint32Operand(JSOp op, uint32_t operand) {
681 BytecodeOffset off;
682 if (!emitN(op, 4, &off)) {
683 return false;
685 SET_UINT32(bytecodeSection().code(off), operand);
686 return true;
689 bool BytecodeEmitter::emitGoto(NestableControl* target, GotoKind kind) {
690 NonLocalExitControl nle(this, kind == GotoKind::Continue
691 ? NonLocalExitKind::Continue
692 : NonLocalExitKind::Break);
693 return nle.emitNonLocalJump(target);
696 AbstractScopePtr BytecodeEmitter::innermostScope() const {
697 return innermostEmitterScope()->scope(this);
700 ScopeIndex BytecodeEmitter::innermostScopeIndex() const {
701 return *innermostEmitterScope()->scopeIndex(this);
704 bool BytecodeEmitter::emitGCIndexOp(JSOp op, GCThingIndex index) {
705 MOZ_ASSERT(checkStrictOrSloppy(op));
707 constexpr size_t OpLength = 1 + GCTHING_INDEX_LEN;
708 MOZ_ASSERT(GetOpLength(op) == OpLength);
710 BytecodeOffset offset;
711 if (!emitCheck(op, OpLength, &offset)) {
712 return false;
715 jsbytecode* code = bytecodeSection().code(offset);
716 code[0] = jsbytecode(op);
717 SET_GCTHING_INDEX(code, index);
718 bytecodeSection().updateDepth(op, offset);
719 return true;
722 bool BytecodeEmitter::emitAtomOp(JSOp op, TaggedParserAtomIndex atom) {
723 MOZ_ASSERT(atom);
725 // .generator lookups should be emitted as JSOp::GetAliasedVar instead of
726 // JSOp::GetName etc, to bypass |with| objects on the scope chain.
727 // It's safe to emit .this lookups though because |with| objects skip
728 // those.
729 MOZ_ASSERT_IF(op == JSOp::GetName || op == JSOp::GetGName,
730 atom != TaggedParserAtomIndex::WellKnown::dot_generator_());
732 GCThingIndex index;
733 if (!makeAtomIndex(atom, ParserAtom::Atomize::Yes, &index)) {
734 return false;
737 return emitAtomOp(op, index);
740 bool BytecodeEmitter::emitAtomOp(JSOp op, GCThingIndex atomIndex) {
741 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
742 #ifdef DEBUG
743 auto atom = perScriptData().gcThingList().getAtom(atomIndex);
744 MOZ_ASSERT(compilationState.parserAtoms.isInstantiatedAsJSAtom(atom));
745 #endif
746 return emitGCIndexOp(op, atomIndex);
749 bool BytecodeEmitter::emitStringOp(JSOp op, TaggedParserAtomIndex atom) {
750 MOZ_ASSERT(atom);
751 GCThingIndex index;
752 if (!makeAtomIndex(atom, ParserAtom::Atomize::No, &index)) {
753 return false;
756 return emitStringOp(op, index);
759 bool BytecodeEmitter::emitStringOp(JSOp op, GCThingIndex atomIndex) {
760 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_STRING);
761 return emitGCIndexOp(op, atomIndex);
764 bool BytecodeEmitter::emitInternedScopeOp(GCThingIndex index, JSOp op) {
765 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_SCOPE);
766 MOZ_ASSERT(index < perScriptData().gcThingList().length());
767 return emitGCIndexOp(op, index);
770 bool BytecodeEmitter::emitInternedObjectOp(GCThingIndex index, JSOp op) {
771 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
772 MOZ_ASSERT(index < perScriptData().gcThingList().length());
773 return emitGCIndexOp(op, index);
776 bool BytecodeEmitter::emitRegExp(GCThingIndex index) {
777 return emitGCIndexOp(JSOp::RegExp, index);
780 bool BytecodeEmitter::emitLocalOp(JSOp op, uint32_t slot) {
781 MOZ_ASSERT(JOF_OPTYPE(op) != JOF_ENVCOORD);
782 MOZ_ASSERT(IsLocalOp(op));
784 BytecodeOffset off;
785 if (!emitN(op, LOCALNO_LEN, &off)) {
786 return false;
789 SET_LOCALNO(bytecodeSection().code(off), slot);
790 return true;
793 bool BytecodeEmitter::emitArgOp(JSOp op, uint16_t slot) {
794 MOZ_ASSERT(IsArgOp(op));
795 BytecodeOffset off;
796 if (!emitN(op, ARGNO_LEN, &off)) {
797 return false;
800 SET_ARGNO(bytecodeSection().code(off), slot);
801 return true;
804 bool BytecodeEmitter::emitEnvCoordOp(JSOp op, EnvironmentCoordinate ec) {
805 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ENVCOORD ||
806 JOF_OPTYPE(op) == JOF_DEBUGCOORD);
808 constexpr size_t N = ENVCOORD_HOPS_LEN + ENVCOORD_SLOT_LEN;
809 MOZ_ASSERT(GetOpLength(op) == 1 + N);
811 BytecodeOffset off;
812 if (!emitN(op, N, &off)) {
813 return false;
816 jsbytecode* pc = bytecodeSection().code(off);
817 SET_ENVCOORD_HOPS(pc, ec.hops());
818 pc += ENVCOORD_HOPS_LEN;
819 SET_ENVCOORD_SLOT(pc, ec.slot());
820 pc += ENVCOORD_SLOT_LEN;
821 return true;
824 JSOp BytecodeEmitter::strictifySetNameOp(JSOp op) {
825 switch (op) {
826 case JSOp::SetName:
827 if (sc->strict()) {
828 op = JSOp::StrictSetName;
830 break;
831 case JSOp::SetGName:
832 if (sc->strict()) {
833 op = JSOp::StrictSetGName;
835 break;
836 default:;
838 return op;
841 bool BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) {
842 AutoCheckRecursionLimit recursion(fc);
843 if (!recursion.check(fc)) {
844 return false;
847 restart:
849 switch (pn->getKind()) {
850 // Trivial cases with no side effects.
851 case ParseNodeKind::EmptyStmt:
852 case ParseNodeKind::TrueExpr:
853 case ParseNodeKind::FalseExpr:
854 case ParseNodeKind::NullExpr:
855 case ParseNodeKind::RawUndefinedExpr:
856 case ParseNodeKind::Elision:
857 case ParseNodeKind::Generator:
858 MOZ_ASSERT(pn->is<NullaryNode>());
859 *answer = false;
860 return true;
862 case ParseNodeKind::ObjectPropertyName:
863 case ParseNodeKind::PrivateName: // no side effects, unlike
864 // ParseNodeKind::Name
865 case ParseNodeKind::StringExpr:
866 case ParseNodeKind::TemplateStringExpr:
867 MOZ_ASSERT(pn->is<NameNode>());
868 *answer = false;
869 return true;
871 case ParseNodeKind::RegExpExpr:
872 MOZ_ASSERT(pn->is<RegExpLiteral>());
873 *answer = false;
874 return true;
876 case ParseNodeKind::NumberExpr:
877 MOZ_ASSERT(pn->is<NumericLiteral>());
878 *answer = false;
879 return true;
881 case ParseNodeKind::BigIntExpr:
882 MOZ_ASSERT(pn->is<BigIntLiteral>());
883 *answer = false;
884 return true;
886 // |this| can throw in derived class constructors, including nested arrow
887 // functions or eval.
888 case ParseNodeKind::ThisExpr:
889 MOZ_ASSERT(pn->is<UnaryNode>());
890 *answer = sc->needsThisTDZChecks();
891 return true;
893 // |new.target| doesn't have any side-effects.
894 case ParseNodeKind::NewTargetExpr: {
895 MOZ_ASSERT(pn->is<NewTargetNode>());
896 *answer = false;
897 return true;
900 // Trivial binary nodes with more token pos holders.
901 case ParseNodeKind::ImportMetaExpr: {
902 MOZ_ASSERT(pn->as<BinaryNode>().left()->isKind(ParseNodeKind::PosHolder));
903 MOZ_ASSERT(
904 pn->as<BinaryNode>().right()->isKind(ParseNodeKind::PosHolder));
905 *answer = false;
906 return true;
909 case ParseNodeKind::BreakStmt:
910 MOZ_ASSERT(pn->is<BreakStatement>());
911 *answer = true;
912 return true;
914 case ParseNodeKind::ContinueStmt:
915 MOZ_ASSERT(pn->is<ContinueStatement>());
916 *answer = true;
917 return true;
919 case ParseNodeKind::DebuggerStmt:
920 MOZ_ASSERT(pn->is<DebuggerStatement>());
921 *answer = true;
922 return true;
924 // Watch out for getters!
925 case ParseNodeKind::OptionalDotExpr:
926 case ParseNodeKind::DotExpr:
927 MOZ_ASSERT(pn->is<BinaryNode>());
928 *answer = true;
929 return true;
931 // Unary cases with side effects only if the child has them.
932 case ParseNodeKind::TypeOfExpr:
933 case ParseNodeKind::VoidExpr:
934 case ParseNodeKind::NotExpr:
935 return checkSideEffects(pn->as<UnaryNode>().kid(), answer);
937 // Even if the name expression is effect-free, performing ToPropertyKey on
938 // it might not be effect-free:
940 // RegExp.prototype.toString = () => { throw 42; };
941 // ({ [/regex/]: 0 }); // ToPropertyKey(/regex/) throws 42
943 // function Q() {
944 // ({ [new.target]: 0 });
945 // }
946 // Q.toString = () => { throw 17; };
947 // new Q; // new.target will be Q, ToPropertyKey(Q) throws 17
948 case ParseNodeKind::ComputedName:
949 MOZ_ASSERT(pn->is<UnaryNode>());
950 *answer = true;
951 return true;
953 // Looking up or evaluating the associated name could throw.
954 case ParseNodeKind::TypeOfNameExpr:
955 MOZ_ASSERT(pn->is<UnaryNode>());
956 *answer = true;
957 return true;
959 // This unary case has side effects on the enclosing object, sure. But
960 // that's not the question this function answers: it's whether the
961 // operation may have a side effect on something *other* than the result
962 // of the overall operation in which it's embedded. The answer to that
963 // is no, because an object literal having a mutated prototype only
964 // produces a value, without affecting anything else.
965 case ParseNodeKind::MutateProto:
966 return checkSideEffects(pn->as<UnaryNode>().kid(), answer);
968 // Unary cases with obvious side effects.
969 case ParseNodeKind::PreIncrementExpr:
970 case ParseNodeKind::PostIncrementExpr:
971 case ParseNodeKind::PreDecrementExpr:
972 case ParseNodeKind::PostDecrementExpr:
973 case ParseNodeKind::ThrowStmt:
974 MOZ_ASSERT(pn->is<UnaryNode>());
975 *answer = true;
976 return true;
978 // These might invoke valueOf/toString, even with a subexpression without
979 // side effects! Consider |+{ valueOf: null, toString: null }|.
980 case ParseNodeKind::BitNotExpr:
981 case ParseNodeKind::PosExpr:
982 case ParseNodeKind::NegExpr:
983 MOZ_ASSERT(pn->is<UnaryNode>());
984 *answer = true;
985 return true;
987 // This invokes the (user-controllable) iterator protocol.
988 case ParseNodeKind::Spread:
989 MOZ_ASSERT(pn->is<UnaryNode>());
990 *answer = true;
991 return true;
993 case ParseNodeKind::InitialYield:
994 case ParseNodeKind::YieldStarExpr:
995 case ParseNodeKind::YieldExpr:
996 case ParseNodeKind::AwaitExpr:
997 MOZ_ASSERT(pn->is<UnaryNode>());
998 *answer = true;
999 return true;
1001 // Deletion generally has side effects, even if isolated cases have none.
1002 case ParseNodeKind::DeleteNameExpr:
1003 case ParseNodeKind::DeletePropExpr:
1004 case ParseNodeKind::DeleteElemExpr:
1005 case ParseNodeKind::DeleteOptionalChainExpr:
1006 MOZ_ASSERT(pn->is<UnaryNode>());
1007 *answer = true;
1008 return true;
1010 // Deletion of a non-Reference expression has side effects only through
1011 // evaluating the expression.
1012 case ParseNodeKind::DeleteExpr: {
1013 ParseNode* expr = pn->as<UnaryNode>().kid();
1014 return checkSideEffects(expr, answer);
1017 case ParseNodeKind::ExpressionStmt:
1018 return checkSideEffects(pn->as<UnaryNode>().kid(), answer);
1020 // Binary cases with obvious side effects.
1021 case ParseNodeKind::InitExpr:
1022 *answer = true;
1023 return true;
1025 case ParseNodeKind::AssignExpr:
1026 case ParseNodeKind::AddAssignExpr:
1027 case ParseNodeKind::SubAssignExpr:
1028 case ParseNodeKind::CoalesceAssignExpr:
1029 case ParseNodeKind::OrAssignExpr:
1030 case ParseNodeKind::AndAssignExpr:
1031 case ParseNodeKind::BitOrAssignExpr:
1032 case ParseNodeKind::BitXorAssignExpr:
1033 case ParseNodeKind::BitAndAssignExpr:
1034 case ParseNodeKind::LshAssignExpr:
1035 case ParseNodeKind::RshAssignExpr:
1036 case ParseNodeKind::UrshAssignExpr:
1037 case ParseNodeKind::MulAssignExpr:
1038 case ParseNodeKind::DivAssignExpr:
1039 case ParseNodeKind::ModAssignExpr:
1040 case ParseNodeKind::PowAssignExpr:
1041 MOZ_ASSERT(pn->is<AssignmentNode>());
1042 *answer = true;
1043 return true;
1045 case ParseNodeKind::SetThis:
1046 MOZ_ASSERT(pn->is<BinaryNode>());
1047 *answer = true;
1048 return true;
1050 case ParseNodeKind::StatementList:
1051 // Strict equality operations and short circuit operators are well-behaved
1052 // and perform no conversions.
1053 case ParseNodeKind::CoalesceExpr:
1054 case ParseNodeKind::OrExpr:
1055 case ParseNodeKind::AndExpr:
1056 case ParseNodeKind::StrictEqExpr:
1057 case ParseNodeKind::StrictNeExpr:
1058 // Any subexpression of a comma expression could be effectful.
1059 case ParseNodeKind::CommaExpr:
1060 MOZ_ASSERT(!pn->as<ListNode>().empty());
1061 [[fallthrough]];
1062 // Subcomponents of a literal may be effectful.
1063 case ParseNodeKind::ArrayExpr:
1064 case ParseNodeKind::ObjectExpr:
1065 for (ParseNode* item : pn->as<ListNode>().contents()) {
1066 if (!checkSideEffects(item, answer)) {
1067 return false;
1069 if (*answer) {
1070 return true;
1073 return true;
1075 #ifdef ENABLE_RECORD_TUPLE
1076 case ParseNodeKind::RecordExpr:
1077 case ParseNodeKind::TupleExpr:
1078 MOZ_CRASH("Record and Tuple are not supported yet");
1079 #endif
1081 #ifdef ENABLE_DECORATORS
1082 case ParseNodeKind::DecoratorList:
1083 MOZ_CRASH("Decorators are not supported yet");
1084 #endif
1086 // Most other binary operations (parsed as lists in SpiderMonkey) may
1087 // perform conversions triggering side effects. Math operations perform
1088 // ToNumber and may fail invoking invalid user-defined toString/valueOf:
1089 // |5 < { toString: null }|. |instanceof| throws if provided a
1090 // non-object constructor: |null instanceof null|. |in| throws if given
1091 // a non-object RHS: |5 in null|.
1092 case ParseNodeKind::BitOrExpr:
1093 case ParseNodeKind::BitXorExpr:
1094 case ParseNodeKind::BitAndExpr:
1095 case ParseNodeKind::EqExpr:
1096 case ParseNodeKind::NeExpr:
1097 case ParseNodeKind::LtExpr:
1098 case ParseNodeKind::LeExpr:
1099 case ParseNodeKind::GtExpr:
1100 case ParseNodeKind::GeExpr:
1101 case ParseNodeKind::InstanceOfExpr:
1102 case ParseNodeKind::InExpr:
1103 case ParseNodeKind::PrivateInExpr:
1104 case ParseNodeKind::LshExpr:
1105 case ParseNodeKind::RshExpr:
1106 case ParseNodeKind::UrshExpr:
1107 case ParseNodeKind::AddExpr:
1108 case ParseNodeKind::SubExpr:
1109 case ParseNodeKind::MulExpr:
1110 case ParseNodeKind::DivExpr:
1111 case ParseNodeKind::ModExpr:
1112 case ParseNodeKind::PowExpr:
1113 MOZ_ASSERT(pn->as<ListNode>().count() >= 2);
1114 *answer = true;
1115 return true;
1117 case ParseNodeKind::PropertyDefinition:
1118 case ParseNodeKind::Case: {
1119 BinaryNode* node = &pn->as<BinaryNode>();
1120 if (!checkSideEffects(node->left(), answer)) {
1121 return false;
1123 if (*answer) {
1124 return true;
1126 return checkSideEffects(node->right(), answer);
1129 // More getters.
1130 case ParseNodeKind::ElemExpr:
1131 case ParseNodeKind::OptionalElemExpr:
1132 MOZ_ASSERT(pn->is<BinaryNode>());
1133 *answer = true;
1134 return true;
1136 // Throws if the operand is not of the right class. Can also call a private
1137 // getter.
1138 case ParseNodeKind::PrivateMemberExpr:
1139 case ParseNodeKind::OptionalPrivateMemberExpr:
1140 *answer = true;
1141 return true;
1143 // These affect visible names in this code, or in other code.
1144 case ParseNodeKind::ImportDecl:
1145 case ParseNodeKind::ExportFromStmt:
1146 case ParseNodeKind::ExportDefaultStmt:
1147 MOZ_ASSERT(pn->is<BinaryNode>());
1148 *answer = true;
1149 return true;
1151 // Likewise.
1152 case ParseNodeKind::ExportStmt:
1153 MOZ_ASSERT(pn->is<UnaryNode>());
1154 *answer = true;
1155 return true;
1157 case ParseNodeKind::CallImportExpr:
1158 case ParseNodeKind::CallImportSpec:
1159 MOZ_ASSERT(pn->is<BinaryNode>());
1160 *answer = true;
1161 return true;
1163 // Every part of a loop might be effect-free, but looping infinitely *is*
1164 // an effect. (Language lawyer trivia: C++ says threads can be assumed
1165 // to exit or have side effects, C++14 [intro.multithread]p27, so a C++
1166 // implementation's equivalent of the below could set |*answer = false;|
1167 // if all loop sub-nodes set |*answer = false|!)
1168 case ParseNodeKind::DoWhileStmt:
1169 case ParseNodeKind::WhileStmt:
1170 case ParseNodeKind::ForStmt:
1171 MOZ_ASSERT(pn->is<BinaryNode>());
1172 *answer = true;
1173 return true;
1175 // Declarations affect the name set of the relevant scope.
1176 case ParseNodeKind::VarStmt:
1177 case ParseNodeKind::ConstDecl:
1178 case ParseNodeKind::LetDecl:
1179 MOZ_ASSERT(pn->is<ListNode>());
1180 *answer = true;
1181 return true;
1183 case ParseNodeKind::IfStmt:
1184 case ParseNodeKind::ConditionalExpr: {
1185 TernaryNode* node = &pn->as<TernaryNode>();
1186 if (!checkSideEffects(node->kid1(), answer)) {
1187 return false;
1189 if (*answer) {
1190 return true;
1192 if (!checkSideEffects(node->kid2(), answer)) {
1193 return false;
1195 if (*answer) {
1196 return true;
1198 if ((pn = node->kid3())) {
1199 goto restart;
1201 return true;
1204 // Function calls can invoke non-local code.
1205 case ParseNodeKind::NewExpr:
1206 case ParseNodeKind::CallExpr:
1207 case ParseNodeKind::OptionalCallExpr:
1208 case ParseNodeKind::TaggedTemplateExpr:
1209 case ParseNodeKind::SuperCallExpr:
1210 MOZ_ASSERT(pn->is<BinaryNode>());
1211 *answer = true;
1212 return true;
1214 // Function arg lists can contain arbitrary expressions. Technically
1215 // this only causes side-effects if one of the arguments does, but since
1216 // the call being made will always trigger side-effects, it isn't needed.
1217 case ParseNodeKind::Arguments:
1218 MOZ_ASSERT(pn->is<ListNode>());
1219 *answer = true;
1220 return true;
1222 case ParseNodeKind::OptionalChain:
1223 MOZ_ASSERT(pn->is<UnaryNode>());
1224 *answer = true;
1225 return true;
1227 // Classes typically introduce names. Even if no name is introduced,
1228 // the heritage and/or class body (through computed property names)
1229 // usually have effects.
1230 case ParseNodeKind::ClassDecl:
1231 MOZ_ASSERT(pn->is<ClassNode>());
1232 *answer = true;
1233 return true;
1235 // |with| calls |ToObject| on its expression and so throws if that value
1236 // is null/undefined.
1237 case ParseNodeKind::WithStmt:
1238 MOZ_ASSERT(pn->is<BinaryNode>());
1239 *answer = true;
1240 return true;
1242 case ParseNodeKind::ReturnStmt:
1243 MOZ_ASSERT(pn->is<BinaryNode>());
1244 *answer = true;
1245 return true;
1247 case ParseNodeKind::Name:
1248 MOZ_ASSERT(pn->is<NameNode>());
1249 *answer = true;
1250 return true;
1252 // Shorthands could trigger getters: the |x| in the object literal in
1253 // |with ({ get x() { throw 42; } }) ({ x });|, for example, triggers
1254 // one. (Of course, it isn't necessary to use |with| for a shorthand to
1255 // trigger a getter.)
1256 case ParseNodeKind::Shorthand:
1257 MOZ_ASSERT(pn->is<BinaryNode>());
1258 *answer = true;
1259 return true;
1261 case ParseNodeKind::Function:
1262 MOZ_ASSERT(pn->is<FunctionNode>());
1264 * A named function, contrary to ES3, is no longer effectful, because
1265 * we bind its name lexically (using JSOp::Callee) instead of creating
1266 * an Object instance and binding a readonly, permanent property in it
1267 * (the object and binding can be detected and hijacked or captured).
1268 * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
1270 *answer = false;
1271 return true;
1273 case ParseNodeKind::Module:
1274 *answer = false;
1275 return true;
1277 case ParseNodeKind::TryStmt: {
1278 TryNode* tryNode = &pn->as<TryNode>();
1279 if (!checkSideEffects(tryNode->body(), answer)) {
1280 return false;
1282 if (*answer) {
1283 return true;
1285 if (LexicalScopeNode* catchScope = tryNode->catchScope()) {
1286 if (!checkSideEffects(catchScope, answer)) {
1287 return false;
1289 if (*answer) {
1290 return true;
1293 if (ParseNode* finallyBlock = tryNode->finallyBlock()) {
1294 if (!checkSideEffects(finallyBlock, answer)) {
1295 return false;
1298 return true;
1301 case ParseNodeKind::Catch: {
1302 BinaryNode* catchClause = &pn->as<BinaryNode>();
1303 if (ParseNode* name = catchClause->left()) {
1304 if (!checkSideEffects(name, answer)) {
1305 return false;
1307 if (*answer) {
1308 return true;
1311 return checkSideEffects(catchClause->right(), answer);
1314 case ParseNodeKind::SwitchStmt: {
1315 SwitchStatement* switchStmt = &pn->as<SwitchStatement>();
1316 if (!checkSideEffects(&switchStmt->discriminant(), answer)) {
1317 return false;
1319 return *answer ||
1320 checkSideEffects(&switchStmt->lexicalForCaseList(), answer);
1323 case ParseNodeKind::LabelStmt:
1324 return checkSideEffects(pn->as<LabeledStatement>().statement(), answer);
1326 case ParseNodeKind::LexicalScope:
1327 return checkSideEffects(pn->as<LexicalScopeNode>().scopeBody(), answer);
1329 // We could methodically check every interpolated expression, but it's
1330 // probably not worth the trouble. Treat template strings as effect-free
1331 // only if they don't contain any substitutions.
1332 case ParseNodeKind::TemplateStringListExpr: {
1333 ListNode* list = &pn->as<ListNode>();
1334 MOZ_ASSERT(!list->empty());
1335 MOZ_ASSERT((list->count() % 2) == 1,
1336 "template strings must alternate template and substitution "
1337 "parts");
1338 *answer = list->count() > 1;
1339 return true;
1342 // This should be unreachable but is left as-is for now.
1343 case ParseNodeKind::ParamsBody:
1344 *answer = true;
1345 return true;
1347 case ParseNodeKind::ForIn: // by ParseNodeKind::For
1348 case ParseNodeKind::ForOf: // by ParseNodeKind::For
1349 case ParseNodeKind::ForHead: // by ParseNodeKind::For
1350 case ParseNodeKind::DefaultConstructor: // by ParseNodeKind::ClassDecl
1351 case ParseNodeKind::ClassBodyScope: // by ParseNodeKind::ClassDecl
1352 case ParseNodeKind::ClassMethod: // by ParseNodeKind::ClassDecl
1353 case ParseNodeKind::ClassField: // by ParseNodeKind::ClassDecl
1354 case ParseNodeKind::ClassNames: // by ParseNodeKind::ClassDecl
1355 case ParseNodeKind::StaticClassBlock: // by ParseNodeKind::ClassDecl
1356 case ParseNodeKind::ClassMemberList: // by ParseNodeKind::ClassDecl
1357 case ParseNodeKind::ImportSpecList: // by ParseNodeKind::Import
1358 case ParseNodeKind::ImportSpec: // by ParseNodeKind::Import
1359 case ParseNodeKind::ImportNamespaceSpec: // by ParseNodeKind::Import
1360 case ParseNodeKind::ImportAssertion: // by ParseNodeKind::Import
1361 case ParseNodeKind::ImportAssertionList: // by ParseNodeKind::Import
1362 case ParseNodeKind::ImportModuleRequest: // by ParseNodeKind::Import
1363 case ParseNodeKind::ExportBatchSpecStmt: // by ParseNodeKind::Export
1364 case ParseNodeKind::ExportSpecList: // by ParseNodeKind::Export
1365 case ParseNodeKind::ExportSpec: // by ParseNodeKind::Export
1366 case ParseNodeKind::ExportNamespaceSpec: // by ParseNodeKind::Export
1367 case ParseNodeKind::CallSiteObj: // by ParseNodeKind::TaggedTemplate
1368 case ParseNodeKind::PosHolder: // by ParseNodeKind::NewTarget
1369 case ParseNodeKind::SuperBase: // by ParseNodeKind::Elem and others
1370 case ParseNodeKind::PropertyNameExpr: // by ParseNodeKind::Dot
1371 MOZ_CRASH("handled by parent nodes");
1373 case ParseNodeKind::LastUnused:
1374 case ParseNodeKind::Limit:
1375 MOZ_CRASH("invalid node kind");
1378 MOZ_CRASH(
1379 "invalid, unenumerated ParseNodeKind value encountered in "
1380 "BytecodeEmitter::checkSideEffects");
1383 bool BytecodeEmitter::isInLoop() {
1384 return findInnermostNestableControl<LoopControl>();
1387 bool BytecodeEmitter::checkSingletonContext() {
1388 MOZ_ASSERT_IF(sc->treatAsRunOnce(), sc->isTopLevelContext());
1389 return sc->treatAsRunOnce() && !isInLoop();
1392 bool BytecodeEmitter::needsImplicitThis() {
1393 // Short-circuit if there is an enclosing 'with' scope.
1394 if (sc->inWith()) {
1395 return true;
1398 // Otherwise see if the current point is under a 'with'.
1399 for (EmitterScope* es = innermostEmitterScope(); es;
1400 es = es->enclosingInFrame()) {
1401 if (es->scope(this).kind() == ScopeKind::With) {
1402 return true;
1406 return false;
1409 size_t BytecodeEmitter::countThisEnvironmentHops() {
1410 unsigned numHops = 0;
1412 for (BytecodeEmitter* current = this; current; current = current->parent) {
1413 for (EmitterScope* es = current->innermostEmitterScope(); es;
1414 es = es->enclosingInFrame()) {
1415 if (es->scope(current).is<FunctionScope>()) {
1416 if (!es->scope(current).isArrow()) {
1417 // The Parser is responsible for marking the environment as either
1418 // closed-over or used-by-eval which ensure that is must exist.
1419 MOZ_ASSERT(es->scope(current).hasEnvironment());
1420 return numHops;
1423 if (es->scope(current).hasEnvironment()) {
1424 numHops++;
1429 // The "this" environment exists outside of the compilation, but the
1430 // `ScopeContext` recorded the number of additional hops needed, so add
1431 // those in now.
1432 MOZ_ASSERT(sc->allowSuperProperty());
1433 numHops += compilationState.scopeContext.enclosingThisEnvironmentHops;
1434 return numHops;
1437 bool BytecodeEmitter::emitThisEnvironmentCallee() {
1438 // Get the innermost enclosing function that has a |this| binding.
1440 // Directly load callee from the frame if possible.
1441 if (sc->isFunctionBox() && !sc->asFunctionBox()->isArrow()) {
1442 return emit1(JSOp::Callee);
1445 // We have to load the callee from the environment chain.
1446 size_t numHops = countThisEnvironmentHops();
1448 static_assert(
1449 ENVCOORD_HOPS_LIMIT - 1 <= UINT8_MAX,
1450 "JSOp::EnvCallee operand size should match ENVCOORD_HOPS_LIMIT");
1452 MOZ_ASSERT(numHops < ENVCOORD_HOPS_LIMIT - 1);
1454 return emit2(JSOp::EnvCallee, numHops);
1457 bool BytecodeEmitter::emitSuperBase() {
1458 if (!emitThisEnvironmentCallee()) {
1459 return false;
1462 return emit1(JSOp::SuperBase);
1465 void BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...) {
1466 uint32_t offset = pn ? pn->pn_pos.begin : *scriptStartOffset;
1468 va_list args;
1469 va_start(args, errorNumber);
1471 errorReporter().errorWithNotesAtVA(nullptr, AsVariant(offset), errorNumber,
1472 &args);
1474 va_end(args);
1477 void BytecodeEmitter::reportError(uint32_t offset, unsigned errorNumber, ...) {
1478 va_list args;
1479 va_start(args, errorNumber);
1481 errorReporter().errorWithNotesAtVA(nullptr, AsVariant(offset), errorNumber,
1482 &args);
1484 va_end(args);
1487 bool BytecodeEmitter::addObjLiteralData(ObjLiteralWriter& writer,
1488 GCThingIndex* outIndex) {
1489 if (!writer.checkForDuplicatedNames(fc)) {
1490 return false;
1493 size_t len = writer.getCode().size();
1494 auto* code = compilationState.alloc.newArrayUninitialized<uint8_t>(len);
1495 if (!code) {
1496 js::ReportOutOfMemory(fc);
1497 return false;
1499 memcpy(code, writer.getCode().data(), len);
1501 ObjLiteralIndex objIndex(compilationState.objLiteralData.length());
1502 if (uint32_t(objIndex) >= TaggedScriptThingIndex::IndexLimit) {
1503 ReportAllocationOverflow(fc);
1504 return false;
1506 if (!compilationState.objLiteralData.emplaceBack(code, len, writer.getKind(),
1507 writer.getFlags(),
1508 writer.getPropertyCount())) {
1509 js::ReportOutOfMemory(fc);
1510 return false;
1513 return perScriptData().gcThingList().append(objIndex, outIndex);
1516 bool BytecodeEmitter::emitPrepareIteratorResult() {
1517 constexpr JSOp op = JSOp::NewObject;
1519 ObjLiteralWriter writer;
1520 writer.beginShape(op);
1522 writer.setPropNameNoDuplicateCheck(parserAtoms(),
1523 TaggedParserAtomIndex::WellKnown::value());
1524 if (!writer.propWithUndefinedValue(fc)) {
1525 return false;
1527 writer.setPropNameNoDuplicateCheck(parserAtoms(),
1528 TaggedParserAtomIndex::WellKnown::done());
1529 if (!writer.propWithUndefinedValue(fc)) {
1530 return false;
1533 GCThingIndex shape;
1534 if (!addObjLiteralData(writer, &shape)) {
1535 return false;
1538 return emitGCIndexOp(op, shape);
1541 bool BytecodeEmitter::emitFinishIteratorResult(bool done) {
1542 if (!emitAtomOp(JSOp::InitProp, TaggedParserAtomIndex::WellKnown::value())) {
1543 return false;
1545 if (!emit1(done ? JSOp::True : JSOp::False)) {
1546 return false;
1548 if (!emitAtomOp(JSOp::InitProp, TaggedParserAtomIndex::WellKnown::done())) {
1549 return false;
1551 return true;
1554 bool BytecodeEmitter::emitGetNameAtLocation(TaggedParserAtomIndex name,
1555 const NameLocation& loc) {
1556 NameOpEmitter noe(this, name, loc, NameOpEmitter::Kind::Get);
1557 if (!noe.emitGet()) {
1558 return false;
1561 return true;
1564 bool BytecodeEmitter::emitGetName(NameNode* name) {
1565 MOZ_ASSERT(name->isKind(ParseNodeKind::Name));
1567 return emitGetName(name->name());
1570 bool BytecodeEmitter::emitGetPrivateName(NameNode* name) {
1571 MOZ_ASSERT(name->isKind(ParseNodeKind::PrivateName));
1572 return emitGetPrivateName(name->name());
1575 bool BytecodeEmitter::emitGetPrivateName(TaggedParserAtomIndex nameAtom) {
1576 // The parser ensures the private name is present on the environment chain,
1577 // but its location can be Dynamic or Global when emitting debugger
1578 // eval-in-frame code.
1579 NameLocation location = lookupName(nameAtom);
1580 MOZ_ASSERT(location.kind() == NameLocation::Kind::FrameSlot ||
1581 location.kind() == NameLocation::Kind::EnvironmentCoordinate ||
1582 location.kind() == NameLocation::Kind::Dynamic ||
1583 location.kind() == NameLocation::Kind::Global);
1585 return emitGetNameAtLocation(nameAtom, location);
1588 bool BytecodeEmitter::emitTDZCheckIfNeeded(TaggedParserAtomIndex name,
1589 const NameLocation& loc,
1590 ValueIsOnStack isOnStack) {
1591 // Dynamic accesses have TDZ checks built into their VM code and should
1592 // never emit explicit TDZ checks.
1593 MOZ_ASSERT(loc.hasKnownSlot());
1594 MOZ_ASSERT(loc.isLexical() || loc.isPrivateMethod() || loc.isSynthetic());
1596 // Private names are implemented as lexical bindings, but it's just an
1597 // implementation detail. Per spec there's no TDZ check when using them.
1598 if (parserAtoms().isPrivateName(name)) {
1599 return true;
1602 Maybe<MaybeCheckTDZ> check =
1603 innermostTDZCheckCache->needsTDZCheck(this, name);
1604 if (!check) {
1605 return false;
1608 // We've already emitted a check in this basic block.
1609 if (*check == DontCheckTDZ) {
1610 return true;
1613 // If the value is not on the stack, we have to load it first.
1614 if (isOnStack == ValueIsOnStack::No) {
1615 if (loc.kind() == NameLocation::Kind::FrameSlot) {
1616 if (!emitLocalOp(JSOp::GetLocal, loc.frameSlot())) {
1617 return false;
1619 } else {
1620 if (!emitEnvCoordOp(JSOp::GetAliasedVar, loc.environmentCoordinate())) {
1621 return false;
1626 // Emit the lexical check.
1627 if (loc.kind() == NameLocation::Kind::FrameSlot) {
1628 if (!emitLocalOp(JSOp::CheckLexical, loc.frameSlot())) {
1629 return false;
1631 } else {
1632 if (!emitEnvCoordOp(JSOp::CheckAliasedLexical,
1633 loc.environmentCoordinate())) {
1634 return false;
1638 // Pop the value if needed.
1639 if (isOnStack == ValueIsOnStack::No) {
1640 if (!emit1(JSOp::Pop)) {
1641 return false;
1645 return innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ);
1648 bool BytecodeEmitter::emitPropLHS(PropertyAccess* prop) {
1649 MOZ_ASSERT(!prop->isSuper());
1651 ParseNode* expr = &prop->expression();
1653 if (!expr->is<PropertyAccess>() || expr->as<PropertyAccess>().isSuper()) {
1654 // The non-optimized case.
1655 return emitTree(expr);
1658 // If the object operand is also a dotted property reference, reverse the
1659 // list linked via expression() temporarily so we can iterate over it from
1660 // the bottom up (reversing again as we go), to avoid excessive recursion.
1661 PropertyAccess* pndot = &expr->as<PropertyAccess>();
1662 ParseNode* pnup = nullptr;
1663 ParseNode* pndown;
1664 for (;;) {
1665 // Reverse pndot->expression() to point up, not down.
1666 pndown = &pndot->expression();
1667 pndot->setExpression(pnup);
1668 if (!pndown->is<PropertyAccess>() ||
1669 pndown->as<PropertyAccess>().isSuper()) {
1670 break;
1672 pnup = pndot;
1673 pndot = &pndown->as<PropertyAccess>();
1676 // pndown is a primary expression, not a dotted property reference.
1677 if (!emitTree(pndown)) {
1678 return false;
1681 while (true) {
1682 // Walk back up the list, emitting annotated name ops.
1683 if (!emitAtomOp(JSOp::GetProp, pndot->key().atom())) {
1684 return false;
1687 // Reverse the pndot->expression() link again.
1688 pnup = pndot->maybeExpression();
1689 pndot->setExpression(pndown);
1690 pndown = pndot;
1691 if (!pnup) {
1692 break;
1694 pndot = &pnup->as<PropertyAccess>();
1696 return true;
1699 bool BytecodeEmitter::emitPropIncDec(UnaryNode* incDec, ValueUsage valueUsage) {
1700 PropertyAccess* prop = &incDec->kid()->as<PropertyAccess>();
1701 bool isSuper = prop->isSuper();
1702 ParseNodeKind kind = incDec->getKind();
1703 PropOpEmitter poe(
1704 this,
1705 kind == ParseNodeKind::PostIncrementExpr
1706 ? PropOpEmitter::Kind::PostIncrement
1707 : kind == ParseNodeKind::PreIncrementExpr
1708 ? PropOpEmitter::Kind::PreIncrement
1709 : kind == ParseNodeKind::PostDecrementExpr
1710 ? PropOpEmitter::Kind::PostDecrement
1711 : PropOpEmitter::Kind::PreDecrement,
1712 isSuper ? PropOpEmitter::ObjKind::Super : PropOpEmitter::ObjKind::Other);
1713 if (!poe.prepareForObj()) {
1714 return false;
1716 if (isSuper) {
1717 UnaryNode* base = &prop->expression().as<UnaryNode>();
1718 if (!emitGetThisForSuperBase(base)) {
1719 // [stack] THIS
1720 return false;
1722 } else {
1723 if (!emitPropLHS(prop)) {
1724 // [stack] OBJ
1725 return false;
1728 if (!poe.emitIncDec(prop->key().atom(), valueUsage)) {
1729 // [stack] RESULT
1730 return false;
1733 return true;
1736 bool BytecodeEmitter::emitNameIncDec(UnaryNode* incDec, ValueUsage valueUsage) {
1737 MOZ_ASSERT(incDec->kid()->isKind(ParseNodeKind::Name));
1739 ParseNodeKind kind = incDec->getKind();
1740 NameNode* name = &incDec->kid()->as<NameNode>();
1741 NameOpEmitter noe(this, name->atom(),
1742 kind == ParseNodeKind::PostIncrementExpr
1743 ? NameOpEmitter::Kind::PostIncrement
1744 : kind == ParseNodeKind::PreIncrementExpr
1745 ? NameOpEmitter::Kind::PreIncrement
1746 : kind == ParseNodeKind::PostDecrementExpr
1747 ? NameOpEmitter::Kind::PostDecrement
1748 : NameOpEmitter::Kind::PreDecrement);
1749 if (!noe.emitIncDec(valueUsage)) {
1750 return false;
1753 return true;
1756 bool BytecodeEmitter::emitObjAndKey(ParseNode* exprOrSuper, ParseNode* key,
1757 ElemOpEmitter& eoe) {
1758 if (exprOrSuper->isKind(ParseNodeKind::SuperBase)) {
1759 if (!eoe.prepareForObj()) {
1760 // [stack]
1761 return false;
1763 UnaryNode* base = &exprOrSuper->as<UnaryNode>();
1764 if (!emitGetThisForSuperBase(base)) {
1765 // [stack] THIS
1766 return false;
1768 if (!eoe.prepareForKey()) {
1769 // [stack] THIS
1770 return false;
1772 if (!emitTree(key)) {
1773 // [stack] THIS KEY
1774 return false;
1777 return true;
1780 if (!eoe.prepareForObj()) {
1781 // [stack]
1782 return false;
1784 if (!emitTree(exprOrSuper)) {
1785 // [stack] OBJ
1786 return false;
1788 if (!eoe.prepareForKey()) {
1789 // [stack] OBJ? OBJ
1790 return false;
1792 if (!emitTree(key)) {
1793 // [stack] OBJ? OBJ KEY
1794 return false;
1797 return true;
1800 bool BytecodeEmitter::emitElemOpBase(JSOp op) {
1801 if (!emit1(op)) {
1802 return false;
1805 return true;
1808 bool BytecodeEmitter::emitElemObjAndKey(PropertyByValue* elem, bool isSuper,
1809 ElemOpEmitter& eoe) {
1810 MOZ_ASSERT(isSuper == elem->expression().isKind(ParseNodeKind::SuperBase));
1811 return emitObjAndKey(&elem->expression(), &elem->key(), eoe);
1814 static ElemOpEmitter::Kind ConvertIncDecKind(ParseNodeKind kind) {
1815 switch (kind) {
1816 case ParseNodeKind::PostIncrementExpr:
1817 return ElemOpEmitter::Kind::PostIncrement;
1818 case ParseNodeKind::PreIncrementExpr:
1819 return ElemOpEmitter::Kind::PreIncrement;
1820 case ParseNodeKind::PostDecrementExpr:
1821 return ElemOpEmitter::Kind::PostDecrement;
1822 case ParseNodeKind::PreDecrementExpr:
1823 return ElemOpEmitter::Kind::PreDecrement;
1824 default:
1825 MOZ_CRASH("unexpected inc/dec node kind");
1829 static PrivateOpEmitter::Kind PrivateConvertIncDecKind(ParseNodeKind kind) {
1830 switch (kind) {
1831 case ParseNodeKind::PostIncrementExpr:
1832 return PrivateOpEmitter::Kind::PostIncrement;
1833 case ParseNodeKind::PreIncrementExpr:
1834 return PrivateOpEmitter::Kind::PreIncrement;
1835 case ParseNodeKind::PostDecrementExpr:
1836 return PrivateOpEmitter::Kind::PostDecrement;
1837 case ParseNodeKind::PreDecrementExpr:
1838 return PrivateOpEmitter::Kind::PreDecrement;
1839 default:
1840 MOZ_CRASH("unexpected inc/dec node kind");
1844 bool BytecodeEmitter::emitElemIncDec(UnaryNode* incDec, ValueUsage valueUsage) {
1845 PropertyByValue* elemExpr = &incDec->kid()->as<PropertyByValue>();
1846 bool isSuper = elemExpr->isSuper();
1847 MOZ_ASSERT(!elemExpr->key().isKind(ParseNodeKind::PrivateName));
1848 ParseNodeKind kind = incDec->getKind();
1849 ElemOpEmitter eoe(
1850 this, ConvertIncDecKind(kind),
1851 isSuper ? ElemOpEmitter::ObjKind::Super : ElemOpEmitter::ObjKind::Other);
1852 if (!emitElemObjAndKey(elemExpr, isSuper, eoe)) {
1853 // [stack] # if Super
1854 // [stack] THIS KEY
1855 // [stack] # otherwise
1856 // [stack] OBJ KEY
1857 return false;
1859 if (!eoe.emitIncDec(valueUsage)) {
1860 // [stack] RESULT
1861 return false;
1864 return true;
1867 bool BytecodeEmitter::emitCallIncDec(UnaryNode* incDec) {
1868 MOZ_ASSERT(incDec->isKind(ParseNodeKind::PreIncrementExpr) ||
1869 incDec->isKind(ParseNodeKind::PostIncrementExpr) ||
1870 incDec->isKind(ParseNodeKind::PreDecrementExpr) ||
1871 incDec->isKind(ParseNodeKind::PostDecrementExpr));
1873 ParseNode* call = incDec->kid();
1874 MOZ_ASSERT(call->isKind(ParseNodeKind::CallExpr));
1875 if (!emitTree(call)) {
1876 // [stack] CALLRESULT
1877 return false;
1879 if (!emit1(JSOp::ToNumeric)) {
1880 // [stack] N
1881 return false;
1884 // The increment/decrement has no side effects, so proceed to throw for
1885 // invalid assignment target.
1886 return emit2(JSOp::ThrowMsg, uint8_t(ThrowMsgKind::AssignToCall));
1889 bool BytecodeEmitter::emitPrivateIncDec(UnaryNode* incDec,
1890 ValueUsage valueUsage) {
1891 PrivateMemberAccess* privateExpr = &incDec->kid()->as<PrivateMemberAccess>();
1892 ParseNodeKind kind = incDec->getKind();
1893 PrivateOpEmitter xoe(this, PrivateConvertIncDecKind(kind),
1894 privateExpr->privateName().name());
1895 if (!emitTree(&privateExpr->expression())) {
1896 // [stack] OBJ
1897 return false;
1899 if (!xoe.emitReference()) {
1900 // [stack] OBJ NAME
1901 return false;
1903 if (!xoe.emitIncDec(valueUsage)) {
1904 // [stack] RESULT
1905 return false;
1908 return true;
1911 bool BytecodeEmitter::emitDouble(double d) {
1912 BytecodeOffset offset;
1913 if (!emitCheck(JSOp::Double, 9, &offset)) {
1914 return false;
1917 jsbytecode* code = bytecodeSection().code(offset);
1918 code[0] = jsbytecode(JSOp::Double);
1919 SET_INLINE_VALUE(code, DoubleValue(d));
1920 bytecodeSection().updateDepth(JSOp::Double, offset);
1921 return true;
1924 bool BytecodeEmitter::emitNumberOp(double dval) {
1925 int32_t ival;
1926 if (NumberIsInt32(dval, &ival)) {
1927 if (ival == 0) {
1928 return emit1(JSOp::Zero);
1930 if (ival == 1) {
1931 return emit1(JSOp::One);
1933 if ((int)(int8_t)ival == ival) {
1934 return emit2(JSOp::Int8, uint8_t(int8_t(ival)));
1937 uint32_t u = uint32_t(ival);
1938 if (u < Bit(16)) {
1939 if (!emitUint16Operand(JSOp::Uint16, u)) {
1940 return false;
1942 } else if (u < Bit(24)) {
1943 BytecodeOffset off;
1944 if (!emitN(JSOp::Uint24, 3, &off)) {
1945 return false;
1947 SET_UINT24(bytecodeSection().code(off), u);
1948 } else {
1949 BytecodeOffset off;
1950 if (!emitN(JSOp::Int32, 4, &off)) {
1951 return false;
1953 SET_INT32(bytecodeSection().code(off), ival);
1955 return true;
1958 return emitDouble(dval);
1962 * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047.
1963 * LLVM is deciding to inline this function which uses a lot of stack space
1964 * into emitTree which is recursive and uses relatively little stack space.
1966 MOZ_NEVER_INLINE bool BytecodeEmitter::emitSwitch(SwitchStatement* switchStmt) {
1967 LexicalScopeNode& lexical = switchStmt->lexicalForCaseList();
1968 MOZ_ASSERT(lexical.isKind(ParseNodeKind::LexicalScope));
1969 ListNode* cases = &lexical.scopeBody()->as<ListNode>();
1970 MOZ_ASSERT(cases->isKind(ParseNodeKind::StatementList));
1972 SwitchEmitter se(this);
1973 if (!se.emitDiscriminant(switchStmt->discriminant().pn_pos.begin)) {
1974 return false;
1977 if (!markStepBreakpoint()) {
1978 return false;
1980 if (!emitTree(&switchStmt->discriminant())) {
1981 return false;
1984 // Enter the scope before pushing the switch BreakableControl since all
1985 // breaks are under this scope.
1987 if (!lexical.isEmptyScope()) {
1988 if (!se.emitLexical(lexical.scopeBindings())) {
1989 return false;
1992 // A switch statement may contain hoisted functions inside its
1993 // cases. The hasTopLevelFunctionDeclarations flag is propagated from the
1994 // StatementList bodies of the cases to the case list.
1995 if (cases->hasTopLevelFunctionDeclarations()) {
1996 for (ParseNode* item : cases->contents()) {
1997 CaseClause* caseClause = &item->as<CaseClause>();
1998 ListNode* statements = caseClause->statementList();
1999 if (statements->hasTopLevelFunctionDeclarations()) {
2000 if (!emitHoistedFunctionsInList(statements)) {
2001 return false;
2006 } else {
2007 MOZ_ASSERT(!cases->hasTopLevelFunctionDeclarations());
2010 SwitchEmitter::TableGenerator tableGen(this);
2011 uint32_t caseCount = cases->count() - (switchStmt->hasDefault() ? 1 : 0);
2012 if (caseCount == 0) {
2013 tableGen.finish(0);
2014 } else {
2015 for (ParseNode* item : cases->contents()) {
2016 CaseClause* caseClause = &item->as<CaseClause>();
2017 if (caseClause->isDefault()) {
2018 continue;
2021 ParseNode* caseValue = caseClause->caseExpression();
2023 if (caseValue->getKind() != ParseNodeKind::NumberExpr) {
2024 tableGen.setInvalid();
2025 break;
2028 int32_t i;
2029 if (!NumberEqualsInt32(caseValue->as<NumericLiteral>().value(), &i)) {
2030 tableGen.setInvalid();
2031 break;
2034 if (!tableGen.addNumber(i)) {
2035 return false;
2039 tableGen.finish(caseCount);
2042 if (!se.validateCaseCount(caseCount)) {
2043 return false;
2046 bool isTableSwitch = tableGen.isValid();
2047 if (isTableSwitch) {
2048 if (!se.emitTable(tableGen)) {
2049 return false;
2051 } else {
2052 if (!se.emitCond()) {
2053 return false;
2056 // Emit code for evaluating cases and jumping to case statements.
2057 for (ParseNode* item : cases->contents()) {
2058 CaseClause* caseClause = &item->as<CaseClause>();
2059 if (caseClause->isDefault()) {
2060 continue;
2063 if (!se.prepareForCaseValue()) {
2064 return false;
2067 ParseNode* caseValue = caseClause->caseExpression();
2068 // If the expression is a literal, suppress line number emission so
2069 // that debugging works more naturally.
2070 if (!emitTree(
2071 caseValue, ValueUsage::WantValue,
2072 caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE)) {
2073 return false;
2076 if (!se.emitCaseJump()) {
2077 return false;
2082 // Emit code for each case's statements.
2083 for (ParseNode* item : cases->contents()) {
2084 CaseClause* caseClause = &item->as<CaseClause>();
2085 if (caseClause->isDefault()) {
2086 if (!se.emitDefaultBody()) {
2087 return false;
2089 } else {
2090 if (isTableSwitch) {
2091 ParseNode* caseValue = caseClause->caseExpression();
2092 MOZ_ASSERT(caseValue->isKind(ParseNodeKind::NumberExpr));
2094 NumericLiteral* literal = &caseValue->as<NumericLiteral>();
2095 #ifdef DEBUG
2096 // Use NumberEqualsInt32 here because switches compare using
2097 // strict equality, which will equate -0 and +0. In contrast
2098 // NumberIsInt32 would return false for -0.
2099 int32_t v;
2100 MOZ_ASSERT(mozilla::NumberEqualsInt32(literal->value(), &v));
2101 #endif
2102 int32_t i = int32_t(literal->value());
2104 if (!se.emitCaseBody(i, tableGen)) {
2105 return false;
2107 } else {
2108 if (!se.emitCaseBody()) {
2109 return false;
2114 if (!emitTree(caseClause->statementList())) {
2115 return false;
2119 if (!se.emitEnd()) {
2120 return false;
2123 return true;
2126 bool BytecodeEmitter::allocateResumeIndex(BytecodeOffset offset,
2127 uint32_t* resumeIndex) {
2128 static constexpr uint32_t MaxResumeIndex = BitMask(24);
2130 static_assert(
2131 MaxResumeIndex < uint32_t(AbstractGeneratorObject::RESUME_INDEX_RUNNING),
2132 "resumeIndex should not include magic AbstractGeneratorObject "
2133 "resumeIndex values");
2134 static_assert(
2135 MaxResumeIndex <= INT32_MAX / sizeof(uintptr_t),
2136 "resumeIndex * sizeof(uintptr_t) must fit in an int32. JIT code relies "
2137 "on this when loading resume entries from BaselineScript");
2139 *resumeIndex = bytecodeSection().resumeOffsetList().length();
2140 if (*resumeIndex > MaxResumeIndex) {
2141 reportError(nullptr, JSMSG_TOO_MANY_RESUME_INDEXES);
2142 return false;
2145 return bytecodeSection().resumeOffsetList().append(offset.value());
2148 bool BytecodeEmitter::allocateResumeIndexRange(
2149 mozilla::Span<BytecodeOffset> offsets, uint32_t* firstResumeIndex) {
2150 *firstResumeIndex = 0;
2152 for (size_t i = 0, len = offsets.size(); i < len; i++) {
2153 uint32_t resumeIndex;
2154 if (!allocateResumeIndex(offsets[i], &resumeIndex)) {
2155 return false;
2157 if (i == 0) {
2158 *firstResumeIndex = resumeIndex;
2162 return true;
2165 bool BytecodeEmitter::emitYieldOp(JSOp op) {
2166 if (op == JSOp::FinalYieldRval) {
2167 return emit1(JSOp::FinalYieldRval);
2170 MOZ_ASSERT(op == JSOp::InitialYield || op == JSOp::Yield ||
2171 op == JSOp::Await);
2173 BytecodeOffset off;
2174 if (!emitN(op, 3, &off)) {
2175 return false;
2178 if (op == JSOp::InitialYield || op == JSOp::Yield) {
2179 bytecodeSection().addNumYields();
2182 uint32_t resumeIndex;
2183 if (!allocateResumeIndex(bytecodeSection().offset(), &resumeIndex)) {
2184 return false;
2187 SET_RESUMEINDEX(bytecodeSection().code(off), resumeIndex);
2189 BytecodeOffset unusedOffset;
2190 return emitJumpTargetOp(JSOp::AfterYield, &unusedOffset);
2193 bool BytecodeEmitter::emitPushResumeKind(GeneratorResumeKind kind) {
2194 return emit2(JSOp::ResumeKind, uint8_t(kind));
2197 bool BytecodeEmitter::emitSetThis(BinaryNode* setThisNode) {
2198 // ParseNodeKind::SetThis is used to update |this| after a super() call
2199 // in a derived class constructor.
2201 MOZ_ASSERT(setThisNode->isKind(ParseNodeKind::SetThis));
2202 MOZ_ASSERT(setThisNode->left()->isKind(ParseNodeKind::Name));
2204 auto name = setThisNode->left()->as<NameNode>().name();
2206 // The 'this' binding is not lexical, but due to super() semantics this
2207 // initialization needs to be treated as a lexical one.
2208 NameLocation loc = lookupName(name);
2209 NameLocation lexicalLoc;
2210 if (loc.kind() == NameLocation::Kind::FrameSlot) {
2211 lexicalLoc = NameLocation::FrameSlot(BindingKind::Let, loc.frameSlot());
2212 } else if (loc.kind() == NameLocation::Kind::EnvironmentCoordinate) {
2213 EnvironmentCoordinate coord = loc.environmentCoordinate();
2214 uint8_t hops = AssertedCast<uint8_t>(coord.hops());
2215 lexicalLoc = NameLocation::EnvironmentCoordinate(BindingKind::Let, hops,
2216 coord.slot());
2217 } else {
2218 MOZ_ASSERT(loc.kind() == NameLocation::Kind::Dynamic);
2219 lexicalLoc = loc;
2222 NameOpEmitter noe(this, name, lexicalLoc, NameOpEmitter::Kind::Initialize);
2223 if (!noe.prepareForRhs()) {
2224 // [stack]
2225 return false;
2228 // Emit the new |this| value.
2229 if (!emitTree(setThisNode->right())) {
2230 // [stack] NEWTHIS
2231 return false;
2234 // Get the original |this| and throw if we already initialized
2235 // it. Do *not* use the NameLocation argument, as that's the special
2236 // lexical location below to deal with super() semantics.
2237 if (!emitGetName(name)) {
2238 // [stack] NEWTHIS THIS
2239 return false;
2241 if (!emit1(JSOp::CheckThisReinit)) {
2242 // [stack] NEWTHIS THIS
2243 return false;
2245 if (!emit1(JSOp::Pop)) {
2246 // [stack] NEWTHIS
2247 return false;
2249 if (!noe.emitAssignment()) {
2250 // [stack] NEWTHIS
2251 return false;
2254 if (!emitInitializeInstanceMembers(true)) {
2255 return false;
2258 return true;
2261 bool BytecodeEmitter::defineHoistedTopLevelFunctions(ParseNode* body) {
2262 MOZ_ASSERT(inPrologue());
2263 MOZ_ASSERT(sc->isGlobalContext() || (sc->isEvalContext() && !sc->strict()));
2264 MOZ_ASSERT(body->is<LexicalScopeNode>() || body->is<ListNode>());
2266 if (body->is<LexicalScopeNode>()) {
2267 body = body->as<LexicalScopeNode>().scopeBody();
2268 MOZ_ASSERT(body->is<ListNode>());
2271 if (!body->as<ListNode>().hasTopLevelFunctionDeclarations()) {
2272 return true;
2275 return emitHoistedFunctionsInList(&body->as<ListNode>());
2278 // For Global and sloppy-Eval scripts, this performs most of the steps of the
2279 // spec's [GlobalDeclarationInstantiation] and [EvalDeclarationInstantiation]
2280 // operations.
2282 // Note that while strict-Eval is handled in the same part of the spec, it never
2283 // fails for global-redeclaration checks so those scripts initialize directly in
2284 // their bytecode.
2285 bool BytecodeEmitter::emitDeclarationInstantiation(ParseNode* body) {
2286 if (sc->isModuleContext()) {
2287 // ES Modules have dedicated variable and lexial environments and therefore
2288 // do not have to perform redeclaration checks. We initialize their bindings
2289 // elsewhere in bytecode.
2290 return true;
2293 if (sc->isEvalContext() && sc->strict()) {
2294 // Strict Eval has a dedicated variables (and lexical) environment and
2295 // therefore does not have to perform redeclaration checks. We initialize
2296 // their bindings elsewhere in the bytecode.
2297 return true;
2300 // If we have no variables bindings, then we are done!
2301 if (sc->isGlobalContext()) {
2302 if (!sc->asGlobalContext()->bindings) {
2303 return true;
2305 } else {
2306 MOZ_ASSERT(sc->isEvalContext());
2308 if (!sc->asEvalContext()->bindings) {
2309 return true;
2313 #if DEBUG
2314 // There should be no emitted functions yet.
2315 for (const auto& thing : perScriptData().gcThingList().objects()) {
2316 MOZ_ASSERT(thing.isEmptyGlobalScope() || thing.isScope());
2318 #endif
2320 // Emit the hoisted functions to gc-things list. There is no bytecode
2321 // generated yet to bind them.
2322 if (!defineHoistedTopLevelFunctions(body)) {
2323 return false;
2326 // Save the last GCThingIndex emitted. The hoisted functions are contained in
2327 // the gc-things list up until this point. This set of gc-things also contain
2328 // initial scopes (of which there must be at least one).
2329 MOZ_ASSERT(perScriptData().gcThingList().length() > 0);
2330 GCThingIndex lastFun =
2331 GCThingIndex(perScriptData().gcThingList().length() - 1);
2333 #if DEBUG
2334 for (const auto& thing : perScriptData().gcThingList().objects()) {
2335 MOZ_ASSERT(thing.isEmptyGlobalScope() || thing.isScope() ||
2336 thing.isFunction());
2338 #endif
2340 // Check for declaration conflicts and initialize the bindings.
2341 // NOTE: The self-hosting top-level script should not populate the builtins
2342 // directly on the GlobalObject (and instead uses JSOp::GetIntrinsic for
2343 // lookups).
2344 if (emitterMode == BytecodeEmitter::EmitterMode::Normal) {
2345 if (!emitGCIndexOp(JSOp::GlobalOrEvalDeclInstantiation, lastFun)) {
2346 return false;
2350 return true;
2353 bool BytecodeEmitter::emitScript(ParseNode* body) {
2354 setScriptStartOffsetIfUnset(body->pn_pos.begin);
2356 MOZ_ASSERT(inPrologue());
2358 TDZCheckCache tdzCache(this);
2359 EmitterScope emitterScope(this);
2360 Maybe<AsyncEmitter> topLevelAwait;
2361 if (sc->isGlobalContext()) {
2362 if (!emitterScope.enterGlobal(this, sc->asGlobalContext())) {
2363 return false;
2365 } else if (sc->isEvalContext()) {
2366 if (!emitterScope.enterEval(this, sc->asEvalContext())) {
2367 return false;
2369 } else {
2370 MOZ_ASSERT(sc->isModuleContext());
2371 if (!emitterScope.enterModule(this, sc->asModuleContext())) {
2372 return false;
2374 if (sc->asModuleContext()->isAsync()) {
2375 topLevelAwait.emplace(this);
2379 setFunctionBodyEndPos(body->pn_pos.end);
2381 bool isSloppyEval = sc->isEvalContext() && !sc->strict();
2382 if (isSloppyEval && body->is<LexicalScopeNode>() &&
2383 !body->as<LexicalScopeNode>().isEmptyScope()) {
2384 // Sloppy eval scripts may emit hoisted functions bindings with a
2385 // `JSOp::GlobalOrEvalDeclInstantiation` opcode below. If this eval needs a
2386 // top-level lexical environment, we must ensure that environment is created
2387 // before those functions are created and bound.
2389 // This differs from the global-script case below because the global-lexical
2390 // environment exists outside the script itself. In the case of strict eval
2391 // scripts, the `emitterScope` above is already sufficient.
2392 EmitterScope lexicalEmitterScope(this);
2393 LexicalScopeNode* scope = &body->as<LexicalScopeNode>();
2395 if (!lexicalEmitterScope.enterLexical(this, ScopeKind::Lexical,
2396 scope->scopeBindings())) {
2397 return false;
2400 if (!emitDeclarationInstantiation(scope->scopeBody())) {
2401 return false;
2404 switchToMain();
2406 ParseNode* scopeBody = scope->scopeBody();
2407 if (!emitLexicalScopeBody(scopeBody)) {
2408 return false;
2411 if (!updateSourceCoordNotes(scopeBody->pn_pos.end)) {
2412 return false;
2415 if (!lexicalEmitterScope.leave(this)) {
2416 return false;
2418 } else {
2419 if (!emitDeclarationInstantiation(body)) {
2420 return false;
2422 if (topLevelAwait) {
2423 if (!topLevelAwait->prepareForModule()) {
2424 return false;
2428 switchToMain();
2430 if (topLevelAwait) {
2431 if (!topLevelAwait->prepareForBody()) {
2432 return false;
2436 if (!emitTree(body)) {
2437 // [stack]
2438 return false;
2441 if (!updateSourceCoordNotes(body->pn_pos.end)) {
2442 return false;
2446 if (topLevelAwait) {
2447 if (!topLevelAwait->emitEndModule()) {
2448 return false;
2452 if (!markSimpleBreakpoint()) {
2453 return false;
2456 if (!emitReturnRval()) {
2457 return false;
2460 if (!emitterScope.leave(this)) {
2461 return false;
2464 if (!NameFunctions(fc, parserAtoms(), body)) {
2465 return false;
2468 // Create a Stencil and convert it into a JSScript.
2469 return intoScriptStencil(CompilationStencil::TopLevelIndex);
2472 js::UniquePtr<ImmutableScriptData>
2473 BytecodeEmitter::createImmutableScriptData() {
2474 uint32_t nslots;
2475 if (!getNslots(&nslots)) {
2476 return nullptr;
2479 bool isFunction = sc->isFunctionBox();
2480 uint16_t funLength = isFunction ? sc->asFunctionBox()->length() : 0;
2482 mozilla::SaturateUint8 propertyCountEstimate = propertyAdditionEstimate;
2484 // Add fields to the property count estimate.
2485 if (isFunction && sc->asFunctionBox()->useMemberInitializers()) {
2486 propertyCountEstimate +=
2487 sc->asFunctionBox()->memberInitializers().numMemberInitializers;
2490 return ImmutableScriptData::new_(
2491 fc, mainOffset(), maxFixedSlots, nslots, bodyScopeIndex,
2492 bytecodeSection().numICEntries(), isFunction, funLength,
2493 propertyCountEstimate.value(), bytecodeSection().code(),
2494 bytecodeSection().notes(), bytecodeSection().resumeOffsetList().span(),
2495 bytecodeSection().scopeNoteList().span(),
2496 bytecodeSection().tryNoteList().span());
2499 bool BytecodeEmitter::getNslots(uint32_t* nslots) {
2500 uint64_t nslots64 =
2501 maxFixedSlots + static_cast<uint64_t>(bytecodeSection().maxStackDepth());
2502 if (nslots64 > UINT32_MAX) {
2503 reportError(nullptr, JSMSG_NEED_DIET, "script");
2504 return false;
2506 *nslots = nslots64;
2507 return true;
2510 bool BytecodeEmitter::emitFunctionScript(FunctionNode* funNode) {
2511 MOZ_ASSERT(inPrologue());
2512 ParamsBodyNode* paramsBody = funNode->body();
2513 FunctionBox* funbox = sc->asFunctionBox();
2515 setScriptStartOffsetIfUnset(paramsBody->pn_pos.begin);
2517 // [stack]
2519 FunctionScriptEmitter fse(this, funbox, Some(paramsBody->pn_pos.begin),
2520 Some(paramsBody->pn_pos.end));
2521 if (!fse.prepareForParameters()) {
2522 // [stack]
2523 return false;
2526 if (!emitFunctionFormalParameters(paramsBody)) {
2527 // [stack]
2528 return false;
2531 if (!fse.prepareForBody()) {
2532 // [stack]
2533 return false;
2536 if (!emitTree(paramsBody->body())) {
2537 // [stack]
2538 return false;
2541 if (!fse.emitEndBody()) {
2542 // [stack]
2543 return false;
2546 if (funbox->index() == CompilationStencil::TopLevelIndex) {
2547 if (!NameFunctions(fc, parserAtoms(), funNode)) {
2548 return false;
2552 return fse.intoStencil();
2555 bool BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target,
2556 size_t* emitted) {
2557 #ifdef DEBUG
2558 int depth = bytecodeSection().stackDepth();
2559 #endif
2561 switch (target->getKind()) {
2562 case ParseNodeKind::Name:
2563 case ParseNodeKind::ArrayExpr:
2564 case ParseNodeKind::ObjectExpr:
2565 // No need to recurse into ParseNodeKind::Array and ParseNodeKind::Object
2566 // subpatterns here, since emitSetOrInitializeDestructuring does the
2567 // recursion when setting or initializing the value. Getting reference
2568 // doesn't recurse.
2569 *emitted = 0;
2570 break;
2572 case ParseNodeKind::DotExpr: {
2573 PropertyAccess* prop = &target->as<PropertyAccess>();
2574 bool isSuper = prop->isSuper();
2575 PropOpEmitter poe(this, PropOpEmitter::Kind::SimpleAssignment,
2576 isSuper ? PropOpEmitter::ObjKind::Super
2577 : PropOpEmitter::ObjKind::Other);
2578 if (!poe.prepareForObj()) {
2579 return false;
2581 if (isSuper) {
2582 UnaryNode* base = &prop->expression().as<UnaryNode>();
2583 if (!emitGetThisForSuperBase(base)) {
2584 // [stack] THIS SUPERBASE
2585 return false;
2587 } else {
2588 if (!emitTree(&prop->expression())) {
2589 // [stack] OBJ
2590 return false;
2593 if (!poe.prepareForRhs()) {
2594 // [stack] # if Super
2595 // [stack] THIS SUPERBASE
2596 // [stack] # otherwise
2597 // [stack] OBJ
2598 return false;
2601 // SUPERBASE was pushed onto THIS in poe.prepareForRhs above.
2602 *emitted = 1 + isSuper;
2603 break;
2606 case ParseNodeKind::ElemExpr: {
2607 PropertyByValue* elem = &target->as<PropertyByValue>();
2608 bool isSuper = elem->isSuper();
2609 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
2610 ElemOpEmitter eoe(this, ElemOpEmitter::Kind::SimpleAssignment,
2611 isSuper ? ElemOpEmitter::ObjKind::Super
2612 : ElemOpEmitter::ObjKind::Other);
2613 if (!emitElemObjAndKey(elem, isSuper, eoe)) {
2614 // [stack] # if Super
2615 // [stack] THIS KEY
2616 // [stack] # otherwise
2617 // [stack] OBJ KEY
2618 return false;
2620 if (!eoe.prepareForRhs()) {
2621 // [stack] # if Super
2622 // [stack] THIS KEY SUPERBASE
2623 // [stack] # otherwise
2624 // [stack] OBJ KEY
2625 return false;
2628 // SUPERBASE was pushed onto KEY in eoe.prepareForRhs above.
2629 *emitted = 2 + isSuper;
2630 break;
2633 case ParseNodeKind::PrivateMemberExpr: {
2634 PrivateMemberAccess* privateExpr = &target->as<PrivateMemberAccess>();
2635 PrivateOpEmitter xoe(this, PrivateOpEmitter::Kind::SimpleAssignment,
2636 privateExpr->privateName().name());
2637 if (!emitTree(&privateExpr->expression())) {
2638 // [stack] OBJ
2639 return false;
2641 if (!xoe.emitReference()) {
2642 // [stack] OBJ NAME
2643 return false;
2645 *emitted = xoe.numReferenceSlots();
2646 break;
2649 case ParseNodeKind::CallExpr:
2650 MOZ_ASSERT_UNREACHABLE(
2651 "Parser::reportIfNotValidSimpleAssignmentTarget "
2652 "rejects function calls as assignment "
2653 "targets in destructuring assignments");
2654 break;
2656 default:
2657 MOZ_CRASH("emitDestructuringLHSRef: bad lhs kind");
2660 MOZ_ASSERT(bytecodeSection().stackDepth() == depth + int(*emitted));
2662 return true;
2665 bool BytecodeEmitter::emitSetOrInitializeDestructuring(
2666 ParseNode* target, DestructuringFlavor flav) {
2667 // Now emit the lvalue opcode sequence. If the lvalue is a nested
2668 // destructuring initialiser-form, call ourselves to handle it, then pop
2669 // the matched value. Otherwise emit an lvalue bytecode sequence followed
2670 // by an assignment op.
2672 switch (target->getKind()) {
2673 case ParseNodeKind::ArrayExpr:
2674 case ParseNodeKind::ObjectExpr:
2675 if (!emitDestructuringOps(&target->as<ListNode>(), flav)) {
2676 return false;
2678 // emitDestructuringOps leaves the assigned (to-be-destructured) value on
2679 // top of the stack.
2680 break;
2682 case ParseNodeKind::Name: {
2683 auto name = target->as<NameNode>().name();
2684 NameLocation loc = lookupName(name);
2685 NameOpEmitter::Kind kind;
2686 switch (flav) {
2687 case DestructuringFlavor::Declaration:
2688 kind = NameOpEmitter::Kind::Initialize;
2689 break;
2691 case DestructuringFlavor::Assignment:
2692 kind = NameOpEmitter::Kind::SimpleAssignment;
2693 break;
2696 NameOpEmitter noe(this, name, loc, kind);
2697 if (!noe.prepareForRhs()) {
2698 // [stack] V ENV?
2699 return false;
2701 if (noe.emittedBindOp()) {
2702 // This is like ordinary assignment, but with one difference.
2704 // In `a = b`, we first determine a binding for `a` (using
2705 // JSOp::BindName or JSOp::BindGName), then we evaluate `b`, then
2706 // a JSOp::SetName instruction.
2708 // In `[a] = [b]`, per spec, `b` is evaluated first, then we
2709 // determine a binding for `a`. Then we need to do assignment--
2710 // but the operands are on the stack in the wrong order for
2711 // JSOp::SetProp, so we have to add a JSOp::Swap.
2713 // In the cases where we are emitting a name op, emit a swap
2714 // because of this.
2715 if (!emit1(JSOp::Swap)) {
2716 // [stack] ENV V
2717 return false;
2719 } else {
2720 // In cases of emitting a frame slot or environment slot,
2721 // nothing needs be done.
2723 if (!noe.emitAssignment()) {
2724 // [stack] V
2725 return false;
2728 break;
2731 case ParseNodeKind::DotExpr: {
2732 // The reference is already pushed by emitDestructuringLHSRef.
2733 // [stack] # if Super
2734 // [stack] THIS SUPERBASE VAL
2735 // [stack] # otherwise
2736 // [stack] OBJ VAL
2737 PropertyAccess* prop = &target->as<PropertyAccess>();
2738 bool isSuper = prop->isSuper();
2739 PropOpEmitter poe(this, PropOpEmitter::Kind::SimpleAssignment,
2740 isSuper ? PropOpEmitter::ObjKind::Super
2741 : PropOpEmitter::ObjKind::Other);
2742 if (!poe.skipObjAndRhs()) {
2743 return false;
2745 // [stack] # VAL
2746 if (!poe.emitAssignment(prop->key().atom())) {
2747 return false;
2749 break;
2752 case ParseNodeKind::ElemExpr: {
2753 // The reference is already pushed by emitDestructuringLHSRef.
2754 // [stack] # if Super
2755 // [stack] THIS KEY SUPERBASE VAL
2756 // [stack] # otherwise
2757 // [stack] OBJ KEY VAL
2758 PropertyByValue* elem = &target->as<PropertyByValue>();
2759 bool isSuper = elem->isSuper();
2760 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
2761 ElemOpEmitter eoe(this, ElemOpEmitter::Kind::SimpleAssignment,
2762 isSuper ? ElemOpEmitter::ObjKind::Super
2763 : ElemOpEmitter::ObjKind::Other);
2764 if (!eoe.skipObjAndKeyAndRhs()) {
2765 return false;
2767 if (!eoe.emitAssignment()) {
2768 // [stack] VAL
2769 return false;
2771 break;
2774 case ParseNodeKind::PrivateMemberExpr: {
2775 // The reference is already pushed by emitDestructuringLHSRef.
2776 // [stack] OBJ NAME VAL
2777 PrivateMemberAccess* privateExpr = &target->as<PrivateMemberAccess>();
2778 PrivateOpEmitter xoe(this, PrivateOpEmitter::Kind::SimpleAssignment,
2779 privateExpr->privateName().name());
2780 if (!xoe.skipReference()) {
2781 return false;
2783 if (!xoe.emitAssignment()) {
2784 // [stack] VAL
2785 return false;
2787 break;
2790 case ParseNodeKind::CallExpr:
2791 MOZ_ASSERT_UNREACHABLE(
2792 "Parser::reportIfNotValidSimpleAssignmentTarget "
2793 "rejects function calls as assignment "
2794 "targets in destructuring assignments");
2795 break;
2797 default:
2798 MOZ_CRASH("emitSetOrInitializeDestructuring: bad lhs kind");
2801 // Pop the assigned value.
2802 if (!emit1(JSOp::Pop)) {
2803 // [stack] # empty
2804 return false;
2807 return true;
2810 JSOp BytecodeEmitter::getIterCallOp(JSOp callOp,
2811 SelfHostedIter selfHostedIter) {
2812 if (emitterMode == BytecodeEmitter::SelfHosting) {
2813 MOZ_ASSERT(selfHostedIter != SelfHostedIter::Deny);
2815 switch (callOp) {
2816 case JSOp::Call:
2817 return JSOp::CallContent;
2818 case JSOp::CallIter:
2819 return JSOp::CallContentIter;
2820 default:
2821 MOZ_CRASH("Unknown iterator call op");
2825 return callOp;
2828 bool BytecodeEmitter::emitIteratorNext(
2829 const Maybe<uint32_t>& callSourceCoordOffset,
2830 IteratorKind iterKind /* = IteratorKind::Sync */,
2831 SelfHostedIter selfHostedIter /* = SelfHostedIter::Deny */) {
2832 MOZ_ASSERT(selfHostedIter != SelfHostedIter::Deny ||
2833 emitterMode != BytecodeEmitter::SelfHosting,
2834 ".next() iteration is prohibited in self-hosted code because it"
2835 "can run user-modifiable iteration code");
2837 // [stack] ... NEXT ITER
2838 MOZ_ASSERT(bytecodeSection().stackDepth() >= 2);
2840 if (!emitCall(getIterCallOp(JSOp::Call, selfHostedIter), 0,
2841 callSourceCoordOffset)) {
2842 // [stack] ... RESULT
2843 return false;
2846 if (iterKind == IteratorKind::Async) {
2847 if (!emitAwaitInInnermostScope()) {
2848 // [stack] ... RESULT
2849 return false;
2853 if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) {
2854 // [stack] ... RESULT
2855 return false;
2857 return true;
2860 bool BytecodeEmitter::emitIteratorCloseInScope(
2861 EmitterScope& currentScope,
2862 IteratorKind iterKind /* = IteratorKind::Sync */,
2863 CompletionKind completionKind /* = CompletionKind::Normal */,
2864 SelfHostedIter selfHostedIter /* = SelfHostedIter::Deny */) {
2865 MOZ_ASSERT(selfHostedIter != SelfHostedIter::Deny ||
2866 emitterMode != BytecodeEmitter::SelfHosting,
2867 ".close() on iterators is prohibited in self-hosted code because "
2868 "it can run user-modifiable iteration code");
2870 if (iterKind == IteratorKind::Sync) {
2871 return emit2(JSOp::CloseIter, uint8_t(completionKind));
2874 // Generate inline logic corresponding to IteratorClose (ES2021 7.4.6) and
2875 // AsyncIteratorClose (ES2021 7.4.7). Steps numbers apply to both operations.
2877 // Callers need to ensure that the iterator object is at the top of the
2878 // stack.
2880 // For non-Throw completions, we emit the equivalent of:
2882 // var returnMethod = GetMethod(iterator, "return");
2883 // if (returnMethod !== undefined) {
2884 // var innerResult = [Await] Call(returnMethod, iterator);
2885 // CheckIsObj(innerResult);
2886 // }
2888 // Whereas for Throw completions, we emit:
2890 // try {
2891 // var returnMethod = GetMethod(iterator, "return");
2892 // if (returnMethod !== undefined) {
2893 // [Await] Call(returnMethod, iterator);
2894 // }
2895 // } catch {}
2897 Maybe<TryEmitter> tryCatch;
2899 if (completionKind == CompletionKind::Throw) {
2900 tryCatch.emplace(this, TryEmitter::Kind::TryCatch,
2901 TryEmitter::ControlKind::NonSyntactic);
2903 if (!tryCatch->emitTry()) {
2904 // [stack] ... ITER
2905 return false;
2909 if (!emit1(JSOp::Dup)) {
2910 // [stack] ... ITER ITER
2911 return false;
2914 // Steps 1-2 are assertions, step 3 is implicit.
2916 // Step 4.
2918 // Get the "return" method.
2919 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::return_())) {
2920 // [stack] ... ITER RET
2921 return false;
2924 // Step 5.
2926 // Do nothing if "return" is undefined or null.
2927 InternalIfEmitter ifReturnMethodIsDefined(this);
2928 if (!emit1(JSOp::IsNullOrUndefined)) {
2929 // [stack] ... ITER RET NULL-OR-UNDEF
2930 return false;
2933 if (!ifReturnMethodIsDefined.emitThenElse(
2934 IfEmitter::ConditionKind::Negative)) {
2935 // [stack] ... ITER RET
2936 return false;
2939 // Steps 5.c, 7.
2941 // Call the "return" method.
2942 if (!emit1(JSOp::Swap)) {
2943 // [stack] ... RET ITER
2944 return false;
2947 if (!emitCall(getIterCallOp(JSOp::Call, selfHostedIter), 0)) {
2948 // [stack] ... RESULT
2949 return false;
2952 // 7.4.7 AsyncIteratorClose, step 5.d.
2953 if (iterKind == IteratorKind::Async) {
2954 if (completionKind != CompletionKind::Throw) {
2955 // Await clobbers rval, so save the current rval.
2956 if (!emit1(JSOp::GetRval)) {
2957 // [stack] ... RESULT RVAL
2958 return false;
2960 if (!emit1(JSOp::Swap)) {
2961 // [stack] ... RVAL RESULT
2962 return false;
2966 if (!emitAwaitInScope(currentScope)) {
2967 // [stack] ... RVAL? RESULT
2968 return false;
2971 if (completionKind != CompletionKind::Throw) {
2972 if (!emit1(JSOp::Swap)) {
2973 // [stack] ... RESULT RVAL
2974 return false;
2976 if (!emit1(JSOp::SetRval)) {
2977 // [stack] ... RESULT
2978 return false;
2983 // Step 6 (Handled in caller).
2985 // Step 8.
2986 if (completionKind != CompletionKind::Throw) {
2987 // Check that the "return" result is an object.
2988 if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) {
2989 // [stack] ... RESULT
2990 return false;
2994 if (!ifReturnMethodIsDefined.emitElse()) {
2995 // [stack] ... ITER RET
2996 return false;
2999 if (!emit1(JSOp::Pop)) {
3000 // [stack] ... ITER
3001 return false;
3004 if (!ifReturnMethodIsDefined.emitEnd()) {
3005 return false;
3008 if (completionKind == CompletionKind::Throw) {
3009 if (!tryCatch->emitCatch()) {
3010 // [stack] ... ITER EXC
3011 return false;
3014 // Just ignore the exception thrown by call and await.
3015 if (!emit1(JSOp::Pop)) {
3016 // [stack] ... ITER
3017 return false;
3020 if (!tryCatch->emitEnd()) {
3021 // [stack] ... ITER
3022 return false;
3026 // Step 9 (Handled in caller).
3028 return emit1(JSOp::Pop);
3029 // [stack] ...
3032 template <typename InnerEmitter>
3033 bool BytecodeEmitter::wrapWithDestructuringTryNote(int32_t iterDepth,
3034 InnerEmitter emitter) {
3035 MOZ_ASSERT(bytecodeSection().stackDepth() >= iterDepth);
3037 // Pad a nop at the beginning of the bytecode covered by the trynote so
3038 // that when unwinding environments, we may unwind to the scope
3039 // corresponding to the pc *before* the start, in case the first bytecode
3040 // emitted by |emitter| is the start of an inner scope. See comment above
3041 // UnwindEnvironmentToTryPc.
3042 if (!emit1(JSOp::TryDestructuring)) {
3043 return false;
3046 BytecodeOffset start = bytecodeSection().offset();
3047 if (!emitter(this)) {
3048 return false;
3050 BytecodeOffset end = bytecodeSection().offset();
3051 if (start != end) {
3052 return addTryNote(TryNoteKind::Destructuring, iterDepth, start, end);
3054 return true;
3057 bool BytecodeEmitter::emitDefault(ParseNode* defaultExpr, ParseNode* pattern) {
3058 // [stack] VALUE
3060 DefaultEmitter de(this);
3061 if (!de.prepareForDefault()) {
3062 // [stack]
3063 return false;
3065 if (!emitInitializer(defaultExpr, pattern)) {
3066 // [stack] DEFAULTVALUE
3067 return false;
3069 if (!de.emitEnd()) {
3070 // [stack] VALUE/DEFAULTVALUE
3071 return false;
3073 return true;
3076 bool BytecodeEmitter::emitAnonymousFunctionWithName(
3077 ParseNode* node, TaggedParserAtomIndex name) {
3078 MOZ_ASSERT(node->isDirectRHSAnonFunction());
3080 if (node->is<FunctionNode>()) {
3081 // Function doesn't have 'name' property at this point.
3082 // Set function's name at compile time.
3083 if (!setFunName(node->as<FunctionNode>().funbox(), name)) {
3084 return false;
3087 return emitTree(node);
3090 MOZ_ASSERT(node->is<ClassNode>());
3092 return emitClass(&node->as<ClassNode>(), ClassNameKind::InferredName, name);
3095 bool BytecodeEmitter::emitAnonymousFunctionWithComputedName(
3096 ParseNode* node, FunctionPrefixKind prefixKind) {
3097 MOZ_ASSERT(node->isDirectRHSAnonFunction());
3099 if (node->is<FunctionNode>()) {
3100 if (!emitTree(node)) {
3101 // [stack] NAME FUN
3102 return false;
3104 if (!emitDupAt(1)) {
3105 // [stack] NAME FUN NAME
3106 return false;
3108 if (!emit2(JSOp::SetFunName, uint8_t(prefixKind))) {
3109 // [stack] NAME FUN
3110 return false;
3112 return true;
3115 MOZ_ASSERT(node->is<ClassNode>());
3116 MOZ_ASSERT(prefixKind == FunctionPrefixKind::None);
3118 return emitClass(&node->as<ClassNode>(), ClassNameKind::ComputedName);
3121 bool BytecodeEmitter::setFunName(FunctionBox* funbox,
3122 TaggedParserAtomIndex name) {
3123 // The inferred name may already be set if this function is an interpreted
3124 // lazy function and we OOM'ed after we set the inferred name the first
3125 // time.
3126 if (funbox->hasInferredName()) {
3127 MOZ_ASSERT(!funbox->emitBytecode);
3128 MOZ_ASSERT(funbox->displayAtom() == name);
3130 return true;
3133 funbox->setInferredName(name);
3134 return true;
3137 bool BytecodeEmitter::emitInitializer(ParseNode* initializer,
3138 ParseNode* pattern) {
3139 if (initializer->isDirectRHSAnonFunction()) {
3140 MOZ_ASSERT(!pattern->isInParens());
3141 auto name = pattern->as<NameNode>().name();
3142 if (!emitAnonymousFunctionWithName(initializer, name)) {
3143 return false;
3145 } else {
3146 if (!emitTree(initializer)) {
3147 return false;
3151 return true;
3154 bool BytecodeEmitter::emitDestructuringOpsArray(ListNode* pattern,
3155 DestructuringFlavor flav) {
3156 MOZ_ASSERT(getSelfHostedIterFor(pattern) == SelfHostedIter::Deny,
3157 "array destructuring is prohibited in self-hosted code because it"
3158 "can run user-modifiable iteration code");
3159 MOZ_ASSERT(pattern->isKind(ParseNodeKind::ArrayExpr));
3160 MOZ_ASSERT(bytecodeSection().stackDepth() != 0);
3162 // Here's pseudo code for |let [a, b, , c=y, ...d] = x;|
3164 // Lines that are annotated "covered by trynote" mean that upon throwing
3165 // an exception, IteratorClose is called on iter only if done is false.
3167 // let x, y;
3168 // let a, b, c, d;
3169 // let iter, next, lref, result, done, value; // stack values
3171 // // NOTE: the fast path for this example is not applicable, because of
3172 // // the spread and the assignment |c=y|, but it is documented here for a
3173 // // simpler example, |let [a,b] = x;|
3174 // //
3175 // // if (IsOptimizableArray(x)) {
3176 // // a = x[0];
3177 // // b = x[1];
3178 // // goto end: // (skip everything below)
3179 // // }
3181 // iter = x[Symbol.iterator]();
3182 // next = iter.next;
3184 // // ==== emitted by loop for a ====
3185 // lref = GetReference(a); // covered by trynote
3187 // result = Call(next, iter);
3188 // done = result.done;
3190 // if (done)
3191 // value = undefined;
3192 // else
3193 // value = result.value;
3195 // SetOrInitialize(lref, value); // covered by trynote
3197 // // ==== emitted by loop for b ====
3198 // lref = GetReference(b); // covered by trynote
3200 // if (done) {
3201 // value = undefined;
3202 // } else {
3203 // result = Call(next, iter);
3204 // done = result.done;
3205 // if (done)
3206 // value = undefined;
3207 // else
3208 // value = result.value;
3209 // }
3211 // SetOrInitialize(lref, value); // covered by trynote
3213 // // ==== emitted by loop for elision ====
3214 // if (done) {
3215 // value = undefined;
3216 // } else {
3217 // result = Call(next, iter);
3218 // done = result.done;
3219 // if (done)
3220 // value = undefined;
3221 // else
3222 // value = result.value;
3223 // }
3225 // // ==== emitted by loop for c ====
3226 // lref = GetReference(c); // covered by trynote
3228 // if (done) {
3229 // value = undefined;
3230 // } else {
3231 // result = Call(next, iter);
3232 // done = result.done;
3233 // if (done)
3234 // value = undefined;
3235 // else
3236 // value = result.value;
3237 // }
3239 // if (value === undefined)
3240 // value = y; // covered by trynote
3242 // SetOrInitialize(lref, value); // covered by trynote
3244 // // ==== emitted by loop for d ====
3245 // lref = GetReference(d); // covered by trynote
3247 // if (done)
3248 // value = [];
3249 // else
3250 // value = [...iter];
3252 // SetOrInitialize(lref, value); // covered by trynote
3254 // // === emitted after loop ===
3255 // if (!done)
3256 // IteratorClose(iter);
3258 // end:
3260 bool isEligibleForArrayOptimizations = true;
3261 for (ParseNode* member : pattern->contents()) {
3262 switch (member->getKind()) {
3263 case ParseNodeKind::Elision:
3264 break;
3265 case ParseNodeKind::Name: {
3266 auto name = member->as<NameNode>().name();
3267 NameLocation loc = lookupName(name);
3268 if (loc.kind() != NameLocation::Kind::ArgumentSlot &&
3269 loc.kind() != NameLocation::Kind::FrameSlot &&
3270 loc.kind() != NameLocation::Kind::EnvironmentCoordinate) {
3271 isEligibleForArrayOptimizations = false;
3273 break;
3275 default:
3276 // Unfortunately we can't handle any recursive destructuring,
3277 // because we can't guarantee that the recursed-into parts
3278 // won't run code which invalidates our constraints. We also
3279 // cannot handle ParseNodeKind::AssignExpr for similar reasons.
3280 isEligibleForArrayOptimizations = false;
3281 break;
3283 if (!isEligibleForArrayOptimizations) {
3284 break;
3288 // Use an iterator to destructure the RHS, instead of index lookup. We
3289 // must leave the *original* value on the stack.
3290 if (!emit1(JSOp::Dup)) {
3291 // [stack] ... OBJ OBJ
3292 return false;
3295 Maybe<InternalIfEmitter> ifArrayOptimizable;
3297 if (isEligibleForArrayOptimizations) {
3298 ifArrayOptimizable.emplace(
3299 this, BranchEmitterBase::LexicalKind::MayContainLexicalAccessInBranch);
3301 if (!emit1(JSOp::Dup)) {
3302 // [stack] OBJ OBJ
3303 return false;
3306 if (!emit1(JSOp::OptimizeGetIterator)) {
3307 // [stack] OBJ OBJ IS_OPTIMIZABLE
3308 return false;
3311 if (!ifArrayOptimizable->emitThenElse()) {
3312 // [stack] OBJ OBJ
3313 return false;
3316 if (!emitAtomOp(JSOp::GetProp,
3317 TaggedParserAtomIndex::WellKnown::length())) {
3318 // [stack] OBJ LENGTH
3319 return false;
3322 if (!emit1(JSOp::Swap)) {
3323 // [stack] LENGTH OBJ
3324 return false;
3327 uint32_t idx = 0;
3328 for (ParseNode* member : pattern->contents()) {
3329 if (member->isKind(ParseNodeKind::Elision)) {
3330 idx += 1;
3331 continue;
3334 if (!emit1(JSOp::Dup)) {
3335 // [stack] LENGTH OBJ OBJ
3336 return false;
3339 if (!emitNumberOp(idx)) {
3340 // [stack] LENGTH OBJ OBJ IDX
3341 return false;
3344 if (!emit1(JSOp::Dup)) {
3345 // [stack] LENGTH OBJ OBJ IDX IDX
3346 return false;
3349 if (!emitDupAt(4)) {
3350 // [stack] LENGTH OBJ OBJ IDX IDX LENGTH
3351 return false;
3354 if (!emit1(JSOp::Lt)) {
3355 // [stack] LENGTH OBJ OBJ IDX IS_IN_DENSE_BOUNDS
3356 return false;
3359 InternalIfEmitter isInDenseBounds(this);
3360 if (!isInDenseBounds.emitThenElse()) {
3361 // [stack] LENGTH OBJ OBJ IDX
3362 return false;
3365 if (!emit1(JSOp::GetElem)) {
3366 // [stack] LENGTH OBJ VALUE
3367 return false;
3370 if (!isInDenseBounds.emitElse()) {
3371 // [stack] LENGTH OBJ OBJ IDX
3372 return false;
3375 if (!emitPopN(2)) {
3376 // [stack] LENGTH OBJ
3377 return false;
3380 if (!emit1(JSOp::Undefined)) {
3381 // [stack] LENGTH OBJ UNDEFINED
3382 return false;
3385 if (!isInDenseBounds.emitEnd()) {
3386 // [stack] LENGTH OBJ VALUE|UNDEFINED
3387 return false;
3390 if (!emitSetOrInitializeDestructuring(member, flav)) {
3391 // [stack] LENGTH OBJ
3392 return false;
3395 idx += 1;
3398 if (!emit1(JSOp::Swap)) {
3399 // [stack] OBJ LENGTH
3400 return false;
3403 if (!emit1(JSOp::Pop)) {
3404 // [stack] OBJ
3405 return false;
3408 if (!ifArrayOptimizable->emitElse()) {
3409 // [stack] OBJ OBJ
3410 return false;
3414 if (!emitIterator(SelfHostedIter::Deny)) {
3415 // [stack] ... OBJ NEXT ITER
3416 return false;
3419 // For an empty pattern [], call IteratorClose unconditionally. Nothing
3420 // else needs to be done.
3421 if (!pattern->head()) {
3422 if (!emit1(JSOp::Swap)) {
3423 // [stack] ... OBJ ITER NEXT
3424 return false;
3426 if (!emit1(JSOp::Pop)) {
3427 // [stack] ... OBJ ITER
3428 return false;
3431 if (!emitIteratorCloseInInnermostScope()) {
3432 // [stack] ... OBJ
3433 return false;
3436 if (ifArrayOptimizable.isSome()) {
3437 if (!ifArrayOptimizable->emitEnd()) {
3438 // [stack] OBJ
3439 return false;
3443 return true;
3446 // Push an initial FALSE value for DONE.
3447 if (!emit1(JSOp::False)) {
3448 // [stack] ... OBJ NEXT ITER FALSE
3449 return false;
3452 // TryNoteKind::Destructuring expects the iterator and the done value
3453 // to be the second to top and the top of the stack, respectively.
3454 // IteratorClose is called upon exception only if done is false.
3455 int32_t tryNoteDepth = bytecodeSection().stackDepth();
3457 for (ParseNode* member : pattern->contents()) {
3458 bool isFirst = member == pattern->head();
3459 DebugOnly<bool> hasNext = !!member->pn_next;
3461 ParseNode* subpattern;
3462 if (member->isKind(ParseNodeKind::Spread)) {
3463 subpattern = member->as<UnaryNode>().kid();
3465 MOZ_ASSERT(!subpattern->isKind(ParseNodeKind::AssignExpr));
3466 } else {
3467 subpattern = member;
3470 ParseNode* lhsPattern = subpattern;
3471 ParseNode* pndefault = nullptr;
3472 if (subpattern->isKind(ParseNodeKind::AssignExpr)) {
3473 lhsPattern = subpattern->as<AssignmentNode>().left();
3474 pndefault = subpattern->as<AssignmentNode>().right();
3477 // Number of stack slots emitted for the LHS reference.
3478 size_t emitted = 0;
3480 // Spec requires LHS reference to be evaluated first.
3481 bool isElision = lhsPattern->isKind(ParseNodeKind::Elision);
3482 if (!isElision) {
3483 auto emitLHSRef = [lhsPattern, &emitted](BytecodeEmitter* bce) {
3484 return bce->emitDestructuringLHSRef(lhsPattern, &emitted);
3485 // [stack] ... OBJ NEXT ITER DONE LREF*
3487 if (!wrapWithDestructuringTryNote(tryNoteDepth, emitLHSRef)) {
3488 return false;
3492 // Pick the DONE value to the top of the stack.
3493 if (emitted) {
3494 if (!emitPickN(emitted)) {
3495 // [stack] ... OBJ NEXT ITER LREF* DONE
3496 return false;
3500 if (isFirst) {
3501 // If this element is the first, DONE is always FALSE, so pop it.
3503 // Non-first elements should emit if-else depending on the
3504 // member pattern, below.
3505 if (!emit1(JSOp::Pop)) {
3506 // [stack] ... OBJ NEXT ITER LREF*
3507 return false;
3511 if (member->isKind(ParseNodeKind::Spread)) {
3512 InternalIfEmitter ifThenElse(this);
3513 if (!isFirst) {
3514 // If spread is not the first element of the pattern,
3515 // iterator can already be completed.
3516 // [stack] ... OBJ NEXT ITER LREF* DONE
3518 if (!ifThenElse.emitThenElse()) {
3519 // [stack] ... OBJ NEXT ITER LREF*
3520 return false;
3523 if (!emitUint32Operand(JSOp::NewArray, 0)) {
3524 // [stack] ... OBJ NEXT ITER LREF* ARRAY
3525 return false;
3527 if (!ifThenElse.emitElse()) {
3528 // [stack] ... OBJ NEXT ITER LREF*
3529 return false;
3533 // If iterator is not completed, create a new array with the rest
3534 // of the iterator.
3535 if (!emitDupAt(emitted + 1, 2)) {
3536 // [stack] ... OBJ NEXT ITER LREF* NEXT ITER
3537 return false;
3539 if (!emitUint32Operand(JSOp::NewArray, 0)) {
3540 // [stack] ... OBJ NEXT ITER LREF* NEXT ITER ARRAY
3541 return false;
3543 if (!emitNumberOp(0)) {
3544 // [stack] ... OBJ NEXT ITER LREF* NEXT ITER ARRAY INDEX
3545 return false;
3547 if (!emitSpread(SelfHostedIter::Deny)) {
3548 // [stack] ... OBJ NEXT ITER LREF* ARRAY INDEX
3549 return false;
3551 if (!emit1(JSOp::Pop)) {
3552 // [stack] ... OBJ NEXT ITER LREF* ARRAY
3553 return false;
3556 if (!isFirst) {
3557 if (!ifThenElse.emitEnd()) {
3558 return false;
3560 MOZ_ASSERT(ifThenElse.pushed() == 1);
3563 // At this point the iterator is done. Unpick a TRUE value for DONE above
3564 // ITER.
3565 if (!emit1(JSOp::True)) {
3566 // [stack] ... OBJ NEXT ITER LREF* ARRAY TRUE
3567 return false;
3569 if (!emitUnpickN(emitted + 1)) {
3570 // [stack] ... OBJ NEXT ITER TRUE LREF* ARRAY
3571 return false;
3574 auto emitAssignment = [lhsPattern, flav](BytecodeEmitter* bce) {
3575 return bce->emitSetOrInitializeDestructuring(lhsPattern, flav);
3576 // [stack] ... OBJ NEXT ITER TRUE
3578 if (!wrapWithDestructuringTryNote(tryNoteDepth, emitAssignment)) {
3579 return false;
3582 MOZ_ASSERT(!hasNext);
3583 break;
3586 InternalIfEmitter ifAlreadyDone(this);
3587 if (!isFirst) {
3588 // [stack] ... OBJ NEXT ITER LREF* DONE
3590 if (!ifAlreadyDone.emitThenElse()) {
3591 // [stack] ... OBJ NEXT ITER LREF*
3592 return false;
3595 if (!emit1(JSOp::Undefined)) {
3596 // [stack] ... OBJ NEXT ITER LREF* UNDEF
3597 return false;
3599 if (!emit1(JSOp::NopDestructuring)) {
3600 // [stack] ... OBJ NEXT ITER LREF* UNDEF
3601 return false;
3604 // The iterator is done. Unpick a TRUE value for DONE above ITER.
3605 if (!emit1(JSOp::True)) {
3606 // [stack] ... OBJ NEXT ITER LREF* UNDEF TRUE
3607 return false;
3609 if (!emitUnpickN(emitted + 1)) {
3610 // [stack] ... OBJ NEXT ITER TRUE LREF* UNDEF
3611 return false;
3614 if (!ifAlreadyDone.emitElse()) {
3615 // [stack] ... OBJ NEXT ITER LREF*
3616 return false;
3620 if (!emitDupAt(emitted + 1, 2)) {
3621 // [stack] ... OBJ NEXT ITER LREF* NEXT
3622 return false;
3624 if (!emitIteratorNext(Some(pattern->pn_pos.begin))) {
3625 // [stack] ... OBJ NEXT ITER LREF* RESULT
3626 return false;
3628 if (!emit1(JSOp::Dup)) {
3629 // [stack] ... OBJ NEXT ITER LREF* RESULT RESULT
3630 return false;
3632 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::done())) {
3633 // [stack] ... OBJ NEXT ITER LREF* RESULT DONE
3634 return false;
3637 if (!emit1(JSOp::Dup)) {
3638 // [stack] ... OBJ NEXT ITER LREF* RESULT DONE DONE
3639 return false;
3641 if (!emitUnpickN(emitted + 2)) {
3642 // [stack] ... OBJ NEXT ITER DONE LREF* RESULT DONE
3643 return false;
3646 InternalIfEmitter ifDone(this);
3647 if (!ifDone.emitThenElse()) {
3648 // [stack] ... OBJ NEXT ITER DONE LREF* RESULT
3649 return false;
3652 if (!emit1(JSOp::Pop)) {
3653 // [stack] ... OBJ NEXT ITER DONE LREF*
3654 return false;
3656 if (!emit1(JSOp::Undefined)) {
3657 // [stack] ... OBJ NEXT ITER DONE LREF* UNDEF
3658 return false;
3660 if (!emit1(JSOp::NopDestructuring)) {
3661 // [stack] ... OBJ NEXT ITER DONE LREF* UNDEF
3662 return false;
3665 if (!ifDone.emitElse()) {
3666 // [stack] ... OBJ NEXT ITER DONE LREF* RESULT
3667 return false;
3670 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::value())) {
3671 // [stack] ... OBJ NEXT ITER DONE LREF* VALUE
3672 return false;
3675 if (!ifDone.emitEnd()) {
3676 return false;
3678 MOZ_ASSERT(ifDone.pushed() == 0);
3680 if (!isFirst) {
3681 if (!ifAlreadyDone.emitEnd()) {
3682 return false;
3684 MOZ_ASSERT(ifAlreadyDone.pushed() == 2);
3687 if (pndefault) {
3688 auto emitDefault = [pndefault, lhsPattern](BytecodeEmitter* bce) {
3689 return bce->emitDefault(pndefault, lhsPattern);
3690 // [stack] ... OBJ NEXT ITER DONE LREF* VALUE
3693 if (!wrapWithDestructuringTryNote(tryNoteDepth, emitDefault)) {
3694 return false;
3698 if (!isElision) {
3699 auto emitAssignment = [lhsPattern, flav](BytecodeEmitter* bce) {
3700 return bce->emitSetOrInitializeDestructuring(lhsPattern, flav);
3701 // [stack] ... OBJ NEXT ITER DONE
3704 if (!wrapWithDestructuringTryNote(tryNoteDepth, emitAssignment)) {
3705 return false;
3707 } else {
3708 if (!emit1(JSOp::Pop)) {
3709 // [stack] ... OBJ NEXT ITER DONE
3710 return false;
3715 // The last DONE value is on top of the stack. If not DONE, call
3716 // IteratorClose.
3717 // [stack] ... OBJ NEXT ITER DONE
3719 InternalIfEmitter ifDone(this);
3720 if (!ifDone.emitThenElse()) {
3721 // [stack] ... OBJ NEXT ITER
3722 return false;
3724 if (!emitPopN(2)) {
3725 // [stack] ... OBJ
3726 return false;
3728 if (!ifDone.emitElse()) {
3729 // [stack] ... OBJ NEXT ITER
3730 return false;
3732 if (!emit1(JSOp::Swap)) {
3733 // [stack] ... OBJ ITER NEXT
3734 return false;
3736 if (!emit1(JSOp::Pop)) {
3737 // [stack] ... OBJ ITER
3738 return false;
3740 if (!emitIteratorCloseInInnermostScope()) {
3741 // [stack] ... OBJ
3742 return false;
3744 if (!ifDone.emitEnd()) {
3745 return false;
3748 if (ifArrayOptimizable.isSome()) {
3749 if (!ifArrayOptimizable->emitEnd()) {
3750 // [stack] OBJ
3751 return false;
3755 return true;
3758 bool BytecodeEmitter::emitComputedPropertyName(UnaryNode* computedPropName) {
3759 MOZ_ASSERT(computedPropName->isKind(ParseNodeKind::ComputedName));
3760 return emitTree(computedPropName->kid()) && emit1(JSOp::ToPropertyKey);
3763 bool BytecodeEmitter::emitDestructuringOpsObject(ListNode* pattern,
3764 DestructuringFlavor flav) {
3765 MOZ_ASSERT(pattern->isKind(ParseNodeKind::ObjectExpr));
3767 // [stack] ... RHS
3768 MOZ_ASSERT(bytecodeSection().stackDepth() > 0);
3770 if (!emit1(JSOp::CheckObjCoercible)) {
3771 // [stack] ... RHS
3772 return false;
3775 bool needsRestPropertyExcludedSet =
3776 pattern->count() > 1 && pattern->last()->isKind(ParseNodeKind::Spread);
3777 if (needsRestPropertyExcludedSet) {
3778 if (!emitDestructuringObjRestExclusionSet(pattern)) {
3779 // [stack] ... RHS SET
3780 return false;
3783 if (!emit1(JSOp::Swap)) {
3784 // [stack] ... SET RHS
3785 return false;
3789 for (ParseNode* member : pattern->contents()) {
3790 ParseNode* subpattern;
3791 if (member->isKind(ParseNodeKind::MutateProto) ||
3792 member->isKind(ParseNodeKind::Spread)) {
3793 subpattern = member->as<UnaryNode>().kid();
3795 MOZ_ASSERT_IF(member->isKind(ParseNodeKind::Spread),
3796 !subpattern->isKind(ParseNodeKind::AssignExpr));
3797 } else {
3798 MOZ_ASSERT(member->isKind(ParseNodeKind::PropertyDefinition) ||
3799 member->isKind(ParseNodeKind::Shorthand));
3800 subpattern = member->as<BinaryNode>().right();
3803 ParseNode* lhs = subpattern;
3804 ParseNode* pndefault = nullptr;
3805 if (subpattern->isKind(ParseNodeKind::AssignExpr)) {
3806 lhs = subpattern->as<AssignmentNode>().left();
3807 pndefault = subpattern->as<AssignmentNode>().right();
3810 // Number of stack slots emitted for the LHS reference.
3811 size_t emitted = 0;
3813 // Spec requires LHS reference to be evaluated first.
3814 if (!emitDestructuringLHSRef(lhs, &emitted)) {
3815 // [stack] ... SET? RHS LREF*
3816 return false;
3819 // Duplicate the value being destructured to use as a reference base.
3820 if (!emitDupAt(emitted)) {
3821 // [stack] ... SET? RHS LREF* RHS
3822 return false;
3825 if (member->isKind(ParseNodeKind::Spread)) {
3826 if (!updateSourceCoordNotes(member->pn_pos.begin)) {
3827 return false;
3830 if (!emit1(JSOp::NewInit)) {
3831 // [stack] ... SET? RHS LREF* RHS TARGET
3832 return false;
3834 if (!emit1(JSOp::Dup)) {
3835 // [stack] ... SET? RHS LREF* RHS TARGET TARGET
3836 return false;
3838 if (!emit2(JSOp::Pick, 2)) {
3839 // [stack] ... SET? RHS LREF* TARGET TARGET RHS
3840 return false;
3843 if (needsRestPropertyExcludedSet) {
3844 if (!emit2(JSOp::Pick, emitted + 4)) {
3845 // [stack] ... RHS LREF* TARGET TARGET RHS SET
3846 return false;
3850 CopyOption option = needsRestPropertyExcludedSet ? CopyOption::Filtered
3851 : CopyOption::Unfiltered;
3852 if (!emitCopyDataProperties(option)) {
3853 // [stack] ... RHS LREF* TARGET
3854 return false;
3857 // Destructure TARGET per this member's lhs.
3858 if (!emitSetOrInitializeDestructuring(lhs, flav)) {
3859 // [stack] ... RHS
3860 return false;
3863 MOZ_ASSERT(member == pattern->last(), "Rest property is always last");
3864 break;
3867 // Now push the property value currently being matched, which is the value
3868 // of the current property name "label" on the left of a colon in the object
3869 // initialiser.
3870 if (member->isKind(ParseNodeKind::MutateProto)) {
3871 if (!emitAtomOp(JSOp::GetProp,
3872 TaggedParserAtomIndex::WellKnown::proto_())) {
3873 // [stack] ... SET? RHS LREF* PROP
3874 return false;
3876 } else {
3877 MOZ_ASSERT(member->isKind(ParseNodeKind::PropertyDefinition) ||
3878 member->isKind(ParseNodeKind::Shorthand));
3880 ParseNode* key = member->as<BinaryNode>().left();
3881 if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
3882 key->isKind(ParseNodeKind::StringExpr)) {
3883 if (!emitAtomOp(JSOp::GetProp, key->as<NameNode>().atom())) {
3884 // [stack] ... SET? RHS LREF* PROP
3885 return false;
3887 } else {
3888 if (key->isKind(ParseNodeKind::NumberExpr)) {
3889 if (!emitNumberOp(key->as<NumericLiteral>().value())) {
3890 // [stack]... SET? RHS LREF* RHS KEY
3891 return false;
3893 } else {
3894 // Otherwise this is a computed property name. BigInt keys are parsed
3895 // as (synthetic) computed property names, too.
3896 MOZ_ASSERT(key->isKind(ParseNodeKind::ComputedName));
3898 if (!emitComputedPropertyName(&key->as<UnaryNode>())) {
3899 // [stack] ... SET? RHS LREF* RHS KEY
3900 return false;
3903 // Add the computed property key to the exclusion set.
3904 if (needsRestPropertyExcludedSet) {
3905 if (!emitDupAt(emitted + 3)) {
3906 // [stack] ... SET RHS LREF* RHS KEY SET
3907 return false;
3909 if (!emitDupAt(1)) {
3910 // [stack] ... SET RHS LREF* RHS KEY SET KEY
3911 return false;
3913 if (!emit1(JSOp::Undefined)) {
3914 // [stack] ... SET RHS LREF* RHS KEY SET KEY UNDEFINED
3915 return false;
3917 if (!emit1(JSOp::InitElem)) {
3918 // [stack] ... SET RHS LREF* RHS KEY SET
3919 return false;
3921 if (!emit1(JSOp::Pop)) {
3922 // [stack] ... SET RHS LREF* RHS KEY
3923 return false;
3928 // Get the property value.
3929 if (!emitElemOpBase(JSOp::GetElem)) {
3930 // [stack] ... SET? RHS LREF* PROP
3931 return false;
3936 if (pndefault) {
3937 if (!emitDefault(pndefault, lhs)) {
3938 // [stack] ... SET? RHS LREF* VALUE
3939 return false;
3943 // Destructure PROP per this member's lhs.
3944 if (!emitSetOrInitializeDestructuring(lhs, flav)) {
3945 // [stack] ... SET? RHS
3946 return false;
3950 return true;
3953 static bool IsDestructuringRestExclusionSetObjLiteralCompatible(
3954 ListNode* pattern) {
3955 uint32_t propCount = 0;
3956 for (ParseNode* member : pattern->contents()) {
3957 if (member->isKind(ParseNodeKind::Spread)) {
3958 MOZ_ASSERT(!member->pn_next, "unexpected trailing element after spread");
3959 break;
3962 propCount++;
3964 if (member->isKind(ParseNodeKind::MutateProto)) {
3965 continue;
3968 ParseNode* key = member->as<BinaryNode>().left();
3969 if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
3970 key->isKind(ParseNodeKind::StringExpr)) {
3971 continue;
3974 // Number and BigInt keys aren't yet supported. Computed property names need
3975 // to be added dynamically.
3976 MOZ_ASSERT(key->isKind(ParseNodeKind::NumberExpr) ||
3977 key->isKind(ParseNodeKind::BigIntExpr) ||
3978 key->isKind(ParseNodeKind::ComputedName));
3979 return false;
3982 if (propCount > SharedPropMap::MaxPropsForNonDictionary) {
3983 // JSOp::NewObject cannot accept dictionary-mode objects.
3984 return false;
3987 return true;
3990 bool BytecodeEmitter::emitDestructuringObjRestExclusionSet(ListNode* pattern) {
3991 MOZ_ASSERT(pattern->isKind(ParseNodeKind::ObjectExpr));
3992 MOZ_ASSERT(pattern->last()->isKind(ParseNodeKind::Spread));
3994 // See if we can use ObjLiteral to construct the exclusion set object.
3995 if (IsDestructuringRestExclusionSetObjLiteralCompatible(pattern)) {
3996 if (!emitDestructuringRestExclusionSetObjLiteral(pattern)) {
3997 // [stack] OBJ
3998 return false;
4000 } else {
4001 // Take the slow but sure way and start off with a blank object.
4002 if (!emit1(JSOp::NewInit)) {
4003 // [stack] OBJ
4004 return false;
4008 for (ParseNode* member : pattern->contents()) {
4009 if (member->isKind(ParseNodeKind::Spread)) {
4010 MOZ_ASSERT(!member->pn_next, "unexpected trailing element after spread");
4011 break;
4014 TaggedParserAtomIndex pnatom;
4015 if (member->isKind(ParseNodeKind::MutateProto)) {
4016 pnatom = TaggedParserAtomIndex::WellKnown::proto_();
4017 } else {
4018 ParseNode* key = member->as<BinaryNode>().left();
4019 if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
4020 key->isKind(ParseNodeKind::StringExpr)) {
4021 pnatom = key->as<NameNode>().atom();
4022 } else if (key->isKind(ParseNodeKind::NumberExpr)) {
4023 if (!emitNumberOp(key->as<NumericLiteral>().value())) {
4024 return false;
4026 } else {
4027 // Otherwise this is a computed property name which needs to be added
4028 // dynamically. BigInt keys are parsed as (synthetic) computed property
4029 // names, too.
4030 MOZ_ASSERT(key->isKind(ParseNodeKind::ComputedName));
4031 continue;
4035 // Initialize elements with |undefined|.
4036 if (!emit1(JSOp::Undefined)) {
4037 return false;
4040 if (!pnatom) {
4041 if (!emit1(JSOp::InitElem)) {
4042 return false;
4044 } else {
4045 if (!emitAtomOp(JSOp::InitProp, pnatom)) {
4046 return false;
4051 return true;
4054 bool BytecodeEmitter::emitDestructuringOps(ListNode* pattern,
4055 DestructuringFlavor flav) {
4056 if (pattern->isKind(ParseNodeKind::ArrayExpr)) {
4057 return emitDestructuringOpsArray(pattern, flav);
4059 return emitDestructuringOpsObject(pattern, flav);
4062 bool BytecodeEmitter::emitTemplateString(ListNode* templateString) {
4063 bool pushedString = false;
4065 for (ParseNode* item : templateString->contents()) {
4066 bool isString = (item->getKind() == ParseNodeKind::StringExpr ||
4067 item->getKind() == ParseNodeKind::TemplateStringExpr);
4069 // Skip empty strings. These are very common: a template string like
4070 // `${a}${b}` has three empty strings and without this optimization
4071 // we'd emit four JSOp::Add operations instead of just one.
4072 if (isString && item->as<NameNode>().atom() ==
4073 TaggedParserAtomIndex::WellKnown::empty()) {
4074 continue;
4077 if (!isString) {
4078 // We update source notes before emitting the expression
4079 if (!updateSourceCoordNotes(item->pn_pos.begin)) {
4080 return false;
4084 if (!emitTree(item)) {
4085 return false;
4088 if (!isString) {
4089 // We need to convert the expression to a string
4090 if (!emit1(JSOp::ToString)) {
4091 return false;
4095 if (pushedString) {
4096 // We've pushed two strings onto the stack. Add them together, leaving
4097 // just one.
4098 if (!emit1(JSOp::Add)) {
4099 return false;
4101 } else {
4102 pushedString = true;
4106 if (!pushedString) {
4107 // All strings were empty, this can happen for something like `${""}`.
4108 // Just push an empty string.
4109 if (!emitStringOp(JSOp::String,
4110 TaggedParserAtomIndex::WellKnown::empty())) {
4111 return false;
4115 return true;
4118 bool BytecodeEmitter::emitDeclarationList(ListNode* declList) {
4119 for (ParseNode* decl : declList->contents()) {
4120 ParseNode* pattern;
4121 ParseNode* initializer;
4122 if (decl->isKind(ParseNodeKind::Name)) {
4123 pattern = decl;
4124 initializer = nullptr;
4125 } else {
4126 AssignmentNode* assignNode = &decl->as<AssignmentNode>();
4127 pattern = assignNode->left();
4128 initializer = assignNode->right();
4131 if (pattern->isKind(ParseNodeKind::Name)) {
4132 // initializer can be null here.
4133 if (!emitSingleDeclaration(declList, &pattern->as<NameNode>(),
4134 initializer)) {
4135 return false;
4137 } else {
4138 MOZ_ASSERT(pattern->isKind(ParseNodeKind::ArrayExpr) ||
4139 pattern->isKind(ParseNodeKind::ObjectExpr));
4140 MOZ_ASSERT(initializer != nullptr);
4142 if (!updateSourceCoordNotes(initializer->pn_pos.begin)) {
4143 return false;
4145 if (!markStepBreakpoint()) {
4146 return false;
4148 if (!emitTree(initializer)) {
4149 return false;
4152 if (!emitDestructuringOps(&pattern->as<ListNode>(),
4153 DestructuringFlavor::Declaration)) {
4154 return false;
4157 if (!emit1(JSOp::Pop)) {
4158 return false;
4162 return true;
4165 bool BytecodeEmitter::emitSingleDeclaration(ListNode* declList, NameNode* decl,
4166 ParseNode* initializer) {
4167 MOZ_ASSERT(decl->isKind(ParseNodeKind::Name));
4169 // Nothing to do for initializer-less 'var' declarations, as there's no TDZ.
4170 if (!initializer && declList->isKind(ParseNodeKind::VarStmt)) {
4171 return true;
4174 auto nameAtom = decl->name();
4175 NameOpEmitter noe(this, nameAtom, NameOpEmitter::Kind::Initialize);
4176 if (!noe.prepareForRhs()) {
4177 // [stack] ENV?
4178 return false;
4180 if (!initializer) {
4181 // Lexical declarations are initialized to undefined without an
4182 // initializer.
4183 MOZ_ASSERT(declList->isKind(ParseNodeKind::LetDecl),
4184 "var declarations without initializers handled above, "
4185 "and const declarations must have initializers");
4186 if (!emit1(JSOp::Undefined)) {
4187 // [stack] ENV? UNDEF
4188 return false;
4190 } else {
4191 MOZ_ASSERT(initializer);
4193 if (!updateSourceCoordNotes(initializer->pn_pos.begin)) {
4194 return false;
4196 if (!markStepBreakpoint()) {
4197 return false;
4199 if (!emitInitializer(initializer, decl)) {
4200 // [stack] ENV? V
4201 return false;
4204 if (!noe.emitAssignment()) {
4205 // [stack] V
4206 return false;
4208 if (!emit1(JSOp::Pop)) {
4209 // [stack]
4210 return false;
4213 return true;
4216 bool BytecodeEmitter::emitAssignmentRhs(
4217 ParseNode* rhs, TaggedParserAtomIndex anonFunctionName) {
4218 if (rhs->isDirectRHSAnonFunction()) {
4219 if (anonFunctionName) {
4220 return emitAnonymousFunctionWithName(rhs, anonFunctionName);
4222 return emitAnonymousFunctionWithComputedName(rhs, FunctionPrefixKind::None);
4224 return emitTree(rhs);
4227 // The RHS value to assign is already on the stack, i.e., the next enumeration
4228 // value in a for-in or for-of loop. Offset is the location in the stack of the
4229 // already-emitted rhs. If we emitted a JSOp::BindName or JSOp::BindGName, then
4230 // the scope is on the top of the stack and we need to dig one deeper to get
4231 // the right RHS value.
4232 bool BytecodeEmitter::emitAssignmentRhs(uint8_t offset) {
4233 if (offset != 1) {
4234 return emitPickN(offset - 1);
4237 return true;
4240 static inline JSOp CompoundAssignmentParseNodeKindToJSOp(ParseNodeKind pnk) {
4241 switch (pnk) {
4242 case ParseNodeKind::InitExpr:
4243 return JSOp::Nop;
4244 case ParseNodeKind::AssignExpr:
4245 return JSOp::Nop;
4246 case ParseNodeKind::AddAssignExpr:
4247 return JSOp::Add;
4248 case ParseNodeKind::SubAssignExpr:
4249 return JSOp::Sub;
4250 case ParseNodeKind::BitOrAssignExpr:
4251 return JSOp::BitOr;
4252 case ParseNodeKind::BitXorAssignExpr:
4253 return JSOp::BitXor;
4254 case ParseNodeKind::BitAndAssignExpr:
4255 return JSOp::BitAnd;
4256 case ParseNodeKind::LshAssignExpr:
4257 return JSOp::Lsh;
4258 case ParseNodeKind::RshAssignExpr:
4259 return JSOp::Rsh;
4260 case ParseNodeKind::UrshAssignExpr:
4261 return JSOp::Ursh;
4262 case ParseNodeKind::MulAssignExpr:
4263 return JSOp::Mul;
4264 case ParseNodeKind::DivAssignExpr:
4265 return JSOp::Div;
4266 case ParseNodeKind::ModAssignExpr:
4267 return JSOp::Mod;
4268 case ParseNodeKind::PowAssignExpr:
4269 return JSOp::Pow;
4270 case ParseNodeKind::CoalesceAssignExpr:
4271 case ParseNodeKind::OrAssignExpr:
4272 case ParseNodeKind::AndAssignExpr:
4273 // Short-circuit assignment operators are handled elsewhere.
4274 [[fallthrough]];
4275 default:
4276 MOZ_CRASH("unexpected compound assignment op");
4280 bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs,
4281 ParseNode* rhs) {
4282 JSOp compoundOp = CompoundAssignmentParseNodeKindToJSOp(kind);
4283 bool isCompound = compoundOp != JSOp::Nop;
4284 bool isInit = kind == ParseNodeKind::InitExpr;
4286 // We estimate the number of properties this could create
4287 // if used as constructor merely by counting this.foo = assignment
4288 // or init expressions;
4290 // This currently doesn't handle this[x] = foo;
4291 if (isInit || kind == ParseNodeKind::AssignExpr) {
4292 if (lhs->isKind(ParseNodeKind::DotExpr)) {
4293 if (lhs->as<PropertyAccess>().expression().isKind(
4294 ParseNodeKind::ThisExpr)) {
4295 propertyAdditionEstimate++;
4300 MOZ_ASSERT_IF(isInit, lhs->isKind(ParseNodeKind::DotExpr) ||
4301 lhs->isKind(ParseNodeKind::ElemExpr) ||
4302 lhs->isKind(ParseNodeKind::PrivateMemberExpr));
4304 // |name| is used within NameOpEmitter, so its lifetime must surpass |noe|.
4305 TaggedParserAtomIndex name;
4307 Maybe<NameOpEmitter> noe;
4308 Maybe<PropOpEmitter> poe;
4309 Maybe<ElemOpEmitter> eoe;
4310 Maybe<PrivateOpEmitter> xoe;
4312 // Deal with non-name assignments.
4313 uint8_t offset = 1;
4315 // Purpose of anonFunctionName:
4317 // In normal name assignments (`f = function(){}`), an anonymous function gets
4318 // an inferred name based on the left-hand side name node.
4320 // In normal property assignments (`obj.x = function(){}`), the anonymous
4321 // function does not have a computed name, and rhs->isDirectRHSAnonFunction()
4322 // will be false (and anonFunctionName will not be used). However, in field
4323 // initializers (`class C { x = function(){} }`), field initialization is
4324 // implemented via a property or elem assignment (where we are now), and
4325 // rhs->isDirectRHSAnonFunction() is set - so we'll assign the name of the
4326 // function.
4327 TaggedParserAtomIndex anonFunctionName;
4329 switch (lhs->getKind()) {
4330 case ParseNodeKind::Name: {
4331 name = lhs->as<NameNode>().name();
4332 anonFunctionName = name;
4333 noe.emplace(this, name,
4334 isCompound ? NameOpEmitter::Kind::CompoundAssignment
4335 : NameOpEmitter::Kind::SimpleAssignment);
4336 break;
4338 case ParseNodeKind::DotExpr: {
4339 PropertyAccess* prop = &lhs->as<PropertyAccess>();
4340 bool isSuper = prop->isSuper();
4341 poe.emplace(this,
4342 isCompound ? PropOpEmitter::Kind::CompoundAssignment
4343 : isInit ? PropOpEmitter::Kind::PropInit
4344 : PropOpEmitter::Kind::SimpleAssignment,
4345 isSuper ? PropOpEmitter::ObjKind::Super
4346 : PropOpEmitter::ObjKind::Other);
4347 if (!poe->prepareForObj()) {
4348 return false;
4350 anonFunctionName = prop->name();
4351 if (isSuper) {
4352 UnaryNode* base = &prop->expression().as<UnaryNode>();
4353 if (!emitGetThisForSuperBase(base)) {
4354 // [stack] THIS SUPERBASE
4355 return false;
4357 // SUPERBASE is pushed onto THIS later in poe->emitGet below.
4358 offset += 2;
4359 } else {
4360 if (!emitTree(&prop->expression())) {
4361 // [stack] OBJ
4362 return false;
4364 offset += 1;
4366 break;
4368 case ParseNodeKind::ElemExpr: {
4369 PropertyByValue* elem = &lhs->as<PropertyByValue>();
4370 bool isSuper = elem->isSuper();
4371 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
4372 eoe.emplace(this,
4373 isCompound ? ElemOpEmitter::Kind::CompoundAssignment
4374 : isInit ? ElemOpEmitter::Kind::PropInit
4375 : ElemOpEmitter::Kind::SimpleAssignment,
4376 isSuper ? ElemOpEmitter::ObjKind::Super
4377 : ElemOpEmitter::ObjKind::Other);
4378 if (!emitElemObjAndKey(elem, isSuper, *eoe)) {
4379 // [stack] # if Super
4380 // [stack] THIS KEY
4381 // [stack] # otherwise
4382 // [stack] OBJ KEY
4383 return false;
4385 if (isSuper) {
4386 // SUPERBASE is pushed onto KEY in eoe->emitGet below.
4387 offset += 3;
4388 } else {
4389 offset += 2;
4391 break;
4393 case ParseNodeKind::PrivateMemberExpr: {
4394 PrivateMemberAccess* privateExpr = &lhs->as<PrivateMemberAccess>();
4395 xoe.emplace(this,
4396 isCompound ? PrivateOpEmitter::Kind::CompoundAssignment
4397 : isInit ? PrivateOpEmitter::Kind::PropInit
4398 : PrivateOpEmitter::Kind::SimpleAssignment,
4399 privateExpr->privateName().name());
4400 if (!emitTree(&privateExpr->expression())) {
4401 // [stack] OBJ
4402 return false;
4404 if (!xoe->emitReference()) {
4405 // [stack] OBJ KEY
4406 return false;
4408 offset += xoe->numReferenceSlots();
4409 break;
4411 case ParseNodeKind::ArrayExpr:
4412 case ParseNodeKind::ObjectExpr:
4413 break;
4414 case ParseNodeKind::CallExpr:
4415 if (!emitTree(lhs)) {
4416 return false;
4419 // Assignment to function calls is forbidden, but we have to make the
4420 // call first. Now we can throw.
4421 if (!emit2(JSOp::ThrowMsg, uint8_t(ThrowMsgKind::AssignToCall))) {
4422 return false;
4425 // Rebalance the stack to placate stack-depth assertions.
4426 if (!emit1(JSOp::Pop)) {
4427 return false;
4429 break;
4430 default:
4431 MOZ_ASSERT(0);
4434 if (isCompound) {
4435 MOZ_ASSERT(rhs);
4436 switch (lhs->getKind()) {
4437 case ParseNodeKind::DotExpr: {
4438 PropertyAccess* prop = &lhs->as<PropertyAccess>();
4439 if (!poe->emitGet(prop->key().atom())) {
4440 // [stack] # if Super
4441 // [stack] THIS SUPERBASE PROP
4442 // [stack] # otherwise
4443 // [stack] OBJ PROP
4444 return false;
4446 break;
4448 case ParseNodeKind::ElemExpr: {
4449 if (!eoe->emitGet()) {
4450 // [stack] KEY THIS OBJ ELEM
4451 return false;
4453 break;
4455 case ParseNodeKind::PrivateMemberExpr: {
4456 if (!xoe->emitGet()) {
4457 // [stack] OBJ KEY VALUE
4458 return false;
4460 break;
4462 case ParseNodeKind::CallExpr:
4463 // We just emitted a JSOp::ThrowMsg and popped the call's return
4464 // value. Push a random value to make sure the stack depth is
4465 // correct.
4466 if (!emit1(JSOp::Null)) {
4467 // [stack] NULL
4468 return false;
4470 break;
4471 default:;
4475 switch (lhs->getKind()) {
4476 case ParseNodeKind::Name:
4477 if (!noe->prepareForRhs()) {
4478 // [stack] ENV? VAL?
4479 return false;
4481 offset += noe->emittedBindOp();
4482 break;
4483 case ParseNodeKind::DotExpr:
4484 if (!poe->prepareForRhs()) {
4485 // [stack] # if Simple Assignment with Super
4486 // [stack] THIS SUPERBASE
4487 // [stack] # if Simple Assignment with other
4488 // [stack] OBJ
4489 // [stack] # if Compound Assignment with Super
4490 // [stack] THIS SUPERBASE PROP
4491 // [stack] # if Compound Assignment with other
4492 // [stack] OBJ PROP
4493 return false;
4495 break;
4496 case ParseNodeKind::ElemExpr:
4497 if (!eoe->prepareForRhs()) {
4498 // [stack] # if Simple Assignment with Super
4499 // [stack] THIS KEY SUPERBASE
4500 // [stack] # if Simple Assignment with other
4501 // [stack] OBJ KEY
4502 // [stack] # if Compound Assignment with Super
4503 // [stack] THIS KEY SUPERBASE ELEM
4504 // [stack] # if Compound Assignment with other
4505 // [stack] OBJ KEY ELEM
4506 return false;
4508 break;
4509 case ParseNodeKind::PrivateMemberExpr:
4510 // no stack adjustment needed
4511 break;
4512 default:
4513 break;
4516 if (rhs) {
4517 if (!emitAssignmentRhs(rhs, anonFunctionName)) {
4518 // [stack] ... VAL? RHS
4519 return false;
4521 } else {
4522 // Assumption: Things with pre-emitted RHS values never need to be named.
4523 if (!emitAssignmentRhs(offset)) {
4524 // [stack] ... VAL? RHS
4525 return false;
4529 /* If += etc., emit the binary operator with a hint for the decompiler. */
4530 if (isCompound) {
4531 if (!emit1(compoundOp)) {
4532 // [stack] ... VAL
4533 return false;
4535 if (!emit1(JSOp::NopIsAssignOp)) {
4536 // [stack] ... VAL
4537 return false;
4541 /* Finally, emit the specialized assignment bytecode. */
4542 switch (lhs->getKind()) {
4543 case ParseNodeKind::Name: {
4544 if (!noe->emitAssignment()) {
4545 // [stack] VAL
4546 return false;
4548 break;
4550 case ParseNodeKind::DotExpr: {
4551 PropertyAccess* prop = &lhs->as<PropertyAccess>();
4552 if (!poe->emitAssignment(prop->key().atom())) {
4553 // [stack] VAL
4554 return false;
4556 break;
4558 case ParseNodeKind::CallExpr:
4559 // We threw above, so nothing to do here.
4560 break;
4561 case ParseNodeKind::ElemExpr: {
4562 if (!eoe->emitAssignment()) {
4563 // [stack] VAL
4564 return false;
4566 break;
4568 case ParseNodeKind::PrivateMemberExpr:
4569 if (!xoe->emitAssignment()) {
4570 // [stack] VAL
4571 return false;
4573 break;
4574 case ParseNodeKind::ArrayExpr:
4575 case ParseNodeKind::ObjectExpr:
4576 if (!emitDestructuringOps(&lhs->as<ListNode>(),
4577 DestructuringFlavor::Assignment)) {
4578 return false;
4580 break;
4581 default:
4582 MOZ_ASSERT(0);
4584 return true;
4587 bool BytecodeEmitter::emitShortCircuitAssignment(AssignmentNode* node) {
4588 TDZCheckCache tdzCache(this);
4590 JSOp op;
4591 switch (node->getKind()) {
4592 case ParseNodeKind::CoalesceAssignExpr:
4593 op = JSOp::Coalesce;
4594 break;
4595 case ParseNodeKind::OrAssignExpr:
4596 op = JSOp::Or;
4597 break;
4598 case ParseNodeKind::AndAssignExpr:
4599 op = JSOp::And;
4600 break;
4601 default:
4602 MOZ_CRASH("Unexpected ParseNodeKind");
4605 ParseNode* lhs = node->left();
4606 ParseNode* rhs = node->right();
4608 // |name| is used within NameOpEmitter, so its lifetime must surpass |noe|.
4609 TaggedParserAtomIndex name;
4611 // Select the appropriate emitter based on the left-hand side.
4612 Maybe<NameOpEmitter> noe;
4613 Maybe<PropOpEmitter> poe;
4614 Maybe<ElemOpEmitter> eoe;
4615 Maybe<PrivateOpEmitter> xoe;
4617 int32_t depth = bytecodeSection().stackDepth();
4619 // Number of values pushed onto the stack in addition to the lhs value.
4620 int32_t numPushed;
4622 // Evaluate the left-hand side expression and compute any stack values needed
4623 // for the assignment.
4624 switch (lhs->getKind()) {
4625 case ParseNodeKind::Name: {
4626 name = lhs->as<NameNode>().name();
4627 noe.emplace(this, name, NameOpEmitter::Kind::CompoundAssignment);
4629 if (!noe->prepareForRhs()) {
4630 // [stack] ENV? LHS
4631 return false;
4634 numPushed = noe->emittedBindOp();
4635 break;
4638 case ParseNodeKind::DotExpr: {
4639 PropertyAccess* prop = &lhs->as<PropertyAccess>();
4640 bool isSuper = prop->isSuper();
4642 poe.emplace(this, PropOpEmitter::Kind::CompoundAssignment,
4643 isSuper ? PropOpEmitter::ObjKind::Super
4644 : PropOpEmitter::ObjKind::Other);
4646 if (!poe->prepareForObj()) {
4647 return false;
4650 if (isSuper) {
4651 UnaryNode* base = &prop->expression().as<UnaryNode>();
4652 if (!emitGetThisForSuperBase(base)) {
4653 // [stack] THIS SUPERBASE
4654 return false;
4656 } else {
4657 if (!emitTree(&prop->expression())) {
4658 // [stack] OBJ
4659 return false;
4663 if (!poe->emitGet(prop->key().atom())) {
4664 // [stack] # if Super
4665 // [stack] THIS SUPERBASE LHS
4666 // [stack] # otherwise
4667 // [stack] OBJ LHS
4668 return false;
4671 if (!poe->prepareForRhs()) {
4672 // [stack] # if Super
4673 // [stack] THIS SUPERBASE LHS
4674 // [stack] # otherwise
4675 // [stack] OBJ LHS
4676 return false;
4679 numPushed = 1 + isSuper;
4680 break;
4683 case ParseNodeKind::ElemExpr: {
4684 PropertyByValue* elem = &lhs->as<PropertyByValue>();
4685 bool isSuper = elem->isSuper();
4686 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
4687 eoe.emplace(this, ElemOpEmitter::Kind::CompoundAssignment,
4688 isSuper ? ElemOpEmitter::ObjKind::Super
4689 : ElemOpEmitter::ObjKind::Other);
4691 if (!emitElemObjAndKey(elem, isSuper, *eoe)) {
4692 // [stack] # if Super
4693 // [stack] THIS KEY
4694 // [stack] # otherwise
4695 // [stack] OBJ KEY
4696 return false;
4699 if (!eoe->emitGet()) {
4700 // [stack] # if Super
4701 // [stack] THIS KEY SUPERBASE LHS
4702 // [stack] # otherwise
4703 // [stack] OBJ KEY LHS
4704 return false;
4707 if (!eoe->prepareForRhs()) {
4708 // [stack] # if Super
4709 // [stack] THIS KEY SUPERBASE LHS
4710 // [stack] # otherwise
4711 // [stack] OBJ KEY LHS
4712 return false;
4715 numPushed = 2 + isSuper;
4716 break;
4719 case ParseNodeKind::PrivateMemberExpr: {
4720 PrivateMemberAccess* privateExpr = &lhs->as<PrivateMemberAccess>();
4721 xoe.emplace(this, PrivateOpEmitter::Kind::CompoundAssignment,
4722 privateExpr->privateName().name());
4723 if (!emitTree(&privateExpr->expression())) {
4724 // [stack] OBJ
4725 return false;
4727 if (!xoe->emitReference()) {
4728 // [stack] OBJ NAME
4729 return false;
4731 if (!xoe->emitGet()) {
4732 // [stack] OBJ NAME LHS
4733 return false;
4735 numPushed = xoe->numReferenceSlots();
4736 break;
4739 default:
4740 MOZ_CRASH();
4743 MOZ_ASSERT(bytecodeSection().stackDepth() == depth + numPushed + 1);
4745 // Test for the short-circuit condition.
4746 JumpList jump;
4747 if (!emitJump(op, &jump)) {
4748 // [stack] ... LHS
4749 return false;
4752 // The short-circuit condition wasn't fulfilled, pop the left-hand side value
4753 // which was kept on the stack.
4754 if (!emit1(JSOp::Pop)) {
4755 // [stack] ...
4756 return false;
4759 if (!emitAssignmentRhs(rhs, name)) {
4760 // [stack] ... RHS
4761 return false;
4764 // Perform the actual assignment.
4765 switch (lhs->getKind()) {
4766 case ParseNodeKind::Name: {
4767 if (!noe->emitAssignment()) {
4768 // [stack] RHS
4769 return false;
4771 break;
4774 case ParseNodeKind::DotExpr: {
4775 PropertyAccess* prop = &lhs->as<PropertyAccess>();
4777 if (!poe->emitAssignment(prop->key().atom())) {
4778 // [stack] RHS
4779 return false;
4781 break;
4784 case ParseNodeKind::ElemExpr: {
4785 if (!eoe->emitAssignment()) {
4786 // [stack] RHS
4787 return false;
4789 break;
4792 case ParseNodeKind::PrivateMemberExpr:
4793 if (!xoe->emitAssignment()) {
4794 // [stack] RHS
4795 return false;
4797 break;
4799 default:
4800 MOZ_CRASH();
4803 MOZ_ASSERT(bytecodeSection().stackDepth() == depth + 1);
4805 // Join with the short-circuit jump and pop anything left on the stack.
4806 if (numPushed > 0) {
4807 JumpList jumpAroundPop;
4808 if (!emitJump(JSOp::Goto, &jumpAroundPop)) {
4809 // [stack] RHS
4810 return false;
4813 if (!emitJumpTargetAndPatch(jump)) {
4814 // [stack] ... LHS
4815 return false;
4818 // Reconstruct the stack depth after the jump.
4819 bytecodeSection().setStackDepth(depth + 1 + numPushed);
4821 // Move the left-hand side value to the bottom and pop the rest.
4822 if (!emitUnpickN(numPushed)) {
4823 // [stack] LHS ...
4824 return false;
4826 if (!emitPopN(numPushed)) {
4827 // [stack] LHS
4828 return false;
4831 if (!emitJumpTargetAndPatch(jumpAroundPop)) {
4832 // [stack] LHS | RHS
4833 return false;
4835 } else {
4836 if (!emitJumpTargetAndPatch(jump)) {
4837 // [stack] LHS | RHS
4838 return false;
4842 MOZ_ASSERT(bytecodeSection().stackDepth() == depth + 1);
4844 return true;
4847 bool BytecodeEmitter::emitCallSiteObjectArray(ObjLiteralWriter& writer,
4848 ListNode* cookedOrRaw,
4849 ParseNode* head, uint32_t count) {
4850 DebugOnly<size_t> idx = 0;
4851 for (ParseNode* pn : cookedOrRaw->contentsFrom(head)) {
4852 MOZ_ASSERT(pn->isKind(ParseNodeKind::TemplateStringExpr) ||
4853 pn->isKind(ParseNodeKind::RawUndefinedExpr));
4855 if (!emitObjLiteralValue(writer, pn)) {
4856 return false;
4858 idx++;
4860 MOZ_ASSERT(idx == count);
4862 return true;
4865 bool BytecodeEmitter::emitCallSiteObject(CallSiteNode* callSiteObj) {
4866 constexpr JSOp op = JSOp::CallSiteObj;
4868 // The first element of a call-site node is the raw-values list. Skip over it.
4869 ListNode* raw = callSiteObj->rawNodes();
4870 MOZ_ASSERT(raw->isKind(ParseNodeKind::ArrayExpr));
4871 ParseNode* head = callSiteObj->head()->pn_next;
4873 uint32_t count = callSiteObj->count() - 1;
4874 MOZ_ASSERT(count == raw->count());
4876 ObjLiteralWriter writer;
4877 writer.beginCallSiteObj(op);
4878 writer.beginDenseArrayElements();
4880 // Write elements of the two arrays: the 'cooked' values followed by the
4881 // 'raw' values.
4882 MOZ_RELEASE_ASSERT(count < UINT32_MAX / 2,
4883 "Number of elements for both arrays must fit in uint32_t");
4884 if (!emitCallSiteObjectArray(writer, callSiteObj, head, count)) {
4885 return false;
4887 if (!emitCallSiteObjectArray(writer, raw, raw->head(), count)) {
4888 return false;
4891 GCThingIndex cookedIndex;
4892 if (!addObjLiteralData(writer, &cookedIndex)) {
4893 return false;
4896 MOZ_ASSERT(sc->hasCallSiteObj());
4898 return emitInternedObjectOp(cookedIndex, op);
4901 bool BytecodeEmitter::emitCatch(BinaryNode* catchClause) {
4902 // We must be nested under a try-finally statement.
4903 MOZ_ASSERT(innermostNestableControl->is<TryFinallyControl>());
4905 ParseNode* param = catchClause->left();
4906 if (!param) {
4907 // Catch parameter was omitted; just discard the exception.
4908 if (!emit1(JSOp::Pop)) {
4909 return false;
4911 } else {
4912 switch (param->getKind()) {
4913 case ParseNodeKind::ArrayExpr:
4914 case ParseNodeKind::ObjectExpr:
4915 if (!emitDestructuringOps(&param->as<ListNode>(),
4916 DestructuringFlavor::Declaration)) {
4917 return false;
4919 if (!emit1(JSOp::Pop)) {
4920 return false;
4922 break;
4924 case ParseNodeKind::Name:
4925 if (!emitLexicalInitialization(&param->as<NameNode>())) {
4926 return false;
4928 if (!emit1(JSOp::Pop)) {
4929 return false;
4931 break;
4933 default:
4934 MOZ_ASSERT(0);
4938 /* Emit the catch body. */
4939 return emitTree(catchClause->right());
4942 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See the
4943 // comment on EmitSwitch.
4944 MOZ_NEVER_INLINE bool BytecodeEmitter::emitTry(TryNode* tryNode) {
4945 LexicalScopeNode* catchScope = tryNode->catchScope();
4946 ParseNode* finallyNode = tryNode->finallyBlock();
4948 TryEmitter::Kind kind;
4949 if (catchScope) {
4950 if (finallyNode) {
4951 kind = TryEmitter::Kind::TryCatchFinally;
4952 } else {
4953 kind = TryEmitter::Kind::TryCatch;
4955 } else {
4956 MOZ_ASSERT(finallyNode);
4957 kind = TryEmitter::Kind::TryFinally;
4959 TryEmitter tryCatch(this, kind, TryEmitter::ControlKind::Syntactic);
4961 if (!tryCatch.emitTry()) {
4962 return false;
4965 if (!emitTree(tryNode->body())) {
4966 return false;
4969 // If this try has a catch block, emit it.
4970 if (catchScope) {
4971 // The emitted code for a catch block looks like:
4973 // [pushlexicalenv] only if any local aliased
4974 // exception
4975 // setlocal 0; pop assign or possibly destructure exception
4976 // < catch block contents >
4977 // debugleaveblock
4978 // [poplexicalenv] only if any local aliased
4979 // if there is a finally block:
4980 // goto <finally>
4981 // [jump target for returning from finally]
4982 // goto <after finally>
4983 if (!tryCatch.emitCatch()) {
4984 return false;
4987 // Emit the lexical scope and catch body.
4988 if (!emitTree(catchScope)) {
4989 return false;
4993 // Emit the finally handler, if there is one.
4994 if (finallyNode) {
4995 if (!tryCatch.emitFinally(Some(finallyNode->pn_pos.begin))) {
4996 return false;
4999 if (!emitTree(finallyNode)) {
5000 return false;
5004 if (!tryCatch.emitEnd()) {
5005 return false;
5008 return true;
5011 [[nodiscard]] bool BytecodeEmitter::emitJumpToFinally(JumpList* jump,
5012 uint32_t idx) {
5013 // Push the continuation index.
5014 if (!emitNumberOp(idx)) {
5015 return false;
5018 // Push |throwing|.
5019 if (!emit1(JSOp::False)) {
5020 return false;
5023 // Jump to the finally block.
5024 if (!emitJumpNoFallthrough(JSOp::Goto, jump)) {
5025 return false;
5028 return true;
5031 bool BytecodeEmitter::emitIf(TernaryNode* ifNode) {
5032 IfEmitter ifThenElse(this);
5034 if (!ifThenElse.emitIf(Some(ifNode->kid1()->pn_pos.begin))) {
5035 return false;
5038 if_again:
5039 ParseNode* testNode = ifNode->kid1();
5040 auto conditionKind = IfEmitter::ConditionKind::Positive;
5041 if (testNode->isKind(ParseNodeKind::NotExpr)) {
5042 testNode = testNode->as<UnaryNode>().kid();
5043 conditionKind = IfEmitter::ConditionKind::Negative;
5046 if (!markStepBreakpoint()) {
5047 return false;
5050 // Emit code for the condition before pushing stmtInfo.
5051 // NOTE: NotExpr of testNode may be unwrapped, and in that case the negation
5052 // is handled by conditionKind.
5053 if (!emitTree(testNode)) {
5054 return false;
5057 ParseNode* elseNode = ifNode->kid3();
5058 if (elseNode) {
5059 if (!ifThenElse.emitThenElse(conditionKind)) {
5060 return false;
5062 } else {
5063 if (!ifThenElse.emitThen(conditionKind)) {
5064 return false;
5068 /* Emit code for the then part. */
5069 if (!emitTree(ifNode->kid2())) {
5070 return false;
5073 if (elseNode) {
5074 if (elseNode->isKind(ParseNodeKind::IfStmt)) {
5075 ifNode = &elseNode->as<TernaryNode>();
5077 if (!ifThenElse.emitElseIf(Some(ifNode->kid1()->pn_pos.begin))) {
5078 return false;
5081 goto if_again;
5084 if (!ifThenElse.emitElse()) {
5085 return false;
5088 /* Emit code for the else part. */
5089 if (!emitTree(elseNode)) {
5090 return false;
5094 if (!ifThenElse.emitEnd()) {
5095 return false;
5098 return true;
5101 bool BytecodeEmitter::emitHoistedFunctionsInList(ListNode* stmtList) {
5102 MOZ_ASSERT(stmtList->hasTopLevelFunctionDeclarations());
5104 // We can call this multiple times for sloppy eval scopes.
5105 if (stmtList->emittedTopLevelFunctionDeclarations()) {
5106 return true;
5109 stmtList->setEmittedTopLevelFunctionDeclarations();
5111 for (ParseNode* stmt : stmtList->contents()) {
5112 ParseNode* maybeFun = stmt;
5114 if (!sc->strict()) {
5115 while (maybeFun->isKind(ParseNodeKind::LabelStmt)) {
5116 maybeFun = maybeFun->as<LabeledStatement>().statement();
5120 if (maybeFun->is<FunctionNode>() &&
5121 maybeFun->as<FunctionNode>().functionIsHoisted()) {
5122 if (!emitTree(maybeFun)) {
5123 return false;
5128 return true;
5131 bool BytecodeEmitter::emitLexicalScopeBody(
5132 ParseNode* body, EmitLineNumberNote emitLineNote /* = EMIT_LINENOTE */) {
5133 if (body->isKind(ParseNodeKind::StatementList) &&
5134 body->as<ListNode>().hasTopLevelFunctionDeclarations()) {
5135 // This block contains function statements whose definitions are
5136 // hoisted to the top of the block. Emit these as a separate pass
5137 // before the rest of the block.
5138 if (!emitHoistedFunctionsInList(&body->as<ListNode>())) {
5139 return false;
5143 // Line notes were updated by emitLexicalScope or emitScript.
5144 return emitTree(body, ValueUsage::WantValue, emitLineNote);
5147 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
5148 // the comment on emitSwitch.
5149 MOZ_NEVER_INLINE bool BytecodeEmitter::emitLexicalScope(
5150 LexicalScopeNode* lexicalScope) {
5151 LexicalScopeEmitter lse(this);
5153 ParseNode* body = lexicalScope->scopeBody();
5154 if (lexicalScope->isEmptyScope()) {
5155 if (!lse.emitEmptyScope()) {
5156 return false;
5159 if (!emitLexicalScopeBody(body)) {
5160 return false;
5163 if (!lse.emitEnd()) {
5164 return false;
5167 return true;
5170 // We are about to emit some bytecode for what the spec calls "declaration
5171 // instantiation". Assign these instructions to the opening `{` of the
5172 // block. (Using the location of each declaration we're instantiating is
5173 // too weird when stepping in the debugger.)
5174 if (!ParseNodeRequiresSpecialLineNumberNotes(body)) {
5175 if (!updateSourceCoordNotes(lexicalScope->pn_pos.begin)) {
5176 return false;
5180 ScopeKind kind;
5181 if (body->isKind(ParseNodeKind::Catch)) {
5182 BinaryNode* catchNode = &body->as<BinaryNode>();
5183 kind =
5184 (!catchNode->left() || catchNode->left()->isKind(ParseNodeKind::Name))
5185 ? ScopeKind::SimpleCatch
5186 : ScopeKind::Catch;
5187 } else {
5188 kind = lexicalScope->kind();
5191 if (!lse.emitScope(kind, lexicalScope->scopeBindings())) {
5192 return false;
5195 if (body->isKind(ParseNodeKind::ForStmt)) {
5196 // for loops need to emit JSOp::FreshenLexicalEnv/JSOp::RecreateLexicalEnv
5197 // if there are lexical declarations in the head. Signal this by passing a
5198 // non-nullptr lexical scope.
5199 if (!emitFor(&body->as<ForNode>(), &lse.emitterScope())) {
5200 return false;
5202 } else {
5203 if (!emitLexicalScopeBody(body, SUPPRESS_LINENOTE)) {
5204 return false;
5208 if (!lse.emitEnd()) {
5209 return false;
5211 return true;
5214 bool BytecodeEmitter::emitWith(BinaryNode* withNode) {
5215 // Ensure that the column of the 'with' is set properly.
5216 if (!updateSourceCoordNotes(withNode->left()->pn_pos.begin)) {
5217 return false;
5220 if (!markStepBreakpoint()) {
5221 return false;
5224 if (!emitTree(withNode->left())) {
5225 return false;
5228 EmitterScope emitterScope(this);
5229 if (!emitterScope.enterWith(this)) {
5230 return false;
5233 if (!emitTree(withNode->right())) {
5234 return false;
5237 return emitterScope.leave(this);
5240 bool BytecodeEmitter::emitCopyDataProperties(CopyOption option) {
5241 DebugOnly<int32_t> depth = bytecodeSection().stackDepth();
5243 uint32_t argc;
5244 if (option == CopyOption::Filtered) {
5245 MOZ_ASSERT(depth > 2);
5246 // [stack] TARGET SOURCE SET
5247 argc = 3;
5249 if (!emitAtomOp(JSOp::GetIntrinsic,
5250 TaggedParserAtomIndex::WellKnown::CopyDataProperties())) {
5251 // [stack] TARGET SOURCE SET COPYDATAPROPERTIES
5252 return false;
5254 } else {
5255 MOZ_ASSERT(depth > 1);
5256 // [stack] TARGET SOURCE
5257 argc = 2;
5259 if (!emitAtomOp(
5260 JSOp::GetIntrinsic,
5261 TaggedParserAtomIndex::WellKnown::CopyDataPropertiesUnfiltered())) {
5262 // [stack] TARGET SOURCE COPYDATAPROPERTIES
5263 return false;
5267 if (!emit1(JSOp::Undefined)) {
5268 // [stack] TARGET SOURCE SET? COPYDATAPROPERTIES
5269 // UNDEFINED
5270 return false;
5272 if (!emit2(JSOp::Pick, argc + 1)) {
5273 // [stack] SOURCE SET? COPYDATAPROPERTIES UNDEFINED
5274 // TARGET
5275 return false;
5277 if (!emit2(JSOp::Pick, argc + 1)) {
5278 // [stack] SET? COPYDATAPROPERTIES UNDEFINED TARGET
5279 // SOURCE
5280 return false;
5282 if (option == CopyOption::Filtered) {
5283 if (!emit2(JSOp::Pick, argc + 1)) {
5284 // [stack] COPYDATAPROPERTIES UNDEFINED TARGET SOURCE SET
5285 return false;
5288 // Callee is always self-hosted instrinsic, and cannot be content function.
5289 if (!emitCall(JSOp::CallIgnoresRv, argc)) {
5290 // [stack] IGNORED
5291 return false;
5294 if (!emit1(JSOp::Pop)) {
5295 // [stack]
5296 return false;
5299 MOZ_ASSERT(depth - int(argc) == bytecodeSection().stackDepth());
5300 return true;
5303 bool BytecodeEmitter::emitBigIntOp(BigIntLiteral* bigint) {
5304 GCThingIndex index;
5305 if (!perScriptData().gcThingList().append(bigint, &index)) {
5306 return false;
5308 return emitGCIndexOp(JSOp::BigInt, index);
5311 bool BytecodeEmitter::emitIterable(ParseNode* value,
5312 SelfHostedIter selfHostedIter,
5313 IteratorKind iterKind) {
5314 MOZ_ASSERT(getSelfHostedIterFor(value) == selfHostedIter);
5316 if (!emitTree(value)) {
5317 // [stack] ITERABLE
5318 return false;
5321 switch (selfHostedIter) {
5322 case SelfHostedIter::Deny:
5323 case SelfHostedIter::AllowContent:
5324 // [stack] ITERABLE
5325 return true;
5327 case SelfHostedIter::AllowContentWith: {
5328 // This is the following case:
5330 // for (const nextValue of allowContentIterWith(items, usingIterator)) {
5332 // `items` is emitted by `emitTree(value)` above, and the result is on the
5333 // stack as ITERABLE.
5334 // `usingIterator` is the value of `items[Symbol.iterator]`, that's
5335 // already retrieved.
5336 ListNode* argsList = value->as<CallNode>().args();
5337 MOZ_ASSERT_IF(iterKind == IteratorKind::Sync, argsList->count() == 2);
5338 MOZ_ASSERT_IF(iterKind == IteratorKind::Async, argsList->count() == 3);
5340 if (!emitTree(argsList->head()->pn_next)) {
5341 // [stack] ITERABLE ITERFN
5342 return false;
5345 // Async iterator has two possible iterators: An async iterator and a sync
5346 // iterator.
5347 if (iterKind == IteratorKind::Async) {
5348 if (!emitTree(argsList->head()->pn_next->pn_next)) {
5349 // [stack] ITERABLE ASYNC_ITERFN SYNC_ITERFN
5350 return false;
5354 // [stack] ITERABLE ASYNC_ITERFN? SYNC_ITERFN
5355 return true;
5358 case SelfHostedIter::AllowContentWithNext: {
5359 // This is the following case:
5361 // for (const nextValue of allowContentIterWithNext(iterator, next)) {
5363 // `iterator` is emitted by `emitTree(value)` above, and the result is on
5364 // the stack as ITER.
5365 // `next` is the value of `iterator.next`, that's already retrieved.
5366 ListNode* argsList = value->as<CallNode>().args();
5367 MOZ_ASSERT(argsList->count() == 2);
5369 if (!emitTree(argsList->head()->pn_next)) {
5370 // [stack] ITER NEXT
5371 return false;
5374 if (!emit1(JSOp::Swap)) {
5375 // [stack] NEXT ITER
5376 return false;
5379 // [stack] NEXT ITER
5380 return true;
5384 MOZ_CRASH("invalid self-hosted iteration kind");
5387 bool BytecodeEmitter::emitIterator(SelfHostedIter selfHostedIter) {
5388 MOZ_ASSERT(selfHostedIter != SelfHostedIter::Deny ||
5389 emitterMode != BytecodeEmitter::SelfHosting,
5390 "[Symbol.iterator]() call is prohibited in self-hosted code "
5391 "because it can run user-modifiable iteration code");
5393 if (selfHostedIter == SelfHostedIter::AllowContentWithNext) {
5394 // [stack] NEXT ITER
5396 // Nothing to do, stack already contains the iterator and its `next` method.
5397 return true;
5400 if (selfHostedIter != SelfHostedIter::AllowContentWith) {
5401 // [stack] OBJ
5403 // Convert iterable to iterator.
5404 if (!emit1(JSOp::Dup)) {
5405 // [stack] OBJ OBJ
5406 return false;
5408 if (!emit2(JSOp::Symbol, uint8_t(JS::SymbolCode::iterator))) {
5409 // [stack] OBJ OBJ @@ITERATOR
5410 return false;
5412 if (!emitElemOpBase(JSOp::GetElem)) {
5413 // [stack] OBJ ITERFN
5414 return false;
5418 if (!emit1(JSOp::Swap)) {
5419 // [stack] ITERFN OBJ
5420 return false;
5422 if (!emitCall(getIterCallOp(JSOp::CallIter, selfHostedIter), 0)) {
5423 // [stack] ITER
5424 return false;
5426 if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) {
5427 // [stack] ITER
5428 return false;
5430 if (!emit1(JSOp::Dup)) {
5431 // [stack] ITER ITER
5432 return false;
5434 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::next())) {
5435 // [stack] ITER NEXT
5436 return false;
5438 if (!emit1(JSOp::Swap)) {
5439 // [stack] NEXT ITER
5440 return false;
5442 return true;
5445 bool BytecodeEmitter::emitAsyncIterator(SelfHostedIter selfHostedIter) {
5446 MOZ_ASSERT(selfHostedIter != SelfHostedIter::AllowContentWithNext);
5447 MOZ_ASSERT(selfHostedIter != SelfHostedIter::Deny ||
5448 emitterMode != BytecodeEmitter::SelfHosting,
5449 "[Symbol.asyncIterator]() call is prohibited in self-hosted code "
5450 "because it can run user-modifiable iteration code");
5452 if (selfHostedIter != SelfHostedIter::AllowContentWith) {
5453 // [stack] OBJ
5455 // Convert iterable to iterator.
5456 if (!emit1(JSOp::Dup)) {
5457 // [stack] OBJ OBJ
5458 return false;
5460 if (!emit2(JSOp::Symbol, uint8_t(JS::SymbolCode::asyncIterator))) {
5461 // [stack] OBJ OBJ @@ASYNCITERATOR
5462 return false;
5464 if (!emitElemOpBase(JSOp::GetElem)) {
5465 // [stack] OBJ ASYNC_ITERFN
5466 return false;
5468 } else {
5469 // [stack] OBJ ASYNC_ITERFN SYNC_ITERFN
5471 if (!emitElemOpBase(JSOp::Swap)) {
5472 // [stack] OBJ SYNC_ITERFN ASYNC_ITERFN
5473 return false;
5477 InternalIfEmitter ifAsyncIterIsUndefined(this);
5478 if (!emit1(JSOp::IsNullOrUndefined)) {
5479 // [stack] OBJ SYNC_ITERFN? ASYNC_ITERFN NULL-OR-UNDEF
5480 return false;
5482 if (!ifAsyncIterIsUndefined.emitThenElse()) {
5483 // [stack] OBJ SYNC_ITERFN? ASYNC_ITERFN
5484 return false;
5487 if (!emit1(JSOp::Pop)) {
5488 // [stack] OBJ SYNC_ITERFN?
5489 return false;
5492 if (selfHostedIter != SelfHostedIter::AllowContentWith) {
5493 if (!emit1(JSOp::Dup)) {
5494 // [stack] OBJ OBJ
5495 return false;
5497 if (!emit2(JSOp::Symbol, uint8_t(JS::SymbolCode::iterator))) {
5498 // [stack] OBJ OBJ @@ITERATOR
5499 return false;
5501 if (!emitElemOpBase(JSOp::GetElem)) {
5502 // [stack] OBJ SYNC_ITERFN
5503 return false;
5505 } else {
5506 // [stack] OBJ SYNC_ITERFN
5509 if (!emit1(JSOp::Swap)) {
5510 // [stack] SYNC_ITERFN OBJ
5511 return false;
5513 if (!emitCall(getIterCallOp(JSOp::CallIter, selfHostedIter), 0)) {
5514 // [stack] ITER
5515 return false;
5517 if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) {
5518 // [stack] ITER
5519 return false;
5522 if (!emit1(JSOp::Dup)) {
5523 // [stack] ITER ITER
5524 return false;
5526 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::next())) {
5527 // [stack] ITER SYNCNEXT
5528 return false;
5531 if (!emit1(JSOp::ToAsyncIter)) {
5532 // [stack] ITER
5533 return false;
5536 if (!ifAsyncIterIsUndefined.emitElse()) {
5537 // [stack] OBJ SYNC_ITERFN? ASYNC_ITERFN
5538 return false;
5541 if (selfHostedIter == SelfHostedIter::AllowContentWith) {
5542 if (!emit1(JSOp::Swap)) {
5543 // [stack] OBJ ASYNC_ITERFN SYNC_ITERFN
5544 return false;
5546 if (!emit1(JSOp::Pop)) {
5547 // [stack] OBJ ASYNC_ITERFN
5548 return false;
5552 if (!emit1(JSOp::Swap)) {
5553 // [stack] ASYNC_ITERFN OBJ
5554 return false;
5556 if (!emitCall(getIterCallOp(JSOp::CallIter, selfHostedIter), 0)) {
5557 // [stack] ITER
5558 return false;
5560 if (!emitCheckIsObj(CheckIsObjectKind::GetAsyncIterator)) {
5561 // [stack] ITER
5562 return false;
5565 if (!ifAsyncIterIsUndefined.emitEnd()) {
5566 // [stack] ITER
5567 return false;
5570 if (!emit1(JSOp::Dup)) {
5571 // [stack] ITER ITER
5572 return false;
5574 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::next())) {
5575 // [stack] ITER NEXT
5576 return false;
5578 if (!emit1(JSOp::Swap)) {
5579 // [stack] NEXT ITER
5580 return false;
5583 return true;
5586 bool BytecodeEmitter::emitSpread(SelfHostedIter selfHostedIter) {
5587 // [stack] NEXT ITER ARR I
5588 return emitSpread(selfHostedIter, 2, JSOp::InitElemInc);
5589 // [stack] ARR FINAL_INDEX
5592 bool BytecodeEmitter::emitSpread(SelfHostedIter selfHostedIter,
5593 int spreadeeStackItems, JSOp storeElementOp) {
5594 LoopControl loopInfo(this, StatementKind::Spread);
5595 // In the [stack] annotations, (spreadee) can be "ARR I" (when spreading
5596 // into an array or into call parameters, or "TUPLE" (when spreading into a
5597 // tuple)
5599 if (!loopInfo.emitLoopHead(this, Nothing())) {
5600 // [stack] NEXT ITER (spreadee)
5601 return false;
5605 #ifdef DEBUG
5606 auto loopDepth = bytecodeSection().stackDepth();
5607 #endif
5609 // Spread operations can't contain |continue|, so don't bother setting loop
5610 // and enclosing "update" offsets, as we do with for-loops.
5612 if (!emitDupAt(spreadeeStackItems + 1, 2)) {
5613 // [stack] NEXT ITER (spreadee) NEXT ITER
5614 return false;
5616 if (!emitIteratorNext(Nothing(), IteratorKind::Sync, selfHostedIter)) {
5617 // [stack] NEXT ITER (spreadee) RESULT
5618 return false;
5620 if (!emit1(JSOp::Dup)) {
5621 // [stack] NEXT ITER (spreadee) RESULT RESULT
5622 return false;
5624 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::done())) {
5625 // [stack] NEXT ITER (spreadee) RESULT DONE
5626 return false;
5628 if (!emitJump(JSOp::JumpIfTrue, &loopInfo.breaks)) {
5629 // [stack] NEXT ITER (spreadee) RESULT
5630 return false;
5633 // Emit code to assign result.value to the iteration variable.
5634 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::value())) {
5635 // [stack] NEXT ITER (spreadee) VALUE
5636 return false;
5638 if (!emit1(storeElementOp)) {
5639 // [stack] NEXT ITER (spreadee)
5640 return false;
5643 if (!loopInfo.emitLoopEnd(this, JSOp::Goto, TryNoteKind::ForOf)) {
5644 // [stack] NEXT ITER (spreadee)
5645 return false;
5648 MOZ_ASSERT(bytecodeSection().stackDepth() == loopDepth);
5651 // When we leave the loop body and jump to this point, the result value is
5652 // still on the stack. Account for that by updating the stack depth
5653 // manually.
5654 bytecodeSection().setStackDepth(bytecodeSection().stackDepth() + 1);
5656 // No continues should occur in spreads.
5657 MOZ_ASSERT(!loopInfo.continues.offset.valid());
5659 if (!emit2(JSOp::Pick, spreadeeStackItems + 2)) {
5660 // [stack] ITER (spreadee) RESULT NEXT
5661 return false;
5663 if (!emit2(JSOp::Pick, spreadeeStackItems + 2)) {
5664 // [stack] (spreadee) RESULT NEXT ITER
5665 return false;
5668 return emitPopN(3);
5669 // [stack] (spreadee)
5672 bool BytecodeEmitter::emitInitializeForInOrOfTarget(TernaryNode* forHead) {
5673 MOZ_ASSERT(forHead->isKind(ParseNodeKind::ForIn) ||
5674 forHead->isKind(ParseNodeKind::ForOf));
5676 MOZ_ASSERT(bytecodeSection().stackDepth() >= 1,
5677 "must have a per-iteration value for initializing");
5679 ParseNode* target = forHead->kid1();
5680 MOZ_ASSERT(!forHead->kid2());
5682 // If the for-in/of loop didn't have a variable declaration, per-loop
5683 // initialization is just assigning the iteration value to a target
5684 // expression.
5685 if (!target->is<DeclarationListNode>()) {
5686 return emitAssignmentOrInit(ParseNodeKind::AssignExpr, target, nullptr);
5687 // [stack] ... ITERVAL
5690 // Otherwise, per-loop initialization is (possibly) declaration
5691 // initialization. If the declaration is a lexical declaration, it must be
5692 // initialized. If the declaration is a variable declaration, an
5693 // assignment to that name (which does *not* necessarily assign to the
5694 // variable!) must be generated.
5696 auto* declarationList = &target->as<DeclarationListNode>();
5697 if (!updateSourceCoordNotes(declarationList->pn_pos.begin)) {
5698 return false;
5701 target = declarationList->singleBinding();
5703 NameNode* nameNode = nullptr;
5704 if (target->isKind(ParseNodeKind::Name)) {
5705 nameNode = &target->as<NameNode>();
5706 } else if (target->isKind(ParseNodeKind::AssignExpr)) {
5707 BinaryNode* assignNode = &target->as<BinaryNode>();
5708 if (assignNode->left()->is<NameNode>()) {
5709 nameNode = &assignNode->left()->as<NameNode>();
5713 if (nameNode) {
5714 auto nameAtom = nameNode->name();
5715 NameOpEmitter noe(this, nameAtom, NameOpEmitter::Kind::Initialize);
5716 if (!noe.prepareForRhs()) {
5717 return false;
5719 if (noe.emittedBindOp()) {
5720 // Per-iteration initialization in for-in/of loops computes the
5721 // iteration value *before* initializing. Thus the initializing
5722 // value may be buried under a bind-specific value on the stack.
5723 // Swap it to the top of the stack.
5724 MOZ_ASSERT(bytecodeSection().stackDepth() >= 2);
5725 if (!emit1(JSOp::Swap)) {
5726 return false;
5728 } else {
5729 // In cases of emitting a frame slot or environment slot,
5730 // nothing needs be done.
5731 MOZ_ASSERT(bytecodeSection().stackDepth() >= 1);
5733 if (!noe.emitAssignment()) {
5734 return false;
5737 // The caller handles removing the iteration value from the stack.
5738 return true;
5741 MOZ_ASSERT(
5742 !target->isKind(ParseNodeKind::AssignExpr),
5743 "for-in/of loop destructuring declarations can't have initializers");
5745 MOZ_ASSERT(target->isKind(ParseNodeKind::ArrayExpr) ||
5746 target->isKind(ParseNodeKind::ObjectExpr));
5747 return emitDestructuringOps(&target->as<ListNode>(),
5748 DestructuringFlavor::Declaration);
5751 bool BytecodeEmitter::emitForOf(ForNode* forOfLoop,
5752 const EmitterScope* headLexicalEmitterScope) {
5753 MOZ_ASSERT(forOfLoop->isKind(ParseNodeKind::ForStmt));
5755 TernaryNode* forOfHead = forOfLoop->head();
5756 MOZ_ASSERT(forOfHead->isKind(ParseNodeKind::ForOf));
5758 unsigned iflags = forOfLoop->iflags();
5759 IteratorKind iterKind =
5760 (iflags & JSITER_FORAWAITOF) ? IteratorKind::Async : IteratorKind::Sync;
5761 MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->isSuspendableContext());
5762 MOZ_ASSERT_IF(iterKind == IteratorKind::Async,
5763 sc->asSuspendableContext()->isAsync());
5765 ParseNode* forHeadExpr = forOfHead->kid3();
5767 // Certain builtins (e.g. Array.from) are implemented in self-hosting
5768 // as for-of loops.
5769 auto selfHostedIter = getSelfHostedIterFor(forHeadExpr);
5770 ForOfEmitter forOf(this, headLexicalEmitterScope, selfHostedIter, iterKind);
5772 if (!forOf.emitIterated()) {
5773 // [stack]
5774 return false;
5777 if (!updateSourceCoordNotes(forHeadExpr->pn_pos.begin)) {
5778 return false;
5780 if (!markStepBreakpoint()) {
5781 return false;
5783 if (!emitIterable(forHeadExpr, selfHostedIter, iterKind)) {
5784 // [stack] ITERABLE
5785 return false;
5788 if (headLexicalEmitterScope) {
5789 DebugOnly<ParseNode*> forOfTarget = forOfHead->kid1();
5790 MOZ_ASSERT(forOfTarget->isKind(ParseNodeKind::LetDecl) ||
5791 forOfTarget->isKind(ParseNodeKind::ConstDecl));
5794 if (!forOf.emitInitialize(forOfHead->pn_pos.begin)) {
5795 // [stack] NEXT ITER VALUE
5796 return false;
5799 if (!emitInitializeForInOrOfTarget(forOfHead)) {
5800 // [stack] NEXT ITER VALUE
5801 return false;
5804 if (!forOf.emitBody()) {
5805 // [stack] NEXT ITER UNDEF
5806 return false;
5809 // Perform the loop body.
5810 ParseNode* forBody = forOfLoop->body();
5811 if (!emitTree(forBody)) {
5812 // [stack] NEXT ITER UNDEF
5813 return false;
5816 if (!forOf.emitEnd(forHeadExpr->pn_pos.begin)) {
5817 // [stack]
5818 return false;
5821 return true;
5824 bool BytecodeEmitter::emitForIn(ForNode* forInLoop,
5825 const EmitterScope* headLexicalEmitterScope) {
5826 TernaryNode* forInHead = forInLoop->head();
5827 MOZ_ASSERT(forInHead->isKind(ParseNodeKind::ForIn));
5829 ForInEmitter forIn(this, headLexicalEmitterScope);
5831 // Annex B: Evaluate the var-initializer expression if present.
5832 // |for (var i = initializer in expr) { ... }|
5833 ParseNode* forInTarget = forInHead->kid1();
5834 if (forInTarget->is<DeclarationListNode>()) {
5835 auto* declarationList = &forInTarget->as<DeclarationListNode>();
5837 ParseNode* decl = declarationList->singleBinding();
5838 if (decl->isKind(ParseNodeKind::AssignExpr)) {
5839 BinaryNode* assignNode = &decl->as<BinaryNode>();
5840 if (assignNode->left()->is<NameNode>()) {
5841 NameNode* nameNode = &assignNode->left()->as<NameNode>();
5842 ParseNode* initializer = assignNode->right();
5843 MOZ_ASSERT(
5844 forInTarget->isKind(ParseNodeKind::VarStmt),
5845 "for-in initializers are only permitted for |var| declarations");
5847 if (!updateSourceCoordNotes(decl->pn_pos.begin)) {
5848 return false;
5851 auto nameAtom = nameNode->name();
5852 NameOpEmitter noe(this, nameAtom, NameOpEmitter::Kind::Initialize);
5853 if (!noe.prepareForRhs()) {
5854 return false;
5856 if (!emitInitializer(initializer, nameNode)) {
5857 return false;
5859 if (!noe.emitAssignment()) {
5860 return false;
5863 // Pop the initializer.
5864 if (!emit1(JSOp::Pop)) {
5865 return false;
5871 if (!forIn.emitIterated()) {
5872 // [stack]
5873 return false;
5876 // Evaluate the expression being iterated.
5877 ParseNode* expr = forInHead->kid3();
5879 if (!updateSourceCoordNotes(expr->pn_pos.begin)) {
5880 return false;
5882 if (!markStepBreakpoint()) {
5883 return false;
5885 if (!emitTree(expr)) {
5886 // [stack] EXPR
5887 return false;
5890 MOZ_ASSERT(forInLoop->iflags() == 0);
5892 MOZ_ASSERT_IF(headLexicalEmitterScope,
5893 forInTarget->isKind(ParseNodeKind::LetDecl) ||
5894 forInTarget->isKind(ParseNodeKind::ConstDecl));
5896 if (!forIn.emitInitialize()) {
5897 // [stack] ITER ITERVAL
5898 return false;
5901 if (!emitInitializeForInOrOfTarget(forInHead)) {
5902 // [stack] ITER ITERVAL
5903 return false;
5906 if (!forIn.emitBody()) {
5907 // [stack] ITER ITERVAL
5908 return false;
5911 // Perform the loop body.
5912 ParseNode* forBody = forInLoop->body();
5913 if (!emitTree(forBody)) {
5914 // [stack] ITER ITERVAL
5915 return false;
5918 if (!forIn.emitEnd(forInHead->pn_pos.begin)) {
5919 // [stack]
5920 return false;
5923 return true;
5926 /* C-style `for (init; cond; update) ...` loop. */
5927 bool BytecodeEmitter::emitCStyleFor(
5928 ForNode* forNode, const EmitterScope* headLexicalEmitterScope) {
5929 TernaryNode* forHead = forNode->head();
5930 ParseNode* forBody = forNode->body();
5931 ParseNode* init = forHead->kid1();
5932 ParseNode* cond = forHead->kid2();
5933 ParseNode* update = forHead->kid3();
5934 bool isLet = init && init->isKind(ParseNodeKind::LetDecl);
5936 CForEmitter cfor(this, isLet ? headLexicalEmitterScope : nullptr);
5938 if (!cfor.emitInit(init ? Some(init->pn_pos.begin) : Nothing())) {
5939 // [stack]
5940 return false;
5943 // If the head of this for-loop declared any lexical variables, the parser
5944 // wrapped this ParseNodeKind::For node in a ParseNodeKind::LexicalScope
5945 // representing the implicit scope of those variables. By the time we get
5946 // here, we have already entered that scope. So far, so good.
5947 if (init) {
5948 // Emit the `init` clause, whether it's an expression or a variable
5949 // declaration. (The loop variables were hoisted into an enclosing
5950 // scope, but we still need to emit code for the initializers.)
5951 if (init->is<DeclarationListNode>()) {
5952 MOZ_ASSERT(!init->as<DeclarationListNode>().empty());
5954 if (!emitTree(init)) {
5955 // [stack]
5956 return false;
5958 } else {
5959 if (!updateSourceCoordNotes(init->pn_pos.begin)) {
5960 return false;
5962 if (!markStepBreakpoint()) {
5963 return false;
5966 // 'init' is an expression, not a declaration. emitTree left its
5967 // value on the stack.
5968 if (!emitTree(init, ValueUsage::IgnoreValue)) {
5969 // [stack] VAL
5970 return false;
5972 if (!emit1(JSOp::Pop)) {
5973 // [stack]
5974 return false;
5979 if (!cfor.emitCond(cond ? Some(cond->pn_pos.begin) : Nothing())) {
5980 // [stack]
5981 return false;
5984 if (cond) {
5985 if (!updateSourceCoordNotes(cond->pn_pos.begin)) {
5986 return false;
5988 if (!markStepBreakpoint()) {
5989 return false;
5991 if (!emitTree(cond)) {
5992 // [stack] VAL
5993 return false;
5997 if (!cfor.emitBody(cond ? CForEmitter::Cond::Present
5998 : CForEmitter::Cond::Missing)) {
5999 // [stack]
6000 return false;
6003 if (!emitTree(forBody)) {
6004 // [stack]
6005 return false;
6008 if (!cfor.emitUpdate(
6009 update ? CForEmitter::Update::Present : CForEmitter::Update::Missing,
6010 update ? Some(update->pn_pos.begin) : Nothing())) {
6011 // [stack]
6012 return false;
6015 // Check for update code to do before the condition (if any).
6016 if (update) {
6017 if (!updateSourceCoordNotes(update->pn_pos.begin)) {
6018 return false;
6020 if (!markStepBreakpoint()) {
6021 return false;
6023 if (!emitTree(update, ValueUsage::IgnoreValue)) {
6024 // [stack] VAL
6025 return false;
6029 if (!cfor.emitEnd(forNode->pn_pos.begin)) {
6030 // [stack]
6031 return false;
6034 return true;
6037 bool BytecodeEmitter::emitFor(ForNode* forNode,
6038 const EmitterScope* headLexicalEmitterScope) {
6039 if (forNode->head()->isKind(ParseNodeKind::ForHead)) {
6040 return emitCStyleFor(forNode, headLexicalEmitterScope);
6043 if (!updateLineNumberNotes(forNode->pn_pos.begin)) {
6044 return false;
6047 if (forNode->head()->isKind(ParseNodeKind::ForIn)) {
6048 return emitForIn(forNode, headLexicalEmitterScope);
6051 MOZ_ASSERT(forNode->head()->isKind(ParseNodeKind::ForOf));
6052 return emitForOf(forNode, headLexicalEmitterScope);
6055 MOZ_NEVER_INLINE bool BytecodeEmitter::emitFunction(
6056 FunctionNode* funNode, bool needsProto /* = false */) {
6057 FunctionBox* funbox = funNode->funbox();
6059 // [stack]
6061 FunctionEmitter fe(this, funbox, funNode->syntaxKind(),
6062 funNode->functionIsHoisted()
6063 ? FunctionEmitter::IsHoisted::Yes
6064 : FunctionEmitter::IsHoisted::No);
6066 // |wasEmittedByEnclosingScript| flag is set to true once the function has
6067 // been emitted. Function definitions that need hoisting to the top of the
6068 // function will be seen by emitFunction in two places.
6069 if (funbox->wasEmittedByEnclosingScript()) {
6070 if (!fe.emitAgain()) {
6071 // [stack]
6072 return false;
6074 MOZ_ASSERT(funNode->functionIsHoisted());
6075 } else if (funbox->isInterpreted()) {
6076 if (!funbox->emitBytecode) {
6077 return fe.emitLazy();
6078 // [stack] FUN?
6081 if (!fe.prepareForNonLazy()) {
6082 // [stack]
6083 return false;
6086 BytecodeEmitter bce2(this, funbox);
6087 if (!bce2.init(funNode->pn_pos)) {
6088 return false;
6091 /* We measured the max scope depth when we parsed the function. */
6092 if (!bce2.emitFunctionScript(funNode)) {
6093 return false;
6096 if (!fe.emitNonLazyEnd()) {
6097 // [stack] FUN?
6098 return false;
6100 } else {
6101 if (!fe.emitAsmJSModule()) {
6102 // [stack]
6103 return false;
6107 // Track the last emitted top-level self-hosted function, so that intrinsics
6108 // can adjust attributes at parse time.
6110 // NOTE: We also disallow lambda functions in the top-level body. This is done
6111 // to simplify handling of the self-hosted stencil. Within normal function
6112 // declarations there are no such restrictions.
6113 if (emitterMode == EmitterMode::SelfHosting) {
6114 if (sc->isTopLevelContext()) {
6115 MOZ_ASSERT(!funbox->isLambda());
6116 MOZ_ASSERT(funbox->explicitName());
6117 prevSelfHostedTopLevelFunction = funbox;
6121 return true;
6124 bool BytecodeEmitter::emitDo(BinaryNode* doNode) {
6125 ParseNode* bodyNode = doNode->left();
6127 DoWhileEmitter doWhile(this);
6128 if (!doWhile.emitBody(doNode->pn_pos.begin, getOffsetForLoop(bodyNode))) {
6129 return false;
6132 if (!emitTree(bodyNode)) {
6133 return false;
6136 if (!doWhile.emitCond()) {
6137 return false;
6140 ParseNode* condNode = doNode->right();
6141 if (!updateSourceCoordNotes(condNode->pn_pos.begin)) {
6142 return false;
6144 if (!markStepBreakpoint()) {
6145 return false;
6147 if (!emitTree(condNode)) {
6148 return false;
6151 if (!doWhile.emitEnd()) {
6152 return false;
6155 return true;
6158 bool BytecodeEmitter::emitWhile(BinaryNode* whileNode) {
6159 ParseNode* bodyNode = whileNode->right();
6161 WhileEmitter wh(this);
6163 ParseNode* condNode = whileNode->left();
6164 if (!wh.emitCond(whileNode->pn_pos.begin, getOffsetForLoop(condNode),
6165 whileNode->pn_pos.end)) {
6166 return false;
6169 if (!updateSourceCoordNotes(condNode->pn_pos.begin)) {
6170 return false;
6172 if (!markStepBreakpoint()) {
6173 return false;
6175 if (!emitTree(condNode)) {
6176 return false;
6179 if (!wh.emitBody()) {
6180 return false;
6182 if (!emitTree(bodyNode)) {
6183 return false;
6186 if (!wh.emitEnd()) {
6187 return false;
6190 return true;
6193 bool BytecodeEmitter::emitBreak(TaggedParserAtomIndex label) {
6194 BreakableControl* target;
6195 if (label) {
6196 // Any statement with the matching label may be the break target.
6197 auto hasSameLabel = [label](LabelControl* labelControl) {
6198 return labelControl->label() == label;
6200 target = findInnermostNestableControl<LabelControl>(hasSameLabel);
6201 } else {
6202 auto isNotLabel = [](BreakableControl* control) {
6203 return !control->is<LabelControl>();
6205 target = findInnermostNestableControl<BreakableControl>(isNotLabel);
6208 return emitGoto(target, GotoKind::Break);
6211 bool BytecodeEmitter::emitContinue(TaggedParserAtomIndex label) {
6212 LoopControl* target = nullptr;
6213 if (label) {
6214 // Find the loop statement enclosed by the matching label.
6215 NestableControl* control = innermostNestableControl;
6216 while (!control->is<LabelControl>() ||
6217 control->as<LabelControl>().label() != label) {
6218 if (control->is<LoopControl>()) {
6219 target = &control->as<LoopControl>();
6221 control = control->enclosing();
6223 } else {
6224 target = findInnermostNestableControl<LoopControl>();
6226 return emitGoto(target, GotoKind::Continue);
6229 bool BytecodeEmitter::emitGetFunctionThis(NameNode* thisName) {
6230 MOZ_ASSERT(sc->hasFunctionThisBinding());
6231 MOZ_ASSERT(thisName->isName(TaggedParserAtomIndex::WellKnown::dot_this_()));
6233 if (!updateLineNumberNotes(thisName->pn_pos.begin)) {
6234 return false;
6237 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
6238 // [stack] THIS
6239 return false;
6241 if (sc->needsThisTDZChecks()) {
6242 if (!emit1(JSOp::CheckThis)) {
6243 // [stack] THIS
6244 return false;
6248 return true;
6251 bool BytecodeEmitter::emitGetThisForSuperBase(UnaryNode* superBase) {
6252 MOZ_ASSERT(superBase->isKind(ParseNodeKind::SuperBase));
6253 NameNode* nameNode = &superBase->kid()->as<NameNode>();
6254 return emitGetFunctionThis(nameNode);
6255 // [stack] THIS
6258 bool BytecodeEmitter::emitThisLiteral(ThisLiteral* pn) {
6259 if (ParseNode* kid = pn->kid()) {
6260 NameNode* thisName = &kid->as<NameNode>();
6261 return emitGetFunctionThis(thisName);
6262 // [stack] THIS
6265 if (sc->thisBinding() == ThisBinding::Module) {
6266 return emit1(JSOp::Undefined);
6267 // [stack] UNDEF
6270 MOZ_ASSERT(sc->thisBinding() == ThisBinding::Global);
6272 MOZ_ASSERT(outermostScope().hasNonSyntacticScopeOnChain() ==
6273 sc->hasNonSyntacticScope());
6274 if (sc->hasNonSyntacticScope()) {
6275 return emit1(JSOp::NonSyntacticGlobalThis);
6276 // [stack] THIS
6279 return emit1(JSOp::GlobalThis);
6280 // [stack] THIS
6283 bool BytecodeEmitter::emitCheckDerivedClassConstructorReturn() {
6284 MOZ_ASSERT(
6285 lookupName(TaggedParserAtomIndex::WellKnown::dot_this_()).hasKnownSlot());
6286 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
6287 return false;
6289 if (!emit1(JSOp::CheckReturn)) {
6290 return false;
6292 if (!emit1(JSOp::SetRval)) {
6293 return false;
6295 return true;
6298 bool BytecodeEmitter::emitNewTarget() {
6299 MOZ_ASSERT(sc->allowNewTarget());
6301 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_newTarget_())) {
6302 // [stack] NEW.TARGET
6303 return false;
6305 return true;
6308 bool BytecodeEmitter::emitNewTarget(NewTargetNode* pn) {
6309 MOZ_ASSERT(pn->newTargetName()->isName(
6310 TaggedParserAtomIndex::WellKnown::dot_newTarget_()));
6312 return emitNewTarget();
6315 bool BytecodeEmitter::emitNewTarget(CallNode* pn) {
6316 MOZ_ASSERT(pn->callOp() == JSOp::SuperCall ||
6317 pn->callOp() == JSOp::SpreadSuperCall);
6319 // The parser is responsible for marking the "new.target" binding as being
6320 // implicitly used in super() calls.
6321 return emitNewTarget();
6324 bool BytecodeEmitter::emitReturn(UnaryNode* returnNode) {
6325 if (!updateSourceCoordNotes(returnNode->pn_pos.begin)) {
6326 return false;
6329 if (!markStepBreakpoint()) {
6330 return false;
6333 /* Push a return value */
6334 if (ParseNode* expr = returnNode->kid()) {
6335 if (!emitTree(expr)) {
6336 return false;
6339 if (sc->asSuspendableContext()->isAsync() &&
6340 sc->asSuspendableContext()->isGenerator()) {
6341 if (!emitAwaitInInnermostScope()) {
6342 return false;
6345 } else {
6346 /* No explicit return value provided */
6347 if (!emit1(JSOp::Undefined)) {
6348 return false;
6352 // We know functionBodyEndPos is set because "return" is only
6353 // valid in a function, and so we've passed through
6354 // emitFunctionScript.
6355 if (!updateSourceCoordNotes(*functionBodyEndPos)) {
6356 return false;
6360 * The return value is currently on the stack. We would like to
6361 * generate JSOp::Return, but if we have work to do before returning,
6362 * we will instead generate JSOp::SetRval / JSOp::RetRval.
6364 * We don't know whether we will need fixup code until after calling
6365 * prepareForNonLocalJumpToOutermost, so we start by generating
6366 * JSOp::SetRval, then mutate it to JSOp::Return in finishReturn if it
6367 * wasn't needed.
6369 BytecodeOffset setRvalOffset = bytecodeSection().offset();
6370 if (!emit1(JSOp::SetRval)) {
6371 return false;
6374 NonLocalExitControl nle(this, NonLocalExitKind::Return);
6375 return nle.emitReturn(setRvalOffset);
6378 bool BytecodeEmitter::finishReturn(BytecodeOffset setRvalOffset) {
6379 // The return value is currently in rval. Depending on the current function,
6380 // we may have to do additional work before returning:
6381 // - Derived class constructors must check if the return value is an object.
6382 // - Generators and async functions must do a final yield.
6383 // - Non-async generators must return the value as an iterator result:
6384 // { value: <rval>, done: true }
6385 // - Non-generator async functions must resolve the function's result promise
6386 // with the value.
6388 // If we have not generated any code since the SetRval that stored the return
6389 // value, we can also optimize the bytecode by rewriting that SetRval as a
6390 // JSOp::Return. See |emitReturn| above.
6392 bool isDerivedClassConstructor =
6393 sc->isFunctionBox() && sc->asFunctionBox()->isDerivedClassConstructor();
6394 bool needsFinalYield =
6395 sc->isFunctionBox() && sc->asFunctionBox()->needsFinalYield();
6396 bool isSimpleReturn =
6397 setRvalOffset.valid() &&
6398 setRvalOffset + BytecodeOffsetDiff(JSOpLength_SetRval) ==
6399 bytecodeSection().offset();
6401 if (isDerivedClassConstructor) {
6402 MOZ_ASSERT(!needsFinalYield);
6403 if (!emitJump(JSOp::Goto, &endOfDerivedClassConstructorBody)) {
6404 return false;
6406 return true;
6409 if (needsFinalYield) {
6410 if (!emitJump(JSOp::Goto, &finalYields)) {
6411 return false;
6413 return true;
6416 if (isSimpleReturn) {
6417 MOZ_ASSERT(JSOp(bytecodeSection().code()[setRvalOffset.value()]) ==
6418 JSOp::SetRval);
6419 bytecodeSection().code()[setRvalOffset.value()] = jsbytecode(JSOp::Return);
6420 return true;
6423 // Nothing special needs to be done.
6424 return emitReturnRval();
6427 bool BytecodeEmitter::emitGetDotGeneratorInScope(EmitterScope& currentScope) {
6428 if (!sc->isFunction() && sc->isModuleContext() &&
6429 sc->asModuleContext()->isAsync()) {
6430 NameLocation loc = *locationOfNameBoundInScopeType<ModuleScope>(
6431 TaggedParserAtomIndex::WellKnown::dot_generator_(), &currentScope);
6432 return emitGetNameAtLocation(
6433 TaggedParserAtomIndex::WellKnown::dot_generator_(), loc);
6435 NameLocation loc = *locationOfNameBoundInScopeType<FunctionScope>(
6436 TaggedParserAtomIndex::WellKnown::dot_generator_(), &currentScope);
6437 return emitGetNameAtLocation(
6438 TaggedParserAtomIndex::WellKnown::dot_generator_(), loc);
6441 bool BytecodeEmitter::emitInitialYield(UnaryNode* yieldNode) {
6442 if (!emitTree(yieldNode->kid())) {
6443 return false;
6446 if (!emitYieldOp(JSOp::InitialYield)) {
6447 // [stack] RVAL GENERATOR RESUMEKIND
6448 return false;
6450 if (!emit1(JSOp::CheckResumeKind)) {
6451 // [stack] RVAL
6452 return false;
6454 if (!emit1(JSOp::Pop)) {
6455 // [stack]
6456 return false;
6459 return true;
6462 bool BytecodeEmitter::emitYield(UnaryNode* yieldNode) {
6463 MOZ_ASSERT(sc->isFunctionBox());
6464 MOZ_ASSERT(sc->asFunctionBox()->isGenerator());
6465 MOZ_ASSERT(yieldNode->isKind(ParseNodeKind::YieldExpr));
6467 bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
6468 if (needsIteratorResult) {
6469 if (!emitPrepareIteratorResult()) {
6470 // [stack] ITEROBJ
6471 return false;
6474 if (ParseNode* expr = yieldNode->kid()) {
6475 if (!emitTree(expr)) {
6476 // [stack] ITEROBJ? VAL
6477 return false;
6479 } else {
6480 if (!emit1(JSOp::Undefined)) {
6481 // [stack] ITEROBJ? UNDEFINED
6482 return false;
6486 if (sc->asSuspendableContext()->isAsync()) {
6487 MOZ_ASSERT(!needsIteratorResult);
6488 if (!emitAwaitInInnermostScope()) {
6489 // [stack] RESULT
6490 return false;
6494 if (needsIteratorResult) {
6495 if (!emitFinishIteratorResult(false)) {
6496 // [stack] ITEROBJ
6497 return false;
6501 if (!emitGetDotGeneratorInInnermostScope()) {
6502 // [stack] # if needsIteratorResult
6503 // [stack] ITEROBJ .GENERATOR
6504 // [stack] # else
6505 // [stack] RESULT .GENERATOR
6506 return false;
6509 if (!emitYieldOp(JSOp::Yield)) {
6510 // [stack] YIELDRESULT GENERATOR RESUMEKIND
6511 return false;
6514 if (!emit1(JSOp::CheckResumeKind)) {
6515 // [stack] YIELDRESULT
6516 return false;
6519 return true;
6522 bool BytecodeEmitter::emitAwaitInInnermostScope(UnaryNode* awaitNode) {
6523 MOZ_ASSERT(sc->isSuspendableContext());
6524 MOZ_ASSERT(awaitNode->isKind(ParseNodeKind::AwaitExpr));
6526 if (!emitTree(awaitNode->kid())) {
6527 return false;
6529 return emitAwaitInInnermostScope();
6532 bool BytecodeEmitter::emitAwaitInScope(EmitterScope& currentScope) {
6533 if (!emit1(JSOp::CanSkipAwait)) {
6534 // [stack] VALUE CANSKIP
6535 return false;
6538 if (!emit1(JSOp::MaybeExtractAwaitValue)) {
6539 // [stack] VALUE_OR_RESOLVED CANSKIP
6540 return false;
6543 InternalIfEmitter ifCanSkip(this);
6544 if (!ifCanSkip.emitThen(IfEmitter::ConditionKind::Negative)) {
6545 // [stack] VALUE_OR_RESOLVED
6546 return false;
6549 if (sc->asSuspendableContext()->needsPromiseResult()) {
6550 if (!emitGetDotGeneratorInScope(currentScope)) {
6551 // [stack] VALUE GENERATOR
6552 return false;
6554 if (!emit1(JSOp::AsyncAwait)) {
6555 // [stack] PROMISE
6556 return false;
6560 if (!emitGetDotGeneratorInScope(currentScope)) {
6561 // [stack] VALUE|PROMISE GENERATOR
6562 return false;
6564 if (!emitYieldOp(JSOp::Await)) {
6565 // [stack] RESOLVED GENERATOR RESUMEKIND
6566 return false;
6568 if (!emit1(JSOp::CheckResumeKind)) {
6569 // [stack] RESOLVED
6570 return false;
6573 if (!ifCanSkip.emitEnd()) {
6574 return false;
6577 MOZ_ASSERT(ifCanSkip.popped() == 0);
6579 return true;
6582 // ES2019 draft rev 49b781ec80117b60f73327ef3054703a3111e40c
6583 // 14.4.14 Runtime Semantics: Evaluation
6584 // YieldExpression : yield* AssignmentExpression
6585 bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
6586 MOZ_ASSERT(getSelfHostedIterFor(iter) == SelfHostedIter::Deny,
6587 "yield* is prohibited in self-hosted code because it can run "
6588 "user-modifiable iteration code");
6590 MOZ_ASSERT(sc->isSuspendableContext());
6591 MOZ_ASSERT(sc->asSuspendableContext()->isGenerator());
6593 // Step 1.
6594 IteratorKind iterKind = sc->asSuspendableContext()->isAsync()
6595 ? IteratorKind::Async
6596 : IteratorKind::Sync;
6597 bool needsIteratorResult = sc->asSuspendableContext()->needsIteratorResult();
6599 // Steps 2-5.
6600 if (!emitTree(iter)) {
6601 // [stack] ITERABLE
6602 return false;
6604 if (iterKind == IteratorKind::Async) {
6605 if (!emitAsyncIterator(SelfHostedIter::Deny)) {
6606 // [stack] NEXT ITER
6607 return false;
6609 } else {
6610 if (!emitIterator(SelfHostedIter::Deny)) {
6611 // [stack] NEXT ITER
6612 return false;
6616 // Step 6.
6617 // Start with NormalCompletion(undefined).
6618 if (!emit1(JSOp::Undefined)) {
6619 // [stack] NEXT ITER RECEIVED
6620 return false;
6622 if (!emitPushResumeKind(GeneratorResumeKind::Next)) {
6623 // [stack] NEXT ITER RECEIVED RESUMEKIND
6624 return false;
6627 const int32_t startDepth = bytecodeSection().stackDepth();
6628 MOZ_ASSERT(startDepth >= 4);
6630 // Step 7 is a loop.
6631 LoopControl loopInfo(this, StatementKind::YieldStar);
6632 if (!loopInfo.emitLoopHead(this, Nothing())) {
6633 // [stack] NEXT ITER RECEIVED RESUMEKIND
6634 return false;
6637 // Step 7.a. Check for Normal completion.
6638 if (!emit1(JSOp::Dup)) {
6639 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND
6640 return false;
6642 if (!emitPushResumeKind(GeneratorResumeKind::Next)) {
6643 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND NORMAL
6644 return false;
6646 if (!emit1(JSOp::StrictEq)) {
6647 // [stack] NEXT ITER RECEIVED RESUMEKIND IS_NORMAL
6648 return false;
6651 InternalIfEmitter ifKind(this);
6652 if (!ifKind.emitThenElse()) {
6653 // [stack] NEXT ITER RECEIVED RESUMEKIND
6654 return false;
6657 if (!emit1(JSOp::Pop)) {
6658 // [stack] NEXT ITER RECEIVED
6659 return false;
6662 // Step 7.a.i.
6663 // result = iter.next(received)
6664 if (!emit2(JSOp::Unpick, 2)) {
6665 // [stack] RECEIVED NEXT ITER
6666 return false;
6668 if (!emit1(JSOp::Dup2)) {
6669 // [stack] RECEIVED NEXT ITER NEXT ITER
6670 return false;
6672 if (!emit2(JSOp::Pick, 4)) {
6673 // [stack] NEXT ITER NEXT ITER RECEIVED
6674 return false;
6676 if (!emitCall(JSOp::Call, 1, iter)) {
6677 // [stack] NEXT ITER RESULT
6678 return false;
6681 // Step 7.a.ii.
6682 if (iterKind == IteratorKind::Async) {
6683 if (!emitAwaitInInnermostScope()) {
6684 // [stack] NEXT ITER RESULT
6685 return false;
6689 // Step 7.a.iii.
6690 if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) {
6691 // [stack] NEXT ITER RESULT
6692 return false;
6695 // Bytecode for steps 7.a.iv-vii is emitted after the ifKind if-else because
6696 // it's shared with other branches.
6699 // Step 7.b. Check for Throw completion.
6700 if (!ifKind.emitElseIf(Nothing())) {
6701 // [stack] NEXT ITER RECEIVED RESUMEKIND
6702 return false;
6704 if (!emit1(JSOp::Dup)) {
6705 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND
6706 return false;
6708 if (!emitPushResumeKind(GeneratorResumeKind::Throw)) {
6709 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND THROW
6710 return false;
6712 if (!emit1(JSOp::StrictEq)) {
6713 // [stack] NEXT ITER RECEIVED RESUMEKIND IS_THROW
6714 return false;
6716 if (!ifKind.emitThenElse()) {
6717 // [stack] NEXT ITER RECEIVED RESUMEKIND
6718 return false;
6721 if (!emit1(JSOp::Pop)) {
6722 // [stack] NEXT ITER RECEIVED
6723 return false;
6725 // Step 7.b.i.
6726 if (!emitDupAt(1)) {
6727 // [stack] NEXT ITER RECEIVED ITER
6728 return false;
6730 if (!emit1(JSOp::Dup)) {
6731 // [stack] NEXT ITER RECEIVED ITER ITER
6732 return false;
6734 if (!emitAtomOp(JSOp::GetProp,
6735 TaggedParserAtomIndex::WellKnown::throw_())) {
6736 // [stack] NEXT ITER RECEIVED ITER THROW
6737 return false;
6740 // Step 7.b.ii.
6741 InternalIfEmitter ifThrowMethodIsNotDefined(this);
6742 if (!emit1(JSOp::IsNullOrUndefined)) {
6743 // [stack] NEXT ITER RECEIVED ITER THROW NULL-OR-UNDEF
6744 return false;
6747 if (!ifThrowMethodIsNotDefined.emitThenElse(
6748 IfEmitter::ConditionKind::Negative)) {
6749 // [stack] NEXT ITER RECEIVED ITER THROW
6750 return false;
6753 // Step 7.b.ii.1.
6754 // RESULT = ITER.throw(EXCEPTION)
6755 if (!emit1(JSOp::Swap)) {
6756 // [stack] NEXT ITER RECEIVED THROW ITER
6757 return false;
6759 if (!emit2(JSOp::Pick, 2)) {
6760 // [stack] NEXT ITER THROW ITER RECEIVED
6761 return false;
6763 if (!emitCall(JSOp::Call, 1, iter)) {
6764 // [stack] NEXT ITER RESULT
6765 return false;
6768 // Step 7.b.ii.2.
6769 if (iterKind == IteratorKind::Async) {
6770 if (!emitAwaitInInnermostScope()) {
6771 // [stack] NEXT ITER RESULT
6772 return false;
6776 // Step 7.b.ii.4.
6777 if (!emitCheckIsObj(CheckIsObjectKind::IteratorThrow)) {
6778 // [stack] NEXT ITER RESULT
6779 return false;
6782 // Bytecode for steps 7.b.ii.5-8 is emitted after the ifKind if-else because
6783 // it's shared with other branches.
6785 // Step 7.b.iii.
6786 if (!ifThrowMethodIsNotDefined.emitElse()) {
6787 // [stack] NEXT ITER RECEIVED ITER THROW
6788 return false;
6790 if (!emit1(JSOp::Pop)) {
6791 // [stack] NEXT ITER RECEIVED ITER
6792 return false;
6795 // Steps 7.b.iii.1-4.
6797 // If the iterator does not have a "throw" method, it calls IteratorClose
6798 // and then throws a TypeError.
6799 if (!emitIteratorCloseInInnermostScope(iterKind, CompletionKind::Normal)) {
6800 // [stack] NEXT ITER RECEIVED ITER
6801 return false;
6803 // Steps 7.b.iii.5-6.
6804 if (!emit2(JSOp::ThrowMsg, uint8_t(ThrowMsgKind::IteratorNoThrow))) {
6805 // [stack] NEXT ITER RECEIVED ITER
6806 // [stack] # throw
6807 return false;
6810 if (!ifThrowMethodIsNotDefined.emitEnd()) {
6811 return false;
6815 // Step 7.c. It must be a Return completion.
6816 if (!ifKind.emitElse()) {
6817 // [stack] NEXT ITER RECEIVED RESUMEKIND
6818 return false;
6821 if (!emit1(JSOp::Pop)) {
6822 // [stack] NEXT ITER RECEIVED
6823 return false;
6826 // Step 7.c.i.
6828 // Call iterator.return() for receiving a "forced return" completion from
6829 // the generator.
6831 // Step 7.c.ii.
6833 // Get the "return" method.
6834 if (!emitDupAt(1)) {
6835 // [stack] NEXT ITER RECEIVED ITER
6836 return false;
6838 if (!emit1(JSOp::Dup)) {
6839 // [stack] NEXT ITER RECEIVED ITER ITER
6840 return false;
6842 if (!emitAtomOp(JSOp::GetProp,
6843 TaggedParserAtomIndex::WellKnown::return_())) {
6844 // [stack] NEXT ITER RECEIVED ITER RET
6845 return false;
6848 // Step 7.c.iii.
6850 // Do nothing if "return" is undefined or null.
6851 InternalIfEmitter ifReturnMethodIsDefined(this);
6852 if (!emit1(JSOp::IsNullOrUndefined)) {
6853 // [stack] NEXT ITER RECEIVED ITER RET NULL-OR-UNDEF
6854 return false;
6857 // Step 7.c.iv.
6859 // Call "return" with the argument passed to Generator.prototype.return.
6860 if (!ifReturnMethodIsDefined.emitThenElse(
6861 IfEmitter::ConditionKind::Negative)) {
6862 // [stack] NEXT ITER RECEIVED ITER RET
6863 return false;
6865 if (!emit1(JSOp::Swap)) {
6866 // [stack] NEXT ITER RECEIVED RET ITER
6867 return false;
6869 if (!emit2(JSOp::Pick, 2)) {
6870 // [stack] NEXT ITER RET ITER RECEIVED
6871 return false;
6873 if (needsIteratorResult) {
6874 if (!emitAtomOp(JSOp::GetProp,
6875 TaggedParserAtomIndex::WellKnown::value())) {
6876 // [stack] NEXT ITER RET ITER VAL
6877 return false;
6880 if (!emitCall(JSOp::Call, 1)) {
6881 // [stack] NEXT ITER RESULT
6882 return false;
6885 // Step 7.c.v.
6886 if (iterKind == IteratorKind::Async) {
6887 if (!emitAwaitInInnermostScope()) {
6888 // [stack] NEXT ITER RESULT
6889 return false;
6893 // Step 7.c.vi.
6894 if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) {
6895 // [stack] NEXT ITER RESULT
6896 return false;
6899 // Check if the returned object from iterator.return() is done. If not,
6900 // continue yielding.
6902 // Steps 7.c.vii-viii.
6903 InternalIfEmitter ifReturnDone(this);
6904 if (!emit1(JSOp::Dup)) {
6905 // [stack] NEXT ITER RESULT RESULT
6906 return false;
6908 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::done())) {
6909 // [stack] NEXT ITER RESULT DONE
6910 return false;
6912 if (!ifReturnDone.emitThenElse()) {
6913 // [stack] NEXT ITER RESULT
6914 return false;
6917 // Step 7.c.viii.1.
6918 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::value())) {
6919 // [stack] NEXT ITER VALUE
6920 return false;
6922 if (needsIteratorResult) {
6923 if (!emitPrepareIteratorResult()) {
6924 // [stack] NEXT ITER VALUE RESULT
6925 return false;
6927 if (!emit1(JSOp::Swap)) {
6928 // [stack] NEXT ITER RESULT VALUE
6929 return false;
6931 if (!emitFinishIteratorResult(true)) {
6932 // [stack] NEXT ITER RESULT
6933 return false;
6937 if (!ifReturnDone.emitElse()) {
6938 // [stack] NEXT ITER RESULT
6939 return false;
6942 // Jump to continue label for steps 7.c.ix-x.
6943 if (!emitJump(JSOp::Goto, &loopInfo.continues)) {
6944 // [stack] NEXT ITER RESULT
6945 return false;
6948 if (!ifReturnDone.emitEnd()) {
6949 // [stack] NEXT ITER RESULT
6950 return false;
6953 // Step 7.c.iii.
6954 if (!ifReturnMethodIsDefined.emitElse()) {
6955 // [stack] NEXT ITER RECEIVED ITER RET
6956 return false;
6958 if (!emitPopN(2)) {
6959 // [stack] NEXT ITER RECEIVED
6960 return false;
6962 if (iterKind == IteratorKind::Async) {
6963 // Step 7.c.iii.1.
6964 if (!emitAwaitInInnermostScope()) {
6965 // [stack] NEXT ITER RECEIVED
6966 return false;
6969 if (!ifReturnMethodIsDefined.emitEnd()) {
6970 // [stack] NEXT ITER RECEIVED
6971 return false;
6974 // Perform a "forced generator return".
6976 // Step 7.c.iii.2.
6977 // Step 7.c.viii.2.
6978 if (!emitGetDotGeneratorInInnermostScope()) {
6979 // [stack] NEXT ITER RESULT GENOBJ
6980 return false;
6982 if (!emitPushResumeKind(GeneratorResumeKind::Return)) {
6983 // [stack] NEXT ITER RESULT GENOBJ RESUMEKIND
6984 return false;
6986 if (!emit1(JSOp::CheckResumeKind)) {
6987 // [stack] NEXT ITER RESULT GENOBJ RESUMEKIND
6988 return false;
6992 if (!ifKind.emitEnd()) {
6993 // [stack] NEXT ITER RESULT
6994 return false;
6997 // Shared tail for Normal/Throw completions.
6999 // Steps 7.a.iv-v.
7000 // Steps 7.b.ii.5-6.
7002 // [stack] NEXT ITER RESULT
7004 // if (result.done) break;
7005 if (!emit1(JSOp::Dup)) {
7006 // [stack] NEXT ITER RESULT RESULT
7007 return false;
7009 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::done())) {
7010 // [stack] NEXT ITER RESULT DONE
7011 return false;
7013 if (!emitJump(JSOp::JumpIfTrue, &loopInfo.breaks)) {
7014 // [stack] NEXT ITER RESULT
7015 return false;
7018 // Steps 7.a.vi-vii.
7019 // Steps 7.b.ii.7-8.
7020 // Steps 7.c.ix-x.
7021 if (!loopInfo.emitContinueTarget(this)) {
7022 // [stack] NEXT ITER RESULT
7023 return false;
7025 if (iterKind == IteratorKind::Async) {
7026 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::value())) {
7027 // [stack] NEXT ITER RESULT
7028 return false;
7031 if (!emitGetDotGeneratorInInnermostScope()) {
7032 // [stack] NEXT ITER RESULT GENOBJ
7033 return false;
7035 if (!emitYieldOp(JSOp::Yield)) {
7036 // [stack] NEXT ITER RVAL GENOBJ RESUMEKIND
7037 return false;
7039 if (!emit1(JSOp::Swap)) {
7040 // [stack] NEXT ITER RVAL RESUMEKIND GENOBJ
7041 return false;
7043 if (!emit1(JSOp::Pop)) {
7044 // [stack] NEXT ITER RVAL RESUMEKIND
7045 return false;
7047 if (!loopInfo.emitLoopEnd(this, JSOp::Goto, TryNoteKind::Loop)) {
7048 // [stack] NEXT ITER RVAL RESUMEKIND
7049 return false;
7052 // Jumps to this point have 3 (instead of 4) values on the stack.
7053 MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth);
7054 bytecodeSection().setStackDepth(startDepth - 1);
7056 // [stack] NEXT ITER RESULT
7058 // Step 7.a.v.1.
7059 // Step 7.b.ii.6.a.
7061 // result.value
7062 if (!emit2(JSOp::Unpick, 2)) {
7063 // [stack] RESULT NEXT ITER
7064 return false;
7066 if (!emitPopN(2)) {
7067 // [stack] RESULT
7068 return false;
7070 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::value())) {
7071 // [stack] VALUE
7072 return false;
7075 MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth - 3);
7077 return true;
7080 bool BytecodeEmitter::emitStatementList(ListNode* stmtList) {
7081 for (ParseNode* stmt : stmtList->contents()) {
7082 if (!emitTree(stmt)) {
7083 return false;
7086 return true;
7089 bool BytecodeEmitter::emitExpressionStatement(UnaryNode* exprStmt) {
7090 MOZ_ASSERT(exprStmt->isKind(ParseNodeKind::ExpressionStmt));
7093 * Top-level or called-from-a-native JS_Execute/EvaluateScript,
7094 * debugger, and eval frames may need the value of the ultimate
7095 * expression statement as the script's result, despite the fact
7096 * that it appears useless to the compiler.
7098 * API users may also set the ReadOnlyCompileOptions::noScriptRval option when
7099 * calling JS_Compile* to suppress JSOp::SetRval.
7101 bool wantval = false;
7102 bool useful = false;
7103 if (sc->isTopLevelContext()) {
7104 useful = wantval = !sc->noScriptRval();
7107 /* Don't eliminate expressions with side effects. */
7108 ParseNode* expr = exprStmt->kid();
7109 if (!useful) {
7110 if (!checkSideEffects(expr, &useful)) {
7111 return false;
7115 * Don't eliminate apparently useless expressions if they are labeled
7116 * expression statements. The startOffset() test catches the case
7117 * where we are nesting in emitTree for a labeled compound statement.
7119 if (innermostNestableControl &&
7120 innermostNestableControl->is<LabelControl>() &&
7121 innermostNestableControl->as<LabelControl>().startOffset() >=
7122 bytecodeSection().offset()) {
7123 useful = true;
7127 if (useful) {
7128 ValueUsage valueUsage =
7129 wantval ? ValueUsage::WantValue : ValueUsage::IgnoreValue;
7130 ExpressionStatementEmitter ese(this, valueUsage);
7131 if (!ese.prepareForExpr(exprStmt->pn_pos.begin)) {
7132 return false;
7134 if (!markStepBreakpoint()) {
7135 return false;
7137 if (!emitTree(expr, valueUsage)) {
7138 return false;
7140 if (!ese.emitEnd()) {
7141 return false;
7145 return true;
7148 bool BytecodeEmitter::emitDeleteName(UnaryNode* deleteNode) {
7149 MOZ_ASSERT(deleteNode->isKind(ParseNodeKind::DeleteNameExpr));
7151 NameNode* nameExpr = &deleteNode->kid()->as<NameNode>();
7152 MOZ_ASSERT(nameExpr->isKind(ParseNodeKind::Name));
7154 return emitAtomOp(JSOp::DelName, nameExpr->atom());
7157 bool BytecodeEmitter::emitDeleteProperty(UnaryNode* deleteNode) {
7158 MOZ_ASSERT(deleteNode->isKind(ParseNodeKind::DeletePropExpr));
7160 PropertyAccess* propExpr = &deleteNode->kid()->as<PropertyAccess>();
7161 PropOpEmitter poe(this, PropOpEmitter::Kind::Delete,
7162 propExpr->as<PropertyAccess>().isSuper()
7163 ? PropOpEmitter::ObjKind::Super
7164 : PropOpEmitter::ObjKind::Other);
7165 if (propExpr->isSuper()) {
7166 // The expression |delete super.foo;| has to evaluate |super.foo|,
7167 // which could throw if |this| hasn't yet been set by a |super(...)|
7168 // call or the super-base is not an object, before throwing a
7169 // ReferenceError for attempting to delete a super-reference.
7170 UnaryNode* base = &propExpr->expression().as<UnaryNode>();
7171 if (!emitGetThisForSuperBase(base)) {
7172 // [stack] THIS
7173 return false;
7175 } else {
7176 if (!poe.prepareForObj()) {
7177 return false;
7179 if (!emitPropLHS(propExpr)) {
7180 // [stack] OBJ
7181 return false;
7185 if (!poe.emitDelete(propExpr->key().atom())) {
7186 // [stack] # if Super
7187 // [stack] THIS
7188 // [stack] # otherwise
7189 // [stack] SUCCEEDED
7190 return false;
7193 return true;
7196 bool BytecodeEmitter::emitDeleteElement(UnaryNode* deleteNode) {
7197 MOZ_ASSERT(deleteNode->isKind(ParseNodeKind::DeleteElemExpr));
7199 PropertyByValue* elemExpr = &deleteNode->kid()->as<PropertyByValue>();
7200 bool isSuper = elemExpr->isSuper();
7201 DebugOnly<bool> isPrivate =
7202 elemExpr->key().isKind(ParseNodeKind::PrivateName);
7203 MOZ_ASSERT(!isPrivate);
7204 ElemOpEmitter eoe(
7205 this, ElemOpEmitter::Kind::Delete,
7206 isSuper ? ElemOpEmitter::ObjKind::Super : ElemOpEmitter::ObjKind::Other);
7207 if (isSuper) {
7208 // The expression |delete super[foo];| has to evaluate |super[foo]|,
7209 // which could throw if |this| hasn't yet been set by a |super(...)|
7210 // call, or trigger side-effects when evaluating ToPropertyKey(foo),
7211 // or also throw when the super-base is not an object, before throwing
7212 // a ReferenceError for attempting to delete a super-reference.
7213 if (!eoe.prepareForObj()) {
7214 // [stack]
7215 return false;
7218 UnaryNode* base = &elemExpr->expression().as<UnaryNode>();
7219 if (!emitGetThisForSuperBase(base)) {
7220 // [stack] THIS
7221 return false;
7223 if (!eoe.prepareForKey()) {
7224 // [stack] THIS
7225 return false;
7227 if (!emitTree(&elemExpr->key())) {
7228 // [stack] THIS KEY
7229 return false;
7231 } else {
7232 if (!emitElemObjAndKey(elemExpr, false, eoe)) {
7233 // [stack] OBJ KEY
7234 return false;
7237 if (!eoe.emitDelete()) {
7238 // [stack] # if Super
7239 // [stack] THIS
7240 // [stack] # otherwise
7241 // [stack] SUCCEEDED
7242 return false;
7245 return true;
7248 bool BytecodeEmitter::emitDeleteExpression(UnaryNode* deleteNode) {
7249 MOZ_ASSERT(deleteNode->isKind(ParseNodeKind::DeleteExpr));
7251 ParseNode* expression = deleteNode->kid();
7253 // If useless, just emit JSOp::True; otherwise convert |delete <expr>| to
7254 // effectively |<expr>, true|.
7255 bool useful = false;
7256 if (!checkSideEffects(expression, &useful)) {
7257 return false;
7260 if (useful) {
7261 if (!emitTree(expression)) {
7262 return false;
7264 if (!emit1(JSOp::Pop)) {
7265 return false;
7269 return emit1(JSOp::True);
7272 bool BytecodeEmitter::emitDeleteOptionalChain(UnaryNode* deleteNode) {
7273 MOZ_ASSERT(deleteNode->isKind(ParseNodeKind::DeleteOptionalChainExpr));
7275 OptionalEmitter oe(this, bytecodeSection().stackDepth());
7277 ParseNode* kid = deleteNode->kid();
7278 switch (kid->getKind()) {
7279 case ParseNodeKind::ElemExpr:
7280 case ParseNodeKind::OptionalElemExpr: {
7281 auto* elemExpr = &kid->as<PropertyByValueBase>();
7282 if (!emitDeleteElementInOptChain(elemExpr, oe)) {
7283 // [stack] # If shortcircuit
7284 // [stack] UNDEFINED-OR-NULL
7285 // [stack] # otherwise
7286 // [stack] SUCCEEDED
7287 return false;
7290 break;
7292 case ParseNodeKind::DotExpr:
7293 case ParseNodeKind::OptionalDotExpr: {
7294 auto* propExpr = &kid->as<PropertyAccessBase>();
7295 if (!emitDeletePropertyInOptChain(propExpr, oe)) {
7296 // [stack] # If shortcircuit
7297 // [stack] UNDEFINED-OR-NULL
7298 // [stack] # otherwise
7299 // [stack] SUCCEEDED
7300 return false;
7302 break;
7304 default:
7305 MOZ_ASSERT_UNREACHABLE("Unrecognized optional delete ParseNodeKind");
7308 if (!oe.emitOptionalJumpTarget(JSOp::True)) {
7309 // [stack] # If shortcircuit
7310 // [stack] TRUE
7311 // [stack] # otherwise
7312 // [stack] SUCCEEDED
7313 return false;
7316 return true;
7319 bool BytecodeEmitter::emitDeletePropertyInOptChain(PropertyAccessBase* propExpr,
7320 OptionalEmitter& oe) {
7321 MOZ_ASSERT_IF(propExpr->is<PropertyAccess>(),
7322 !propExpr->as<PropertyAccess>().isSuper());
7323 PropOpEmitter poe(this, PropOpEmitter::Kind::Delete,
7324 PropOpEmitter::ObjKind::Other);
7326 if (!poe.prepareForObj()) {
7327 // [stack]
7328 return false;
7330 if (!emitOptionalTree(&propExpr->expression(), oe)) {
7331 // [stack] OBJ
7332 return false;
7334 if (propExpr->isKind(ParseNodeKind::OptionalDotExpr)) {
7335 if (!oe.emitJumpShortCircuit()) {
7336 // [stack] # if Jump
7337 // [stack] UNDEFINED-OR-NULL
7338 // [stack] # otherwise
7339 // [stack] OBJ
7340 return false;
7344 if (!poe.emitDelete(propExpr->key().atom())) {
7345 // [stack] SUCCEEDED
7346 return false;
7349 return true;
7352 bool BytecodeEmitter::emitDeleteElementInOptChain(PropertyByValueBase* elemExpr,
7353 OptionalEmitter& oe) {
7354 MOZ_ASSERT_IF(elemExpr->is<PropertyByValue>(),
7355 !elemExpr->as<PropertyByValue>().isSuper());
7356 ElemOpEmitter eoe(this, ElemOpEmitter::Kind::Delete,
7357 ElemOpEmitter::ObjKind::Other);
7359 if (!eoe.prepareForObj()) {
7360 // [stack]
7361 return false;
7364 if (!emitOptionalTree(&elemExpr->expression(), oe)) {
7365 // [stack] OBJ
7366 return false;
7369 if (elemExpr->isKind(ParseNodeKind::OptionalElemExpr)) {
7370 if (!oe.emitJumpShortCircuit()) {
7371 // [stack] # if Jump
7372 // [stack] UNDEFINED-OR-NULL
7373 // [stack] # otherwise
7374 // [stack] OBJ
7375 return false;
7379 if (!eoe.prepareForKey()) {
7380 // [stack] OBJ
7381 return false;
7384 if (!emitTree(&elemExpr->key())) {
7385 // [stack] OBJ KEY
7386 return false;
7389 if (!eoe.emitDelete()) {
7390 // [stack] SUCCEEDED
7391 return false;
7394 return true;
7397 bool BytecodeEmitter::emitDebugCheckSelfHosted() {
7398 // [stack] CALLEE
7400 #ifdef DEBUG
7401 if (!emit1(JSOp::DebugCheckSelfHosted)) {
7402 // [stack] CALLEE
7403 return false;
7405 #endif
7407 return true;
7410 bool BytecodeEmitter::emitSelfHostedCallFunction(CallNode* callNode, JSOp op) {
7411 // Special-casing of callFunction to emit bytecode that directly
7412 // invokes the callee with the correct |this| object and arguments.
7413 // callFunction(fun, thisArg, arg0, arg1) thus becomes:
7414 // - emit lookup for fun
7415 // - emit lookup for thisArg
7416 // - emit lookups for arg0, arg1
7418 // argc is set to the amount of actually emitted args and the
7419 // emitting of args below is disabled by setting emitArgs to false.
7420 NameNode* calleeNode = &callNode->callee()->as<NameNode>();
7421 ListNode* argsList = callNode->args();
7423 MOZ_ASSERT(argsList->count() >= 2);
7425 MOZ_ASSERT(callNode->callOp() == JSOp::Call);
7427 bool constructing =
7428 calleeNode->name() ==
7429 TaggedParserAtomIndex::WellKnown::constructContentFunction();
7430 ParseNode* funNode = argsList->head();
7432 if (!emitTree(funNode)) {
7433 // [stack] CALLEE
7434 return false;
7437 #ifdef DEBUG
7438 MOZ_ASSERT(op == JSOp::Call || op == JSOp::CallContent ||
7439 op == JSOp::NewContent);
7440 if (op == JSOp::Call) {
7441 if (!emitDebugCheckSelfHosted()) {
7442 // [stack] CALLEE
7443 return false;
7446 #endif
7448 ParseNode* thisOrNewTarget = funNode->pn_next;
7449 if (constructing) {
7450 // Save off the new.target value, but here emit a proper |this| for a
7451 // constructing call.
7452 if (!emit1(JSOp::IsConstructing)) {
7453 // [stack] CALLEE IS_CONSTRUCTING
7454 return false;
7456 } else {
7457 // It's |this|, emit it.
7458 if (!emitTree(thisOrNewTarget)) {
7459 // [stack] CALLEE THIS
7460 return false;
7464 for (ParseNode* argpn : argsList->contentsFrom(thisOrNewTarget->pn_next)) {
7465 if (!emitTree(argpn)) {
7466 // [stack] CALLEE ... ARGS...
7467 return false;
7471 if (constructing) {
7472 if (!emitTree(thisOrNewTarget)) {
7473 // [stack] CALLEE IS_CONSTRUCTING ARGS... NEW.TARGET
7474 return false;
7478 uint32_t argc = argsList->count() - 2;
7479 if (!emitCall(op, argc)) {
7480 // [stack] RVAL
7481 return false;
7484 return true;
7487 bool BytecodeEmitter::emitSelfHostedResumeGenerator(CallNode* callNode) {
7488 ListNode* argsList = callNode->args();
7490 // Syntax: resumeGenerator(gen, value, 'next'|'throw'|'return')
7491 MOZ_ASSERT(argsList->count() == 3);
7493 ParseNode* genNode = argsList->head();
7494 if (!emitTree(genNode)) {
7495 // [stack] GENERATOR
7496 return false;
7499 ParseNode* valNode = genNode->pn_next;
7500 if (!emitTree(valNode)) {
7501 // [stack] GENERATOR VALUE
7502 return false;
7505 ParseNode* kindNode = valNode->pn_next;
7506 MOZ_ASSERT(kindNode->isKind(ParseNodeKind::StringExpr));
7507 GeneratorResumeKind kind =
7508 ParserAtomToResumeKind(kindNode->as<NameNode>().atom());
7509 MOZ_ASSERT(!kindNode->pn_next);
7511 if (!emitPushResumeKind(kind)) {
7512 // [stack] GENERATOR VALUE RESUMEKIND
7513 return false;
7516 if (!emit1(JSOp::Resume)) {
7517 // [stack] RVAL
7518 return false;
7521 return true;
7524 bool BytecodeEmitter::emitSelfHostedForceInterpreter() {
7525 // JSScript::hasForceInterpreterOp() relies on JSOp::ForceInterpreter being
7526 // the first bytecode op in the script.
7527 MOZ_ASSERT(bytecodeSection().code().empty());
7529 if (!emit1(JSOp::ForceInterpreter)) {
7530 return false;
7532 if (!emit1(JSOp::Undefined)) {
7533 return false;
7536 return true;
7539 bool BytecodeEmitter::emitSelfHostedAllowContentIter(CallNode* callNode) {
7540 ListNode* argsList = callNode->args();
7542 MOZ_ASSERT(argsList->count() == 1);
7544 // We're just here as a sentinel. Pass the value through directly.
7545 return emitTree(argsList->head());
7548 bool BytecodeEmitter::emitSelfHostedAllowContentIterWith(CallNode* callNode) {
7549 ListNode* argsList = callNode->args();
7551 MOZ_ASSERT(argsList->count() == 2 || argsList->count() == 3);
7553 // We're just here as a sentinel. Pass the value through directly.
7554 return emitTree(argsList->head());
7557 bool BytecodeEmitter::emitSelfHostedAllowContentIterWithNext(
7558 CallNode* callNode) {
7559 ListNode* argsList = callNode->args();
7561 MOZ_ASSERT(argsList->count() == 2);
7563 // We're just here as a sentinel. Pass the value through directly.
7564 return emitTree(argsList->head());
7567 bool BytecodeEmitter::emitSelfHostedDefineDataProperty(CallNode* callNode) {
7568 ListNode* argsList = callNode->args();
7570 // Only optimize when 3 arguments are passed.
7571 MOZ_ASSERT(argsList->count() == 3);
7573 ParseNode* objNode = argsList->head();
7574 if (!emitTree(objNode)) {
7575 return false;
7578 ParseNode* idNode = objNode->pn_next;
7579 if (!emitTree(idNode)) {
7580 return false;
7583 ParseNode* valNode = idNode->pn_next;
7584 if (!emitTree(valNode)) {
7585 return false;
7588 // This will leave the object on the stack instead of pushing |undefined|,
7589 // but that's fine because the self-hosted code doesn't use the return
7590 // value.
7591 return emit1(JSOp::InitElem);
7594 bool BytecodeEmitter::emitSelfHostedHasOwn(CallNode* callNode) {
7595 ListNode* argsList = callNode->args();
7597 MOZ_ASSERT(argsList->count() == 2);
7599 ParseNode* idNode = argsList->head();
7600 if (!emitTree(idNode)) {
7601 return false;
7604 ParseNode* objNode = idNode->pn_next;
7605 if (!emitTree(objNode)) {
7606 return false;
7609 return emit1(JSOp::HasOwn);
7612 bool BytecodeEmitter::emitSelfHostedGetPropertySuper(CallNode* callNode) {
7613 ListNode* argsList = callNode->args();
7615 MOZ_ASSERT(argsList->count() == 3);
7617 ParseNode* objNode = argsList->head();
7618 ParseNode* idNode = objNode->pn_next;
7619 ParseNode* receiverNode = idNode->pn_next;
7621 if (!emitTree(receiverNode)) {
7622 return false;
7625 if (!emitTree(idNode)) {
7626 return false;
7629 if (!emitTree(objNode)) {
7630 return false;
7633 return emitElemOpBase(JSOp::GetElemSuper);
7636 bool BytecodeEmitter::emitSelfHostedToNumeric(CallNode* callNode) {
7637 ListNode* argsList = callNode->args();
7639 MOZ_ASSERT(argsList->count() == 1);
7641 ParseNode* argNode = argsList->head();
7643 if (!emitTree(argNode)) {
7644 return false;
7647 return emit1(JSOp::ToNumeric);
7650 bool BytecodeEmitter::emitSelfHostedToString(CallNode* callNode) {
7651 ListNode* argsList = callNode->args();
7653 MOZ_ASSERT(argsList->count() == 1);
7655 ParseNode* argNode = argsList->head();
7657 if (!emitTree(argNode)) {
7658 return false;
7661 return emit1(JSOp::ToString);
7664 bool BytecodeEmitter::emitSelfHostedIsNullOrUndefined(CallNode* callNode) {
7665 ListNode* argsList = callNode->args();
7667 MOZ_ASSERT(argsList->count() == 1);
7669 ParseNode* argNode = argsList->head();
7671 if (!emitTree(argNode)) {
7672 // [stack] ARG
7673 return false;
7675 if (!emit1(JSOp::IsNullOrUndefined)) {
7676 // [stack] ARG IS_NULL_OR_UNDEF
7677 return false;
7679 if (!emit1(JSOp::Swap)) {
7680 // [stack] IS_NULL_OR_UNDEF ARG
7681 return false;
7683 if (!emit1(JSOp::Pop)) {
7684 // [stack] IS_NULL_OR_UNDEF
7685 return false;
7687 return true;
7690 bool BytecodeEmitter::emitSelfHostedIteratorClose(CallNode* callNode) {
7691 ListNode* argsList = callNode->args();
7692 MOZ_ASSERT(argsList->count() == 1);
7694 ParseNode* argNode = argsList->head();
7695 if (!emitTree(argNode)) {
7696 // [stack] ARG
7697 return false;
7700 if (!emit2(JSOp::CloseIter, uint8_t(CompletionKind::Normal))) {
7701 // [stack]
7702 return false;
7705 // This is still a call node, so we must generate a stack value.
7706 if (!emit1(JSOp::Undefined)) {
7707 // [stack] RVAL
7708 return false;
7711 return true;
7714 bool BytecodeEmitter::emitSelfHostedGetBuiltinConstructorOrPrototype(
7715 CallNode* callNode, bool isConstructor) {
7716 ListNode* argsList = callNode->args();
7718 MOZ_ASSERT(argsList->count() == 1);
7720 ParseNode* argNode = argsList->head();
7722 if (!argNode->isKind(ParseNodeKind::StringExpr)) {
7723 reportError(callNode, JSMSG_UNEXPECTED_TYPE, "built-in name",
7724 "not a string constant");
7725 return false;
7728 auto name = argNode->as<NameNode>().atom();
7730 BuiltinObjectKind kind;
7731 if (isConstructor) {
7732 kind = BuiltinConstructorForName(name);
7733 } else {
7734 kind = BuiltinPrototypeForName(name);
7737 if (kind == BuiltinObjectKind::None) {
7738 reportError(callNode, JSMSG_UNEXPECTED_TYPE, "built-in name",
7739 "not a valid built-in");
7740 return false;
7743 return emitBuiltinObject(kind);
7746 bool BytecodeEmitter::emitSelfHostedGetBuiltinConstructor(CallNode* callNode) {
7747 return emitSelfHostedGetBuiltinConstructorOrPrototype(
7748 callNode, /* isConstructor = */ true);
7751 bool BytecodeEmitter::emitSelfHostedGetBuiltinPrototype(CallNode* callNode) {
7752 return emitSelfHostedGetBuiltinConstructorOrPrototype(
7753 callNode, /* isConstructor = */ false);
7756 JS::SymbolCode ParserAtomToSymbolCode(TaggedParserAtomIndex atom) {
7757 // NOTE: This is a linear search, but the set of entries is quite small and
7758 // this is only used for initial self-hosted parse.
7759 #define MATCH_WELL_KNOWN_SYMBOL(NAME) \
7760 if (atom == TaggedParserAtomIndex::WellKnown::NAME()) { \
7761 return JS::SymbolCode::NAME; \
7763 JS_FOR_EACH_WELL_KNOWN_SYMBOL(MATCH_WELL_KNOWN_SYMBOL)
7764 #undef MATCH_WELL_KNOWN_SYMBOL
7766 return JS::SymbolCode::Limit;
7769 bool BytecodeEmitter::emitSelfHostedGetBuiltinSymbol(CallNode* callNode) {
7770 ListNode* argsList = callNode->args();
7772 MOZ_ASSERT(argsList->count() == 1);
7774 ParseNode* argNode = argsList->head();
7776 if (!argNode->isKind(ParseNodeKind::StringExpr)) {
7777 reportError(callNode, JSMSG_UNEXPECTED_TYPE, "built-in name",
7778 "not a string constant");
7779 return false;
7782 auto name = argNode->as<NameNode>().atom();
7784 JS::SymbolCode code = ParserAtomToSymbolCode(name);
7785 if (code == JS::SymbolCode::Limit) {
7786 reportError(callNode, JSMSG_UNEXPECTED_TYPE, "built-in name",
7787 "not a valid built-in");
7788 return false;
7791 return emit2(JSOp::Symbol, uint8_t(code));
7794 bool BytecodeEmitter::emitSelfHostedArgumentsLength(CallNode* callNode) {
7795 MOZ_ASSERT(!sc->asFunctionBox()->needsArgsObj());
7796 sc->asFunctionBox()->setUsesArgumentsIntrinsics();
7798 MOZ_ASSERT(callNode->args()->count() == 0);
7800 return emit1(JSOp::ArgumentsLength);
7803 bool BytecodeEmitter::emitSelfHostedGetArgument(CallNode* callNode) {
7804 MOZ_ASSERT(!sc->asFunctionBox()->needsArgsObj());
7805 sc->asFunctionBox()->setUsesArgumentsIntrinsics();
7807 ListNode* argsList = callNode->args();
7808 MOZ_ASSERT(argsList->count() == 1);
7810 ParseNode* argNode = argsList->head();
7811 if (!emitTree(argNode)) {
7812 return false;
7815 return emit1(JSOp::GetActualArg);
7818 #ifdef DEBUG
7819 void BytecodeEmitter::assertSelfHostedExpectedTopLevel(ParseNode* node) {
7820 // The function argument is expected to be a simple binding/function name.
7821 // Eg. `function foo() { }; SpecialIntrinsic(foo)`
7822 MOZ_ASSERT(node->isKind(ParseNodeKind::Name),
7823 "argument must be a function name");
7824 TaggedParserAtomIndex targetName = node->as<NameNode>().name();
7826 // The special intrinsics must follow the target functions definition. A
7827 // simple assert is fine here since any hoisted function will cause a non-null
7828 // value to be set here.
7829 MOZ_ASSERT(prevSelfHostedTopLevelFunction);
7831 // The target function must match the most recently defined top-level
7832 // self-hosted function.
7833 MOZ_ASSERT(prevSelfHostedTopLevelFunction->explicitName() == targetName,
7834 "selfhost decorator must immediately follow target function");
7836 #endif
7838 bool BytecodeEmitter::emitSelfHostedSetIsInlinableLargeFunction(
7839 CallNode* callNode) {
7840 #ifdef DEBUG
7841 ListNode* argsList = callNode->args();
7843 MOZ_ASSERT(argsList->count() == 1);
7845 assertSelfHostedExpectedTopLevel(argsList->head());
7846 #endif
7848 MOZ_ASSERT(prevSelfHostedTopLevelFunction->isInitialCompilation);
7849 prevSelfHostedTopLevelFunction->setIsInlinableLargeFunction();
7851 // This is still a call node, so we must generate a stack value.
7852 return emit1(JSOp::Undefined);
7855 bool BytecodeEmitter::emitSelfHostedSetCanonicalName(CallNode* callNode) {
7856 ListNode* argsList = callNode->args();
7858 MOZ_ASSERT(argsList->count() == 2);
7860 #ifdef DEBUG
7861 assertSelfHostedExpectedTopLevel(argsList->head());
7862 #endif
7864 ParseNode* nameNode = argsList->last();
7865 MOZ_ASSERT(nameNode->isKind(ParseNodeKind::StringExpr));
7866 TaggedParserAtomIndex specName = nameNode->as<NameNode>().atom();
7867 // Canonical name must be atomized.
7868 compilationState.parserAtoms.markUsedByStencil(specName,
7869 ParserAtom::Atomize::Yes);
7871 // Store the canonical name for instantiation.
7872 prevSelfHostedTopLevelFunction->functionStencil().setSelfHostedCanonicalName(
7873 specName);
7875 return emit1(JSOp::Undefined);
7878 #ifdef DEBUG
7879 void BytecodeEmitter::assertSelfHostedUnsafeGetReservedSlot(
7880 ListNode* argsList) {
7881 MOZ_ASSERT(argsList->count() == 2);
7883 ParseNode* objNode = argsList->head();
7884 ParseNode* slotNode = objNode->pn_next;
7886 // Ensure that the slot argument is fixed, this is required by the JITs.
7887 MOZ_ASSERT(slotNode->isKind(ParseNodeKind::NumberExpr),
7888 "slot argument must be a constant");
7891 void BytecodeEmitter::assertSelfHostedUnsafeSetReservedSlot(
7892 ListNode* argsList) {
7893 MOZ_ASSERT(argsList->count() == 3);
7895 ParseNode* objNode = argsList->head();
7896 ParseNode* slotNode = objNode->pn_next;
7898 // Ensure that the slot argument is fixed, this is required by the JITs.
7899 MOZ_ASSERT(slotNode->isKind(ParseNodeKind::NumberExpr),
7900 "slot argument must be a constant");
7902 #endif
7904 /* A version of emitCalleeAndThis for the optional cases:
7905 * * a?.()
7906 * * a?.b()
7907 * * a?.["b"]()
7908 * * (a?.b)()
7909 * * a?.#b()
7911 * See emitCallOrNew and emitOptionalCall for more context.
7913 bool BytecodeEmitter::emitOptionalCalleeAndThis(ParseNode* callee,
7914 CallNode* call,
7915 CallOrNewEmitter& cone,
7916 OptionalEmitter& oe) {
7917 AutoCheckRecursionLimit recursion(fc);
7918 if (!recursion.check(fc)) {
7919 return false;
7922 switch (ParseNodeKind kind = callee->getKind()) {
7923 case ParseNodeKind::Name: {
7924 auto name = callee->as<NameNode>().name();
7925 if (!cone.emitNameCallee(name)) {
7926 // [stack] CALLEE THIS
7927 return false;
7929 break;
7932 case ParseNodeKind::OptionalDotExpr: {
7933 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
7934 OptionalPropertyAccess* prop = &callee->as<OptionalPropertyAccess>();
7935 bool isSuper = false;
7937 PropOpEmitter& poe = cone.prepareForPropCallee(isSuper);
7938 if (!emitOptionalDotExpression(prop, poe, isSuper, oe)) {
7939 // [stack] CALLEE THIS
7940 return false;
7942 break;
7944 case ParseNodeKind::DotExpr: {
7945 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
7946 PropertyAccess* prop = &callee->as<PropertyAccess>();
7947 bool isSuper = prop->isSuper();
7949 PropOpEmitter& poe = cone.prepareForPropCallee(isSuper);
7950 if (!emitOptionalDotExpression(prop, poe, isSuper, oe)) {
7951 // [stack] CALLEE THIS
7952 return false;
7954 break;
7957 case ParseNodeKind::OptionalElemExpr: {
7958 OptionalPropertyByValue* elem = &callee->as<OptionalPropertyByValue>();
7959 bool isSuper = false;
7960 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
7961 ElemOpEmitter& eoe = cone.prepareForElemCallee(isSuper);
7962 if (!emitOptionalElemExpression(elem, eoe, isSuper, oe)) {
7963 // [stack] CALLEE THIS
7964 return false;
7966 break;
7968 case ParseNodeKind::ElemExpr: {
7969 PropertyByValue* elem = &callee->as<PropertyByValue>();
7970 bool isSuper = elem->isSuper();
7971 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
7972 ElemOpEmitter& eoe = cone.prepareForElemCallee(isSuper);
7973 if (!emitOptionalElemExpression(elem, eoe, isSuper, oe)) {
7974 // [stack] CALLEE THIS
7975 return false;
7977 break;
7980 case ParseNodeKind::PrivateMemberExpr:
7981 case ParseNodeKind::OptionalPrivateMemberExpr: {
7982 PrivateMemberAccessBase* privateExpr =
7983 &callee->as<PrivateMemberAccessBase>();
7984 PrivateOpEmitter& xoe =
7985 cone.prepareForPrivateCallee(privateExpr->privateName().name());
7986 if (!emitOptionalPrivateExpression(privateExpr, xoe, oe)) {
7987 // [stack] CALLEE THIS
7988 return false;
7990 break;
7993 case ParseNodeKind::Function:
7994 if (!cone.prepareForFunctionCallee()) {
7995 return false;
7997 if (!emitOptionalTree(callee, oe)) {
7998 // [stack] CALLEE
7999 return false;
8001 break;
8003 case ParseNodeKind::OptionalChain: {
8004 return emitCalleeAndThisForOptionalChain(&callee->as<UnaryNode>(), call,
8005 cone);
8008 default:
8009 MOZ_RELEASE_ASSERT(kind != ParseNodeKind::SuperBase);
8011 if (!cone.prepareForOtherCallee()) {
8012 return false;
8014 if (!emitOptionalTree(callee, oe)) {
8015 // [stack] CALLEE
8016 return false;
8018 break;
8021 if (!cone.emitThis()) {
8022 // [stack] CALLEE THIS
8023 return false;
8026 return true;
8029 bool BytecodeEmitter::emitCalleeAndThis(ParseNode* callee, CallNode* maybeCall,
8030 CallOrNewEmitter& cone) {
8031 MOZ_ASSERT_IF(maybeCall, maybeCall->callee() == callee);
8033 switch (callee->getKind()) {
8034 case ParseNodeKind::Name: {
8035 auto name = callee->as<NameNode>().name();
8036 if (!cone.emitNameCallee(name)) {
8037 // [stack] CALLEE THIS?
8038 return false;
8040 break;
8042 case ParseNodeKind::DotExpr: {
8043 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
8044 PropertyAccess* prop = &callee->as<PropertyAccess>();
8045 bool isSuper = prop->isSuper();
8047 PropOpEmitter& poe = cone.prepareForPropCallee(isSuper);
8048 if (!poe.prepareForObj()) {
8049 return false;
8051 if (isSuper) {
8052 UnaryNode* base = &prop->expression().as<UnaryNode>();
8053 if (!emitGetThisForSuperBase(base)) {
8054 // [stack] THIS
8055 return false;
8057 } else {
8058 if (!emitPropLHS(prop)) {
8059 // [stack] OBJ
8060 return false;
8063 if (!poe.emitGet(prop->key().atom())) {
8064 // [stack] CALLEE THIS?
8065 return false;
8068 break;
8070 case ParseNodeKind::ElemExpr: {
8071 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
8072 PropertyByValue* elem = &callee->as<PropertyByValue>();
8073 bool isSuper = elem->isSuper();
8074 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
8075 ElemOpEmitter& eoe = cone.prepareForElemCallee(isSuper);
8076 if (!emitElemObjAndKey(elem, isSuper, eoe)) {
8077 // [stack] # if Super
8078 // [stack] THIS? THIS KEY
8079 // [stack] # otherwise
8080 // [stack] OBJ? OBJ KEY
8081 return false;
8083 if (!eoe.emitGet()) {
8084 // [stack] CALLEE THIS?
8085 return false;
8088 break;
8090 case ParseNodeKind::PrivateMemberExpr: {
8091 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
8092 PrivateMemberAccessBase* privateExpr =
8093 &callee->as<PrivateMemberAccessBase>();
8094 PrivateOpEmitter& xoe =
8095 cone.prepareForPrivateCallee(privateExpr->privateName().name());
8096 if (!emitTree(&privateExpr->expression())) {
8097 // [stack] OBJ
8098 return false;
8100 if (!xoe.emitReference()) {
8101 // [stack] OBJ NAME
8102 return false;
8104 if (!xoe.emitGetForCallOrNew()) {
8105 // [stack] CALLEE THIS
8106 return false;
8109 break;
8111 case ParseNodeKind::Function:
8112 if (!cone.prepareForFunctionCallee()) {
8113 return false;
8115 if (!emitTree(callee)) {
8116 // [stack] CALLEE
8117 return false;
8119 break;
8120 case ParseNodeKind::SuperBase:
8121 MOZ_ASSERT(maybeCall);
8122 MOZ_ASSERT(maybeCall->isKind(ParseNodeKind::SuperCallExpr));
8123 MOZ_ASSERT(callee->isKind(ParseNodeKind::SuperBase));
8124 if (!cone.emitSuperCallee()) {
8125 // [stack] CALLEE IsConstructing
8126 return false;
8128 break;
8129 case ParseNodeKind::OptionalChain: {
8130 MOZ_ASSERT(maybeCall);
8131 return emitCalleeAndThisForOptionalChain(&callee->as<UnaryNode>(),
8132 maybeCall, cone);
8134 default:
8135 if (!cone.prepareForOtherCallee()) {
8136 return false;
8138 if (!emitTree(callee)) {
8139 return false;
8141 break;
8144 if (!cone.emitThis()) {
8145 // [stack] CALLEE THIS
8146 return false;
8149 return true;
8152 ParseNode* BytecodeEmitter::getCoordNode(ParseNode* callNode,
8153 ParseNode* calleeNode, JSOp op,
8154 ListNode* argsList) {
8155 ParseNode* coordNode = callNode;
8156 if (op == JSOp::Call || op == JSOp::SpreadCall) {
8157 // Default to using the location of the `(` itself.
8158 // obj[expr]() // expression
8159 // ^ // column coord
8160 coordNode = argsList;
8162 switch (calleeNode->getKind()) {
8163 case ParseNodeKind::DotExpr:
8164 // Use the position of a property access identifier.
8166 // obj().aprop() // expression
8167 // ^ // column coord
8169 // Note: Because of the constant folding logic in FoldElement,
8170 // this case also applies for constant string properties.
8172 // obj()['aprop']() // expression
8173 // ^ // column coord
8174 coordNode = &calleeNode->as<PropertyAccess>().key();
8175 break;
8176 case ParseNodeKind::Name: {
8177 // Use the start of callee name unless it is at a separator
8178 // or has no args.
8180 // 2 + obj() // expression
8181 // ^ // column coord
8183 if (argsList->empty() ||
8184 !bytecodeSection().atSeparator(calleeNode->pn_pos.begin)) {
8185 // Use the start of callee names.
8186 coordNode = calleeNode;
8188 break;
8191 default:
8192 break;
8195 return coordNode;
8198 bool BytecodeEmitter::emitArguments(ListNode* argsList, bool isCall,
8199 bool isSpread, CallOrNewEmitter& cone) {
8200 uint32_t argc = argsList->count();
8201 if (argc >= ARGC_LIMIT) {
8202 reportError(argsList,
8203 isCall ? JSMSG_TOO_MANY_FUN_ARGS : JSMSG_TOO_MANY_CON_ARGS);
8204 return false;
8206 if (!isSpread) {
8207 if (!cone.prepareForNonSpreadArguments()) {
8208 // [stack] CALLEE THIS
8209 return false;
8211 for (ParseNode* arg : argsList->contents()) {
8212 if (!updateSourceCoordNotesIfNonLiteral(arg)) {
8213 return false;
8215 if (!emitTree(arg)) {
8216 // [stack] CALLEE THIS ARG*
8217 return false;
8220 } else if (cone.wantSpreadOperand()) {
8221 auto* spreadNode = &argsList->head()->as<UnaryNode>();
8222 if (!updateSourceCoordNotesIfNonLiteral(spreadNode->kid())) {
8223 return false;
8225 if (!emitTree(spreadNode->kid())) {
8226 // [stack] CALLEE THIS ARG0
8227 return false;
8230 if (!cone.emitSpreadArgumentsTest()) {
8231 // [stack] CALLEE THIS ARG0
8232 return false;
8235 if (cone.wantSpreadIteration()) {
8236 if (!emitSpreadIntoArray(spreadNode)) {
8237 // [stack] CALLEE THIS ARR
8238 return false;
8242 if (!cone.emitSpreadArgumentsTestEnd()) {
8243 // [stack] CALLEE THIS ARR
8244 return false;
8246 } else {
8247 if (!cone.prepareForSpreadArguments()) {
8248 // [stack] CALLEE THIS
8249 return false;
8251 if (!emitArray(argsList)) {
8252 // [stack] CALLEE THIS ARR
8253 return false;
8257 return true;
8260 bool BytecodeEmitter::emitOptionalCall(CallNode* callNode, OptionalEmitter& oe,
8261 ValueUsage valueUsage) {
8263 * A modified version of emitCallOrNew that handles optional calls.
8265 * These include the following:
8266 * a?.()
8267 * a.b?.()
8268 * a.["b"]?.()
8269 * (a?.b)?.()
8271 * See CallOrNewEmitter for more context.
8273 ParseNode* calleeNode = callNode->callee();
8274 ListNode* argsList = callNode->args();
8275 bool isSpread = IsSpreadOp(callNode->callOp());
8276 JSOp op = callNode->callOp();
8277 uint32_t argc = argsList->count();
8278 bool isOptimizableSpread = isSpread && argc == 1;
8280 CallOrNewEmitter cone(this, op,
8281 isOptimizableSpread
8282 ? CallOrNewEmitter::ArgumentsKind::SingleSpread
8283 : CallOrNewEmitter::ArgumentsKind::Other,
8284 valueUsage);
8286 ParseNode* coordNode = getCoordNode(callNode, calleeNode, op, argsList);
8288 if (!emitOptionalCalleeAndThis(calleeNode, callNode, cone, oe)) {
8289 // [stack] CALLEE THIS
8290 return false;
8293 if (callNode->isKind(ParseNodeKind::OptionalCallExpr)) {
8294 if (!oe.emitJumpShortCircuitForCall()) {
8295 // [stack] CALLEE THIS
8296 return false;
8300 if (!emitArguments(argsList, /* isCall = */ true, isSpread, cone)) {
8301 // [stack] CALLEE THIS ARGS...
8302 return false;
8305 if (!cone.emitEnd(argc, coordNode->pn_pos.begin)) {
8306 // [stack] RVAL
8307 return false;
8310 return true;
8313 bool BytecodeEmitter::emitCallOrNew(CallNode* callNode, ValueUsage valueUsage) {
8315 * Emit callable invocation or operator new (constructor call) code.
8316 * First, emit code for the left operand to evaluate the callable or
8317 * constructable object expression.
8319 * Then (or in a call case that has no explicit reference-base
8320 * object) we emit JSOp::Undefined to produce the undefined |this|
8321 * value required for calls (which non-strict mode functions
8322 * will box into the global object).
8324 bool isCall = callNode->isKind(ParseNodeKind::CallExpr) ||
8325 callNode->isKind(ParseNodeKind::TaggedTemplateExpr);
8326 ParseNode* calleeNode = callNode->callee();
8327 ListNode* argsList = callNode->args();
8328 JSOp op = callNode->callOp();
8330 if (calleeNode->isKind(ParseNodeKind::Name) &&
8331 emitterMode == BytecodeEmitter::SelfHosting && op == JSOp::Call) {
8332 // Calls to "forceInterpreter", "callFunction",
8333 // "callContentFunction", or "resumeGenerator" in self-hosted
8334 // code generate inline bytecode.
8336 // NOTE: The list of special instruction names has to be kept in sync with
8337 // "js/src/builtin/.eslintrc.js".
8338 auto calleeName = calleeNode->as<NameNode>().name();
8339 if (calleeName == TaggedParserAtomIndex::WellKnown::callFunction()) {
8340 return emitSelfHostedCallFunction(callNode, JSOp::Call);
8342 if (calleeName == TaggedParserAtomIndex::WellKnown::callContentFunction()) {
8343 return emitSelfHostedCallFunction(callNode, JSOp::CallContent);
8345 if (calleeName ==
8346 TaggedParserAtomIndex::WellKnown::constructContentFunction()) {
8347 return emitSelfHostedCallFunction(callNode, JSOp::NewContent);
8349 if (calleeName == TaggedParserAtomIndex::WellKnown::resumeGenerator()) {
8350 return emitSelfHostedResumeGenerator(callNode);
8352 if (calleeName == TaggedParserAtomIndex::WellKnown::forceInterpreter()) {
8353 return emitSelfHostedForceInterpreter();
8355 if (calleeName == TaggedParserAtomIndex::WellKnown::allowContentIter()) {
8356 return emitSelfHostedAllowContentIter(callNode);
8358 if (calleeName ==
8359 TaggedParserAtomIndex::WellKnown::allowContentIterWith()) {
8360 return emitSelfHostedAllowContentIterWith(callNode);
8362 if (calleeName ==
8363 TaggedParserAtomIndex::WellKnown::allowContentIterWithNext()) {
8364 return emitSelfHostedAllowContentIterWithNext(callNode);
8366 if (calleeName == TaggedParserAtomIndex::WellKnown::DefineDataProperty() &&
8367 argsList->count() == 3) {
8368 return emitSelfHostedDefineDataProperty(callNode);
8370 if (calleeName == TaggedParserAtomIndex::WellKnown::hasOwn()) {
8371 return emitSelfHostedHasOwn(callNode);
8373 if (calleeName == TaggedParserAtomIndex::WellKnown::getPropertySuper()) {
8374 return emitSelfHostedGetPropertySuper(callNode);
8376 if (calleeName == TaggedParserAtomIndex::WellKnown::ToNumeric()) {
8377 return emitSelfHostedToNumeric(callNode);
8379 if (calleeName == TaggedParserAtomIndex::WellKnown::ToString()) {
8380 return emitSelfHostedToString(callNode);
8382 if (calleeName ==
8383 TaggedParserAtomIndex::WellKnown::GetBuiltinConstructor()) {
8384 return emitSelfHostedGetBuiltinConstructor(callNode);
8386 if (calleeName == TaggedParserAtomIndex::WellKnown::GetBuiltinPrototype()) {
8387 return emitSelfHostedGetBuiltinPrototype(callNode);
8389 if (calleeName == TaggedParserAtomIndex::WellKnown::GetBuiltinSymbol()) {
8390 return emitSelfHostedGetBuiltinSymbol(callNode);
8392 if (calleeName == TaggedParserAtomIndex::WellKnown::ArgumentsLength()) {
8393 return emitSelfHostedArgumentsLength(callNode);
8395 if (calleeName == TaggedParserAtomIndex::WellKnown::GetArgument()) {
8396 return emitSelfHostedGetArgument(callNode);
8398 if (calleeName ==
8399 TaggedParserAtomIndex::WellKnown::SetIsInlinableLargeFunction()) {
8400 return emitSelfHostedSetIsInlinableLargeFunction(callNode);
8402 if (calleeName == TaggedParserAtomIndex::WellKnown::SetCanonicalName()) {
8403 return emitSelfHostedSetCanonicalName(callNode);
8405 if (calleeName == TaggedParserAtomIndex::WellKnown::IsNullOrUndefined()) {
8406 return emitSelfHostedIsNullOrUndefined(callNode);
8408 if (calleeName == TaggedParserAtomIndex::WellKnown::IteratorClose()) {
8409 return emitSelfHostedIteratorClose(callNode);
8411 #ifdef DEBUG
8412 if (calleeName ==
8413 TaggedParserAtomIndex::WellKnown::UnsafeGetReservedSlot() ||
8414 calleeName == TaggedParserAtomIndex::WellKnown::
8415 UnsafeGetObjectFromReservedSlot() ||
8416 calleeName == TaggedParserAtomIndex::WellKnown::
8417 UnsafeGetInt32FromReservedSlot() ||
8418 calleeName == TaggedParserAtomIndex::WellKnown::
8419 UnsafeGetStringFromReservedSlot()) {
8420 // Make sure that this call is correct, but don't emit any special code.
8421 assertSelfHostedUnsafeGetReservedSlot(argsList);
8423 if (calleeName ==
8424 TaggedParserAtomIndex::WellKnown::UnsafeSetReservedSlot()) {
8425 // Make sure that this call is correct, but don't emit any special code.
8426 assertSelfHostedUnsafeSetReservedSlot(argsList);
8428 #endif
8429 // Fall through
8432 uint32_t argc = argsList->count();
8433 bool isSpread = IsSpreadOp(op);
8434 bool isOptimizableSpread = isSpread && argc == 1;
8435 bool isDefaultDerivedClassConstructor =
8436 sc->isFunctionBox() && sc->asFunctionBox()->isDerivedClassConstructor() &&
8437 sc->asFunctionBox()->isSyntheticFunction();
8438 MOZ_ASSERT_IF(isDefaultDerivedClassConstructor, isOptimizableSpread);
8439 CallOrNewEmitter cone(
8440 this, op,
8441 isOptimizableSpread
8442 ? isDefaultDerivedClassConstructor
8443 ? CallOrNewEmitter::ArgumentsKind::PassthroughRest
8444 : CallOrNewEmitter::ArgumentsKind::SingleSpread
8445 : CallOrNewEmitter::ArgumentsKind::Other,
8446 valueUsage);
8448 if (!emitCalleeAndThis(calleeNode, callNode, cone)) {
8449 // [stack] CALLEE THIS
8450 return false;
8452 if (!emitArguments(argsList, isCall, isSpread, cone)) {
8453 // [stack] CALLEE THIS ARGS...
8454 return false;
8457 // Push new.target for construct calls.
8458 if (IsConstructOp(op)) {
8459 if (op == JSOp::SuperCall || op == JSOp::SpreadSuperCall) {
8460 if (!emitNewTarget(callNode)) {
8461 // [stack] CALLEE THIS ARGS.. NEW.TARGET
8462 return false;
8464 } else {
8465 // Repush the callee as new.target
8466 uint32_t effectiveArgc = isSpread ? 1 : argc;
8467 if (!emitDupAt(effectiveArgc + 1)) {
8468 // [stack] CALLEE THIS ARGS.. CALLEE
8469 return false;
8474 ParseNode* coordNode = getCoordNode(callNode, calleeNode, op, argsList);
8476 if (!cone.emitEnd(argc, coordNode->pn_pos.begin)) {
8477 // [stack] RVAL
8478 return false;
8481 return true;
8484 // This list must be kept in the same order in several places:
8485 // - The binary operators in ParseNode.h ,
8486 // - the binary operators in TokenKind.h
8487 // - the precedence list in Parser.cpp
8488 static const JSOp ParseNodeKindToJSOp[] = {
8489 // Some binary ops require special code generation (PrivateIn);
8490 // these should not use BinaryOpParseNodeKindToJSOp. This table fills those
8491 // slots with Nops to make the rest of the table lookup work.
8492 JSOp::Coalesce, JSOp::Or, JSOp::And, JSOp::BitOr, JSOp::BitXor,
8493 JSOp::BitAnd, JSOp::StrictEq, JSOp::Eq, JSOp::StrictNe, JSOp::Ne,
8494 JSOp::Lt, JSOp::Le, JSOp::Gt, JSOp::Ge, JSOp::Instanceof,
8495 JSOp::In, JSOp::Nop, JSOp::Lsh, JSOp::Rsh, JSOp::Ursh,
8496 JSOp::Add, JSOp::Sub, JSOp::Mul, JSOp::Div, JSOp::Mod,
8497 JSOp::Pow};
8499 static inline JSOp BinaryOpParseNodeKindToJSOp(ParseNodeKind pnk) {
8500 MOZ_ASSERT(pnk >= ParseNodeKind::BinOpFirst);
8501 MOZ_ASSERT(pnk <= ParseNodeKind::BinOpLast);
8502 int parseNodeFirst = size_t(ParseNodeKind::BinOpFirst);
8503 #ifdef DEBUG
8504 int jsopArraySize = std::size(ParseNodeKindToJSOp);
8505 int parseNodeKindListSize =
8506 size_t(ParseNodeKind::BinOpLast) - parseNodeFirst + 1;
8507 MOZ_ASSERT(jsopArraySize == parseNodeKindListSize);
8508 // Ensure we don't use this to find an op for a parse node
8509 // requiring special emission rules.
8510 MOZ_ASSERT(ParseNodeKindToJSOp[size_t(pnk) - parseNodeFirst] != JSOp::Nop);
8511 #endif
8512 return ParseNodeKindToJSOp[size_t(pnk) - parseNodeFirst];
8515 bool BytecodeEmitter::emitRightAssociative(ListNode* node) {
8516 // ** is the only right-associative operator.
8517 MOZ_ASSERT(node->isKind(ParseNodeKind::PowExpr));
8519 // Right-associative operator chain.
8520 for (ParseNode* subexpr : node->contents()) {
8521 if (!updateSourceCoordNotesIfNonLiteral(subexpr)) {
8522 return false;
8524 if (!emitTree(subexpr)) {
8525 return false;
8528 for (uint32_t i = 0; i < node->count() - 1; i++) {
8529 if (!emit1(JSOp::Pow)) {
8530 return false;
8533 return true;
8536 bool BytecodeEmitter::emitLeftAssociative(ListNode* node) {
8537 // Left-associative operator chain.
8538 if (!emitTree(node->head())) {
8539 return false;
8541 JSOp op = BinaryOpParseNodeKindToJSOp(node->getKind());
8542 ParseNode* nextExpr = node->head()->pn_next;
8543 do {
8544 if (!updateSourceCoordNotesIfNonLiteral(nextExpr)) {
8545 return false;
8547 if (!emitTree(nextExpr)) {
8548 return false;
8550 if (!emit1(op)) {
8551 return false;
8553 } while ((nextExpr = nextExpr->pn_next));
8554 return true;
8557 bool BytecodeEmitter::emitPrivateInExpr(ListNode* node) {
8558 MOZ_ASSERT(node->head()->isKind(ParseNodeKind::PrivateName));
8560 NameNode& privateNameNode = node->head()->as<NameNode>();
8561 TaggedParserAtomIndex privateName = privateNameNode.name();
8563 PrivateOpEmitter xoe(this, PrivateOpEmitter::Kind::ErgonomicBrandCheck,
8564 privateName);
8566 ParseNode* valueNode = node->head()->pn_next;
8567 MOZ_ASSERT(valueNode->pn_next == nullptr);
8569 if (!emitTree(valueNode)) {
8570 // [stack] OBJ
8571 return false;
8574 if (!xoe.emitReference()) {
8575 // [stack] OBJ BRAND if private method
8576 // [stack] OBJ NAME if private field or accessor.
8577 return false;
8580 if (!xoe.emitBrandCheck()) {
8581 // [stack] OBJ BRAND BOOL if private method
8582 // [stack] OBJ NAME BOOL if private field or accessor.
8583 return false;
8586 if (!emitUnpickN(2)) {
8587 // [stack] BOOL OBJ BRAND if private method
8588 // [stack] BOOL OBJ NAME if private field or accessor.
8589 return false;
8592 if (!emitPopN(2)) {
8593 // [stack] BOOL
8594 return false;
8597 return true;
8601 * Special `emitTree` for Optional Chaining case.
8602 * Examples of this are `emitOptionalChain`, `emitDeleteOptionalChain` and
8603 * `emitCalleeAndThisForOptionalChain`.
8605 bool BytecodeEmitter::emitOptionalTree(
8606 ParseNode* pn, OptionalEmitter& oe,
8607 ValueUsage valueUsage /* = ValueUsage::WantValue */) {
8608 AutoCheckRecursionLimit recursion(fc);
8609 if (!recursion.check(fc)) {
8610 return false;
8612 ParseNodeKind kind = pn->getKind();
8613 switch (kind) {
8614 case ParseNodeKind::OptionalDotExpr: {
8615 OptionalPropertyAccess* prop = &pn->as<OptionalPropertyAccess>();
8616 bool isSuper = false;
8617 PropOpEmitter poe(this, PropOpEmitter::Kind::Get,
8618 PropOpEmitter::ObjKind::Other);
8619 if (!emitOptionalDotExpression(prop, poe, isSuper, oe)) {
8620 return false;
8622 break;
8624 case ParseNodeKind::DotExpr: {
8625 PropertyAccess* prop = &pn->as<PropertyAccess>();
8626 bool isSuper = prop->isSuper();
8627 PropOpEmitter poe(this, PropOpEmitter::Kind::Get,
8628 isSuper ? PropOpEmitter::ObjKind::Super
8629 : PropOpEmitter::ObjKind::Other);
8630 if (!emitOptionalDotExpression(prop, poe, isSuper, oe)) {
8631 return false;
8633 break;
8636 case ParseNodeKind::OptionalElemExpr: {
8637 OptionalPropertyByValue* elem = &pn->as<OptionalPropertyByValue>();
8638 bool isSuper = false;
8639 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
8640 ElemOpEmitter eoe(this, ElemOpEmitter::Kind::Get,
8641 ElemOpEmitter::ObjKind::Other);
8643 if (!emitOptionalElemExpression(elem, eoe, isSuper, oe)) {
8644 return false;
8646 break;
8648 case ParseNodeKind::ElemExpr: {
8649 PropertyByValue* elem = &pn->as<PropertyByValue>();
8650 bool isSuper = elem->isSuper();
8651 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
8652 ElemOpEmitter eoe(this, ElemOpEmitter::Kind::Get,
8653 isSuper ? ElemOpEmitter::ObjKind::Super
8654 : ElemOpEmitter::ObjKind::Other);
8656 if (!emitOptionalElemExpression(elem, eoe, isSuper, oe)) {
8657 return false;
8659 break;
8661 case ParseNodeKind::PrivateMemberExpr:
8662 case ParseNodeKind::OptionalPrivateMemberExpr: {
8663 PrivateMemberAccessBase* privateExpr = &pn->as<PrivateMemberAccessBase>();
8664 PrivateOpEmitter xoe(this, PrivateOpEmitter::Kind::Get,
8665 privateExpr->privateName().name());
8666 if (!emitOptionalPrivateExpression(privateExpr, xoe, oe)) {
8667 return false;
8669 break;
8671 case ParseNodeKind::CallExpr:
8672 case ParseNodeKind::OptionalCallExpr:
8673 if (!emitOptionalCall(&pn->as<CallNode>(), oe, valueUsage)) {
8674 return false;
8676 break;
8677 // List of accepted ParseNodeKinds that might appear only at the beginning
8678 // of an Optional Chain.
8679 // For example, a taggedTemplateExpr node might occur if we have
8680 // `test`?.b, with `test` as the taggedTemplateExpr ParseNode.
8681 default:
8682 #ifdef DEBUG
8683 // https://tc39.es/ecma262/#sec-primary-expression
8684 bool isPrimaryExpression =
8685 kind == ParseNodeKind::ThisExpr || kind == ParseNodeKind::Name ||
8686 kind == ParseNodeKind::PrivateName ||
8687 kind == ParseNodeKind::NullExpr || kind == ParseNodeKind::TrueExpr ||
8688 kind == ParseNodeKind::FalseExpr ||
8689 kind == ParseNodeKind::NumberExpr ||
8690 kind == ParseNodeKind::BigIntExpr ||
8691 kind == ParseNodeKind::StringExpr ||
8692 kind == ParseNodeKind::ArrayExpr ||
8693 kind == ParseNodeKind::ObjectExpr ||
8694 kind == ParseNodeKind::Function || kind == ParseNodeKind::ClassDecl ||
8695 kind == ParseNodeKind::RegExpExpr ||
8696 kind == ParseNodeKind::TemplateStringExpr ||
8697 kind == ParseNodeKind::TemplateStringListExpr ||
8698 kind == ParseNodeKind::RawUndefinedExpr || pn->isInParens();
8700 // https://tc39.es/ecma262/#sec-left-hand-side-expressions
8701 bool isMemberExpression = isPrimaryExpression ||
8702 kind == ParseNodeKind::TaggedTemplateExpr ||
8703 kind == ParseNodeKind::NewExpr ||
8704 kind == ParseNodeKind::NewTargetExpr ||
8705 kind == ParseNodeKind::ImportMetaExpr;
8707 bool isCallExpression = kind == ParseNodeKind::SetThis ||
8708 kind == ParseNodeKind::CallImportExpr;
8710 MOZ_ASSERT(isMemberExpression || isCallExpression,
8711 "Unknown ParseNodeKind for OptionalChain");
8712 #endif
8713 return emitTree(pn);
8715 return true;
8718 // Handle the case of a call made on a OptionalChainParseNode.
8719 // For example `(a?.b)()` and `(a?.b)?.()`.
8720 bool BytecodeEmitter::emitCalleeAndThisForOptionalChain(
8721 UnaryNode* optionalChain, CallNode* callNode, CallOrNewEmitter& cone) {
8722 ParseNode* calleeNode = optionalChain->kid();
8724 // Create a new OptionalEmitter, in order to emit the right bytecode
8725 // in isolation.
8726 OptionalEmitter oe(this, bytecodeSection().stackDepth());
8728 if (!emitOptionalCalleeAndThis(calleeNode, callNode, cone, oe)) {
8729 // [stack] CALLEE THIS
8730 return false;
8733 // complete the jump if necessary. This will set both the "this" value
8734 // and the "callee" value to undefined, if the callee is undefined. It
8735 // does not matter much what the this value is, the function call will
8736 // fail if it is not optional, and be set to undefined otherwise.
8737 if (!oe.emitOptionalJumpTarget(JSOp::Undefined,
8738 OptionalEmitter::Kind::Reference)) {
8739 // [stack] # If shortcircuit
8740 // [stack] UNDEFINED UNDEFINED
8741 // [stack] # otherwise
8742 // [stack] CALLEE THIS
8743 return false;
8745 return true;
8748 bool BytecodeEmitter::emitOptionalChain(UnaryNode* optionalChain,
8749 ValueUsage valueUsage) {
8750 ParseNode* expr = optionalChain->kid();
8752 OptionalEmitter oe(this, bytecodeSection().stackDepth());
8754 if (!emitOptionalTree(expr, oe, valueUsage)) {
8755 // [stack] VAL
8756 return false;
8759 if (!oe.emitOptionalJumpTarget(JSOp::Undefined)) {
8760 // [stack] # If shortcircuit
8761 // [stack] UNDEFINED
8762 // [stack] # otherwise
8763 // [stack] VAL
8764 return false;
8767 return true;
8770 bool BytecodeEmitter::emitOptionalDotExpression(PropertyAccessBase* prop,
8771 PropOpEmitter& poe,
8772 bool isSuper,
8773 OptionalEmitter& oe) {
8774 if (!poe.prepareForObj()) {
8775 // [stack]
8776 return false;
8779 if (isSuper) {
8780 UnaryNode* base = &prop->expression().as<UnaryNode>();
8781 if (!emitGetThisForSuperBase(base)) {
8782 // [stack] OBJ
8783 return false;
8785 } else {
8786 if (!emitOptionalTree(&prop->expression(), oe)) {
8787 // [stack] OBJ
8788 return false;
8792 if (prop->isKind(ParseNodeKind::OptionalDotExpr)) {
8793 MOZ_ASSERT(!isSuper);
8794 if (!oe.emitJumpShortCircuit()) {
8795 // [stack] # if Jump
8796 // [stack] UNDEFINED-OR-NULL
8797 // [stack] # otherwise
8798 // [stack] OBJ
8799 return false;
8803 if (!poe.emitGet(prop->key().atom())) {
8804 // [stack] PROP
8805 return false;
8808 return true;
8811 bool BytecodeEmitter::emitOptionalElemExpression(PropertyByValueBase* elem,
8812 ElemOpEmitter& eoe,
8813 bool isSuper,
8814 OptionalEmitter& oe) {
8815 if (!eoe.prepareForObj()) {
8816 // [stack]
8817 return false;
8820 if (isSuper) {
8821 UnaryNode* base = &elem->expression().as<UnaryNode>();
8822 if (!emitGetThisForSuperBase(base)) {
8823 // [stack] OBJ
8824 return false;
8826 } else {
8827 if (!emitOptionalTree(&elem->expression(), oe)) {
8828 // [stack] OBJ
8829 return false;
8833 if (elem->isKind(ParseNodeKind::OptionalElemExpr)) {
8834 MOZ_ASSERT(!isSuper);
8835 if (!oe.emitJumpShortCircuit()) {
8836 // [stack] # if Jump
8837 // [stack] UNDEFINED-OR-NULL
8838 // [stack] # otherwise
8839 // [stack] OBJ
8840 return false;
8844 if (!eoe.prepareForKey()) {
8845 // [stack] OBJ? OBJ
8846 return false;
8849 if (!emitTree(&elem->key())) {
8850 // [stack] OBJ? OBJ KEY
8851 return false;
8854 if (!eoe.emitGet()) {
8855 // [stack] ELEM
8856 return false;
8859 return true;
8862 bool BytecodeEmitter::emitOptionalPrivateExpression(
8863 PrivateMemberAccessBase* privateExpr, PrivateOpEmitter& xoe,
8864 OptionalEmitter& oe) {
8865 if (!emitOptionalTree(&privateExpr->expression(), oe)) {
8866 // [stack] OBJ
8867 return false;
8870 if (privateExpr->isKind(ParseNodeKind::OptionalPrivateMemberExpr)) {
8871 if (!oe.emitJumpShortCircuit()) {
8872 // [stack] # if Jump
8873 // [stack] UNDEFINED-OR-NULL
8874 // [stack] # otherwise
8875 // [stack] OBJ
8876 return false;
8880 if (!xoe.emitReference()) {
8881 // [stack] OBJ NAME
8882 return false;
8884 if (!xoe.emitGet()) {
8885 // [stack] CALLEE THIS # if call
8886 // [stack] VALUE # otherwise
8887 return false;
8890 return true;
8893 bool BytecodeEmitter::emitShortCircuit(ListNode* node, ValueUsage valueUsage) {
8894 MOZ_ASSERT(node->isKind(ParseNodeKind::OrExpr) ||
8895 node->isKind(ParseNodeKind::CoalesceExpr) ||
8896 node->isKind(ParseNodeKind::AndExpr));
8899 * JSOp::Or converts the operand on the stack to boolean, leaves the original
8900 * value on the stack and jumps if true; otherwise it falls into the next
8901 * bytecode, which pops the left operand and then evaluates the right operand.
8902 * The jump goes around the right operand evaluation.
8904 * JSOp::And converts the operand on the stack to boolean and jumps if false;
8905 * otherwise it falls into the right operand's bytecode.
8908 TDZCheckCache tdzCache(this);
8910 JSOp op;
8911 switch (node->getKind()) {
8912 case ParseNodeKind::OrExpr:
8913 op = JSOp::Or;
8914 break;
8915 case ParseNodeKind::CoalesceExpr:
8916 op = JSOp::Coalesce;
8917 break;
8918 case ParseNodeKind::AndExpr:
8919 op = JSOp::And;
8920 break;
8921 default:
8922 MOZ_CRASH("Unexpected ParseNodeKind");
8925 JumpList jump;
8927 // Left-associative operator chain: avoid too much recursion.
8929 // Emit all nodes but the last.
8930 for (ParseNode* expr : node->contentsTo(node->last())) {
8931 if (!emitTree(expr)) {
8932 return false;
8934 if (!emitJump(op, &jump)) {
8935 return false;
8937 if (!emit1(JSOp::Pop)) {
8938 return false;
8942 // Emit the last node
8943 if (!emitTree(node->last(), valueUsage)) {
8944 return false;
8947 if (!emitJumpTargetAndPatch(jump)) {
8948 return false;
8950 return true;
8953 bool BytecodeEmitter::emitSequenceExpr(ListNode* node, ValueUsage valueUsage) {
8954 for (ParseNode* child : node->contentsTo(node->last())) {
8955 if (!updateSourceCoordNotes(child->pn_pos.begin)) {
8956 return false;
8958 if (!emitTree(child, ValueUsage::IgnoreValue)) {
8959 return false;
8961 if (!emit1(JSOp::Pop)) {
8962 return false;
8966 ParseNode* child = node->last();
8967 if (!updateSourceCoordNotes(child->pn_pos.begin)) {
8968 return false;
8970 if (!emitTree(child, valueUsage)) {
8971 return false;
8973 return true;
8976 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
8977 // the comment on emitSwitch.
8978 MOZ_NEVER_INLINE bool BytecodeEmitter::emitIncOrDec(UnaryNode* incDec,
8979 ValueUsage valueUsage) {
8980 switch (incDec->kid()->getKind()) {
8981 case ParseNodeKind::DotExpr:
8982 return emitPropIncDec(incDec, valueUsage);
8983 case ParseNodeKind::ElemExpr:
8984 return emitElemIncDec(incDec, valueUsage);
8985 case ParseNodeKind::PrivateMemberExpr:
8986 return emitPrivateIncDec(incDec, valueUsage);
8987 case ParseNodeKind::CallExpr:
8988 return emitCallIncDec(incDec);
8989 default:
8990 return emitNameIncDec(incDec, valueUsage);
8994 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
8995 // the comment on emitSwitch.
8996 MOZ_NEVER_INLINE bool BytecodeEmitter::emitLabeledStatement(
8997 const LabeledStatement* labeledStmt) {
8998 auto name = labeledStmt->label();
8999 LabelEmitter label(this);
9001 label.emitLabel(name);
9003 if (!emitTree(labeledStmt->statement())) {
9004 return false;
9006 if (!label.emitEnd()) {
9007 return false;
9010 return true;
9013 bool BytecodeEmitter::emitConditionalExpression(
9014 ConditionalExpression& conditional, ValueUsage valueUsage) {
9015 CondEmitter cond(this);
9016 if (!cond.emitCond()) {
9017 return false;
9020 ParseNode* conditionNode = &conditional.condition();
9021 auto conditionKind = IfEmitter::ConditionKind::Positive;
9022 if (conditionNode->isKind(ParseNodeKind::NotExpr)) {
9023 conditionNode = conditionNode->as<UnaryNode>().kid();
9024 conditionKind = IfEmitter::ConditionKind::Negative;
9027 // NOTE: NotExpr of conditionNode may be unwrapped, and in that case the
9028 // negation is handled by conditionKind.
9029 if (!emitTree(conditionNode)) {
9030 return false;
9033 if (!cond.emitThenElse(conditionKind)) {
9034 return false;
9037 if (!emitTree(&conditional.thenExpression(), valueUsage)) {
9038 return false;
9041 if (!cond.emitElse()) {
9042 return false;
9045 if (!emitTree(&conditional.elseExpression(), valueUsage)) {
9046 return false;
9049 if (!cond.emitEnd()) {
9050 return false;
9052 MOZ_ASSERT(cond.pushed() == 1);
9054 return true;
9057 // Check for an object-literal property list that can be handled by the
9058 // ObjLiteral writer. We ensure that for each `prop: value` pair, the key is a
9059 // constant name or numeric index, there is no accessor specified, and the value
9060 // can be encoded by an ObjLiteral instruction (constant number, string,
9061 // boolean, null/undefined).
9062 void BytecodeEmitter::isPropertyListObjLiteralCompatible(ListNode* obj,
9063 bool* withValues,
9064 bool* withoutValues) {
9065 bool keysOK = true;
9066 bool valuesOK = true;
9067 uint32_t propCount = 0;
9069 for (ParseNode* propdef : obj->contents()) {
9070 if (!propdef->is<BinaryNode>()) {
9071 keysOK = false;
9072 break;
9074 propCount++;
9076 BinaryNode* prop = &propdef->as<BinaryNode>();
9077 ParseNode* key = prop->left();
9078 ParseNode* value = prop->right();
9080 // Computed keys not OK (ObjLiteral data stores constant keys).
9081 if (key->isKind(ParseNodeKind::ComputedName)) {
9082 keysOK = false;
9083 break;
9086 // BigIntExprs should have been lowered to computed names at parse
9087 // time, and so should be excluded above.
9088 MOZ_ASSERT(!key->isKind(ParseNodeKind::BigIntExpr));
9090 // Numeric keys OK as long as they are integers and in range.
9091 if (key->isKind(ParseNodeKind::NumberExpr)) {
9092 double numValue = key->as<NumericLiteral>().value();
9093 int32_t i = 0;
9094 if (!NumberIsInt32(numValue, &i)) {
9095 keysOK = false;
9096 break;
9098 if (!ObjLiteralWriter::arrayIndexInRange(i)) {
9099 keysOK = false;
9100 break;
9104 MOZ_ASSERT(key->isKind(ParseNodeKind::ObjectPropertyName) ||
9105 key->isKind(ParseNodeKind::StringExpr) ||
9106 key->isKind(ParseNodeKind::NumberExpr));
9108 AccessorType accessorType =
9109 prop->is<PropertyDefinition>()
9110 ? prop->as<PropertyDefinition>().accessorType()
9111 : AccessorType::None;
9112 if (accessorType != AccessorType::None) {
9113 keysOK = false;
9114 break;
9117 if (!isRHSObjLiteralCompatible(value)) {
9118 valuesOK = false;
9122 if (propCount > SharedPropMap::MaxPropsForNonDictionary) {
9123 // JSOp::NewObject cannot accept dictionary-mode objects.
9124 keysOK = false;
9127 *withValues = keysOK && valuesOK;
9128 *withoutValues = keysOK;
9131 bool BytecodeEmitter::isArrayObjLiteralCompatible(ListNode* array) {
9132 for (ParseNode* elem : array->contents()) {
9133 if (elem->isKind(ParseNodeKind::Spread)) {
9134 return false;
9136 if (!isRHSObjLiteralCompatible(elem)) {
9137 return false;
9140 return true;
9143 bool BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe,
9144 PropListType type) {
9145 // [stack] CTOR? OBJ
9147 size_t curFieldKeyIndex = 0;
9148 size_t curStaticFieldKeyIndex = 0;
9149 for (ParseNode* propdef : obj->contents()) {
9150 if (propdef->is<ClassField>()) {
9151 MOZ_ASSERT(type == ClassBody);
9152 // Only handle computing field keys here: the .initializers lambda array
9153 // is created elsewhere.
9154 ClassField* field = &propdef->as<ClassField>();
9155 if (field->name().getKind() == ParseNodeKind::ComputedName) {
9156 auto fieldKeys =
9157 field->isStatic()
9158 ? TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_()
9159 : TaggedParserAtomIndex::WellKnown::dot_fieldKeys_();
9160 if (!emitGetName(fieldKeys)) {
9161 // [stack] CTOR OBJ ARRAY
9162 return false;
9165 ParseNode* nameExpr = field->name().as<UnaryNode>().kid();
9167 if (!emitTree(nameExpr, ValueUsage::WantValue)) {
9168 // [stack] CTOR OBJ ARRAY KEY
9169 return false;
9172 if (!emit1(JSOp::ToPropertyKey)) {
9173 // [stack] CTOR OBJ ARRAY KEY
9174 return false;
9177 size_t fieldKeysIndex;
9178 if (field->isStatic()) {
9179 fieldKeysIndex = curStaticFieldKeyIndex++;
9180 } else {
9181 fieldKeysIndex = curFieldKeyIndex++;
9184 if (!emitUint32Operand(JSOp::InitElemArray, fieldKeysIndex)) {
9185 // [stack] CTOR OBJ ARRAY
9186 return false;
9189 if (!emit1(JSOp::Pop)) {
9190 // [stack] CTOR OBJ
9191 return false;
9194 continue;
9197 if (propdef->isKind(ParseNodeKind::StaticClassBlock)) {
9198 // Static class blocks are emitted as part of
9199 // emitCreateMemberInitializers.
9200 continue;
9203 if (propdef->is<LexicalScopeNode>()) {
9204 // Constructors are sometimes wrapped in LexicalScopeNodes. As we
9205 // already handled emitting the constructor, skip it.
9206 MOZ_ASSERT(
9207 propdef->as<LexicalScopeNode>().scopeBody()->is<ClassMethod>());
9208 continue;
9211 // Handle __proto__: v specially because *only* this form, and no other
9212 // involving "__proto__", performs [[Prototype]] mutation.
9213 if (propdef->isKind(ParseNodeKind::MutateProto)) {
9214 // [stack] OBJ
9215 MOZ_ASSERT(type == ObjectLiteral);
9216 if (!pe.prepareForProtoValue(propdef->pn_pos.begin)) {
9217 // [stack] OBJ
9218 return false;
9220 if (!emitTree(propdef->as<UnaryNode>().kid())) {
9221 // [stack] OBJ PROTO
9222 return false;
9224 if (!pe.emitMutateProto()) {
9225 // [stack] OBJ
9226 return false;
9228 continue;
9231 if (propdef->isKind(ParseNodeKind::Spread)) {
9232 MOZ_ASSERT(type == ObjectLiteral);
9233 // [stack] OBJ
9234 if (!pe.prepareForSpreadOperand(propdef->pn_pos.begin)) {
9235 // [stack] OBJ OBJ
9236 return false;
9238 if (!emitTree(propdef->as<UnaryNode>().kid())) {
9239 // [stack] OBJ OBJ VAL
9240 return false;
9242 if (!pe.emitSpread()) {
9243 // [stack] OBJ
9244 return false;
9246 continue;
9249 BinaryNode* prop = &propdef->as<BinaryNode>();
9251 ParseNode* key = prop->left();
9252 AccessorType accessorType;
9253 if (prop->is<ClassMethod>()) {
9254 ClassMethod& method = prop->as<ClassMethod>();
9255 accessorType = method.accessorType();
9257 if (!method.isStatic() && key->isKind(ParseNodeKind::PrivateName) &&
9258 accessorType != AccessorType::None) {
9259 // Private non-static accessors are stamped onto instances from
9260 // initializers; see emitCreateMemberInitializers.
9261 continue;
9263 } else if (prop->is<PropertyDefinition>()) {
9264 accessorType = prop->as<PropertyDefinition>().accessorType();
9265 } else {
9266 accessorType = AccessorType::None;
9269 auto emitValue = [this, &key, &prop, accessorType, &pe]() {
9270 // [stack] CTOR? OBJ CTOR? KEY?
9272 ParseNode* propVal = prop->right();
9273 if (propVal->isDirectRHSAnonFunction()) {
9274 // The following branches except for the last `else` clause emit the
9275 // cases handled in NameResolver::resolveFun (see NameFunctions.cpp)
9276 if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
9277 key->isKind(ParseNodeKind::PrivateName) ||
9278 key->isKind(ParseNodeKind::StringExpr)) {
9279 auto keyAtom = key->as<NameNode>().atom();
9280 if (!emitAnonymousFunctionWithName(propVal, keyAtom)) {
9281 // [stack] CTOR? OBJ CTOR? VAL
9282 return false;
9284 } else if (key->isKind(ParseNodeKind::NumberExpr)) {
9285 MOZ_ASSERT(accessorType == AccessorType::None);
9287 auto keyAtom = key->as<NumericLiteral>().toAtom(fc, parserAtoms());
9288 if (!keyAtom) {
9289 return false;
9291 if (!emitAnonymousFunctionWithName(propVal, keyAtom)) {
9292 // [stack] CTOR? OBJ CTOR? KEY VAL
9293 return false;
9295 } else if (key->isKind(ParseNodeKind::ComputedName) &&
9296 (key->as<UnaryNode>().kid()->isKind(
9297 ParseNodeKind::NumberExpr) ||
9298 key->as<UnaryNode>().kid()->isKind(
9299 ParseNodeKind::StringExpr)) &&
9300 accessorType == AccessorType::None) {
9301 ParseNode* keyKid = key->as<UnaryNode>().kid();
9302 if (keyKid->isKind(ParseNodeKind::NumberExpr)) {
9303 auto keyAtom =
9304 keyKid->as<NumericLiteral>().toAtom(fc, parserAtoms());
9305 if (!keyAtom) {
9306 return false;
9308 if (!emitAnonymousFunctionWithName(propVal, keyAtom)) {
9309 // [stack] CTOR? OBJ CTOR? KEY VAL
9310 return false;
9312 } else {
9313 MOZ_ASSERT(keyKid->isKind(ParseNodeKind::StringExpr));
9314 auto keyAtom = keyKid->as<NameNode>().atom();
9315 if (!emitAnonymousFunctionWithName(propVal, keyAtom)) {
9316 // [stack] CTOR? OBJ CTOR? KEY VAL
9317 return false;
9320 } else {
9321 // Either a proper computed property name or a synthetic computed
9322 // property name for BigInt keys.
9323 MOZ_ASSERT(key->isKind(ParseNodeKind::ComputedName));
9325 FunctionPrefixKind prefix =
9326 accessorType == AccessorType::None ? FunctionPrefixKind::None
9327 : accessorType == AccessorType::Getter ? FunctionPrefixKind::Get
9328 : FunctionPrefixKind::Set;
9330 if (!emitAnonymousFunctionWithComputedName(propVal, prefix)) {
9331 // [stack] CTOR? OBJ CTOR? KEY VAL
9332 return false;
9335 } else {
9336 if (!emitTree(propVal)) {
9337 // [stack] CTOR? OBJ CTOR? KEY? VAL
9338 return false;
9342 if (propVal->is<FunctionNode>() &&
9343 propVal->as<FunctionNode>().funbox()->needsHomeObject()) {
9344 if (!pe.emitInitHomeObject()) {
9345 // [stack] CTOR? OBJ CTOR? KEY? FUN
9346 return false;
9350 #ifdef ENABLE_DECORATORS
9351 if (prop->is<ClassMethod>()) {
9352 ClassMethod& method = prop->as<ClassMethod>();
9353 if (method.decorators() && !method.decorators()->empty()) {
9354 DecoratorEmitter::Kind kind;
9355 switch (method.accessorType()) {
9356 case AccessorType::Getter:
9357 kind = DecoratorEmitter::Getter;
9358 break;
9359 case AccessorType::Setter:
9360 kind = DecoratorEmitter::Setter;
9361 break;
9362 case AccessorType::None:
9363 kind = DecoratorEmitter::Method;
9364 break;
9367 // The decorators are applied to the current value on the stack,
9368 // possibly replacing it.
9369 DecoratorEmitter de(this);
9370 if (!de.emitApplyDecoratorsToElementDefinition(
9371 kind, key, method.decorators(), method.isStatic())) {
9372 // [stack] CTOR? OBJ CTOR? KEY? VAL
9373 return false;
9377 #endif
9379 return true;
9382 PropertyEmitter::Kind kind =
9383 (type == ClassBody && propdef->as<ClassMethod>().isStatic())
9384 ? PropertyEmitter::Kind::Static
9385 : PropertyEmitter::Kind::Prototype;
9386 if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
9387 key->isKind(ParseNodeKind::StringExpr)) {
9388 // [stack] CTOR? OBJ
9390 auto keyAtom = key->as<NameNode>().atom();
9392 // emitClass took care of constructor already.
9393 if (type == ClassBody &&
9394 keyAtom == TaggedParserAtomIndex::WellKnown::constructor() &&
9395 !propdef->as<ClassMethod>().isStatic()) {
9396 continue;
9399 if (!pe.prepareForPropValue(propdef->pn_pos.begin, kind)) {
9400 // [stack] CTOR? OBJ CTOR?
9401 return false;
9404 if (!emitValue()) {
9405 // [stack] CTOR? OBJ CTOR? VAL
9406 return false;
9409 if (!pe.emitInit(accessorType, keyAtom)) {
9410 // [stack] CTOR? OBJ
9411 return false;
9414 continue;
9417 if (key->isKind(ParseNodeKind::NumberExpr)) {
9418 // [stack] CTOR? OBJ
9419 if (!pe.prepareForIndexPropKey(propdef->pn_pos.begin, kind)) {
9420 // [stack] CTOR? OBJ CTOR?
9421 return false;
9423 if (!emitNumberOp(key->as<NumericLiteral>().value())) {
9424 // [stack] CTOR? OBJ CTOR? KEY
9425 return false;
9427 if (!pe.prepareForIndexPropValue()) {
9428 // [stack] CTOR? OBJ CTOR? KEY
9429 return false;
9431 if (!emitValue()) {
9432 // [stack] CTOR? OBJ CTOR? KEY VAL
9433 return false;
9436 if (!pe.emitInitIndexOrComputed(accessorType)) {
9437 // [stack] CTOR? OBJ
9438 return false;
9441 continue;
9444 if (key->isKind(ParseNodeKind::ComputedName)) {
9445 // Either a proper computed property name or a synthetic computed property
9446 // name for BigInt keys.
9448 // [stack] CTOR? OBJ
9450 if (!pe.prepareForComputedPropKey(propdef->pn_pos.begin, kind)) {
9451 // [stack] CTOR? OBJ CTOR?
9452 return false;
9454 if (!emitTree(key->as<UnaryNode>().kid())) {
9455 // [stack] CTOR? OBJ CTOR? KEY
9456 return false;
9458 if (!pe.prepareForComputedPropValue()) {
9459 // [stack] CTOR? OBJ CTOR? KEY
9460 return false;
9462 if (!emitValue()) {
9463 // [stack] CTOR? OBJ CTOR? KEY VAL
9464 return false;
9467 if (!pe.emitInitIndexOrComputed(accessorType)) {
9468 // [stack] CTOR? OBJ
9469 return false;
9472 continue;
9475 MOZ_ASSERT(key->isKind(ParseNodeKind::PrivateName));
9476 MOZ_ASSERT(type == ClassBody);
9478 auto* privateName = &key->as<NameNode>();
9480 if (kind == PropertyEmitter::Kind::Prototype) {
9481 MOZ_ASSERT(accessorType == AccessorType::None);
9482 if (!pe.prepareForPrivateMethod()) {
9483 // [stack] CTOR OBJ
9484 return false;
9486 NameOpEmitter noe(this, privateName->atom(),
9487 NameOpEmitter::Kind::SimpleAssignment);
9489 // Ensure the NameOp emitter doesn't push an environment onto the stack,
9490 // because that would change the stack location of the home object.
9491 MOZ_ASSERT(noe.loc().kind() == NameLocation::Kind::FrameSlot ||
9492 noe.loc().kind() == NameLocation::Kind::EnvironmentCoordinate);
9494 if (!noe.prepareForRhs()) {
9495 // [stack] CTOR OBJ
9496 return false;
9498 if (!emitValue()) {
9499 // [stack] CTOR OBJ METHOD
9500 return false;
9502 if (!noe.emitAssignment()) {
9503 // [stack] CTOR OBJ METHOD
9504 return false;
9506 if (!emit1(JSOp::Pop)) {
9507 // [stack] CTOR OBJ
9508 return false;
9510 if (!pe.skipInit()) {
9511 // [stack] CTOR OBJ
9512 return false;
9514 continue;
9517 MOZ_ASSERT(kind == PropertyEmitter::Kind::Static);
9519 // [stack] CTOR OBJ
9521 if (!pe.prepareForPrivateStaticMethod(propdef->pn_pos.begin)) {
9522 // [stack] CTOR OBJ CTOR
9523 return false;
9525 if (!emitGetPrivateName(privateName)) {
9526 // [stack] CTOR OBJ CTOR KEY
9527 return false;
9529 if (!emitValue()) {
9530 // [stack] CTOR OBJ CTOR KEY VAL
9531 return false;
9534 if (!pe.emitPrivateStaticMethod(accessorType)) {
9535 // [stack] CTOR OBJ
9536 return false;
9539 if (privateName->privateNameKind() == PrivateNameKind::Setter) {
9540 if (!emitDupAt(1)) {
9541 // [stack] CTOR OBJ CTOR
9542 return false;
9544 if (!emitGetPrivateName(privateName)) {
9545 // [stack] CTOR OBJ CTOR NAME
9546 return false;
9548 if (!emitAtomOp(JSOp::GetIntrinsic,
9549 TaggedParserAtomIndex::WellKnown::NoPrivateGetter())) {
9550 // [stack] CTOR OBJ CTOR NAME FUN
9551 return false;
9553 if (!emit1(JSOp::InitHiddenElemGetter)) {
9554 // [stack] CTOR OBJ CTOR
9555 return false;
9557 if (!emit1(JSOp::Pop)) {
9558 // [stack] CTOR OBJ
9559 return false;
9564 return true;
9567 bool BytecodeEmitter::emitPropertyListObjLiteral(ListNode* obj, JSOp op,
9568 bool useObjLiteralValues) {
9569 ObjLiteralWriter writer;
9571 #ifdef DEBUG
9572 // In self-hosted JS, we check duplication only on debug build.
9573 mozilla::Maybe<mozilla::HashSet<frontend::TaggedParserAtomIndex,
9574 frontend::TaggedParserAtomIndexHasher>>
9575 selfHostedPropNames;
9576 if (emitterMode == BytecodeEmitter::SelfHosting) {
9577 selfHostedPropNames.emplace();
9579 #endif
9581 if (op == JSOp::Object) {
9582 writer.beginObject(op);
9583 } else {
9584 MOZ_ASSERT(op == JSOp::NewObject);
9585 writer.beginShape(op);
9588 for (ParseNode* propdef : obj->contents()) {
9589 BinaryNode* prop = &propdef->as<BinaryNode>();
9590 ParseNode* key = prop->left();
9592 if (key->is<NameNode>()) {
9593 if (emitterMode == BytecodeEmitter::SelfHosting) {
9594 auto propName = key->as<NameNode>().atom();
9595 #ifdef DEBUG
9596 // Self-hosted JS shouldn't contain duplicate properties.
9597 auto p = selfHostedPropNames->lookupForAdd(propName);
9598 MOZ_ASSERT(!p);
9599 if (!selfHostedPropNames->add(p, propName)) {
9600 js::ReportOutOfMemory(fc);
9601 return false;
9603 #endif
9604 writer.setPropNameNoDuplicateCheck(parserAtoms(), propName);
9605 } else {
9606 if (!writer.setPropName(parserAtoms(), key->as<NameNode>().atom())) {
9607 return false;
9610 } else {
9611 double numValue = key->as<NumericLiteral>().value();
9612 int32_t i = 0;
9613 DebugOnly<bool> numIsInt =
9614 NumberIsInt32(numValue, &i); // checked previously.
9615 MOZ_ASSERT(numIsInt);
9616 MOZ_ASSERT(
9617 ObjLiteralWriter::arrayIndexInRange(i)); // checked previously.
9619 // Ignore indexed properties if we're not storing property values, and
9620 // rely on InitElem ops to define those. These properties will be either
9621 // dense elements (not possible to represent in the literal's shape) or
9622 // sparse elements (enumerated separately, so this doesn't affect property
9623 // iteration order).
9624 if (!useObjLiteralValues) {
9625 continue;
9628 writer.setPropIndex(i);
9631 if (useObjLiteralValues) {
9632 MOZ_ASSERT(op == JSOp::Object);
9633 ParseNode* value = prop->right();
9634 if (!emitObjLiteralValue(writer, value)) {
9635 return false;
9637 } else {
9638 if (!writer.propWithUndefinedValue(fc)) {
9639 return false;
9644 GCThingIndex index;
9645 if (!addObjLiteralData(writer, &index)) {
9646 return false;
9649 // JSOp::Object may only be used by (top-level) run-once scripts.
9650 MOZ_ASSERT_IF(op == JSOp::Object,
9651 sc->isTopLevelContext() && sc->treatAsRunOnce());
9653 if (!emitGCIndexOp(op, index)) {
9654 // [stack] OBJ
9655 return false;
9658 return true;
9661 bool BytecodeEmitter::emitDestructuringRestExclusionSetObjLiteral(
9662 ListNode* pattern) {
9663 // Note: if we want to squeeze out a little more performance, we could switch
9664 // to the `JSOp::Object` opcode, because the exclusion set object is never
9665 // exposed to the user, so it's safe to bake the object into the bytecode.
9666 constexpr JSOp op = JSOp::NewObject;
9668 ObjLiteralWriter writer;
9669 writer.beginShape(op);
9671 for (ParseNode* member : pattern->contents()) {
9672 if (member->isKind(ParseNodeKind::Spread)) {
9673 MOZ_ASSERT(!member->pn_next, "unexpected trailing element after spread");
9674 break;
9677 TaggedParserAtomIndex atom;
9678 if (member->isKind(ParseNodeKind::MutateProto)) {
9679 atom = TaggedParserAtomIndex::WellKnown::proto_();
9680 } else {
9681 ParseNode* key = member->as<BinaryNode>().left();
9682 atom = key->as<NameNode>().atom();
9685 if (!writer.setPropName(parserAtoms(), atom)) {
9686 return false;
9689 if (!writer.propWithUndefinedValue(fc)) {
9690 return false;
9694 GCThingIndex index;
9695 if (!addObjLiteralData(writer, &index)) {
9696 return false;
9699 if (!emitGCIndexOp(op, index)) {
9700 // [stack] OBJ
9701 return false;
9704 return true;
9707 bool BytecodeEmitter::emitObjLiteralArray(ListNode* array) {
9708 MOZ_ASSERT(checkSingletonContext());
9710 constexpr JSOp op = JSOp::Object;
9712 ObjLiteralWriter writer;
9713 writer.beginArray(op);
9715 writer.beginDenseArrayElements();
9716 for (ParseNode* elem : array->contents()) {
9717 if (!emitObjLiteralValue(writer, elem)) {
9718 return false;
9722 GCThingIndex index;
9723 if (!addObjLiteralData(writer, &index)) {
9724 return false;
9727 if (!emitGCIndexOp(op, index)) {
9728 // [stack] OBJ
9729 return false;
9732 return true;
9735 bool BytecodeEmitter::isRHSObjLiteralCompatible(ParseNode* value) {
9736 return value->isKind(ParseNodeKind::NumberExpr) ||
9737 value->isKind(ParseNodeKind::TrueExpr) ||
9738 value->isKind(ParseNodeKind::FalseExpr) ||
9739 value->isKind(ParseNodeKind::NullExpr) ||
9740 value->isKind(ParseNodeKind::RawUndefinedExpr) ||
9741 value->isKind(ParseNodeKind::StringExpr) ||
9742 value->isKind(ParseNodeKind::TemplateStringExpr);
9745 bool BytecodeEmitter::emitObjLiteralValue(ObjLiteralWriter& writer,
9746 ParseNode* value) {
9747 MOZ_ASSERT(isRHSObjLiteralCompatible(value));
9748 if (value->isKind(ParseNodeKind::NumberExpr)) {
9749 double numValue = value->as<NumericLiteral>().value();
9750 int32_t i = 0;
9751 js::Value v;
9752 if (NumberIsInt32(numValue, &i)) {
9753 v.setInt32(i);
9754 } else {
9755 v.setDouble(numValue);
9757 if (!writer.propWithConstNumericValue(fc, v)) {
9758 return false;
9760 } else if (value->isKind(ParseNodeKind::TrueExpr)) {
9761 if (!writer.propWithTrueValue(fc)) {
9762 return false;
9764 } else if (value->isKind(ParseNodeKind::FalseExpr)) {
9765 if (!writer.propWithFalseValue(fc)) {
9766 return false;
9768 } else if (value->isKind(ParseNodeKind::NullExpr)) {
9769 if (!writer.propWithNullValue(fc)) {
9770 return false;
9772 } else if (value->isKind(ParseNodeKind::RawUndefinedExpr)) {
9773 if (!writer.propWithUndefinedValue(fc)) {
9774 return false;
9776 } else if (value->isKind(ParseNodeKind::StringExpr) ||
9777 value->isKind(ParseNodeKind::TemplateStringExpr)) {
9778 if (!writer.propWithAtomValue(fc, parserAtoms(),
9779 value->as<NameNode>().atom())) {
9780 return false;
9782 } else {
9783 MOZ_CRASH("Unexpected parse node");
9785 return true;
9788 static bool NeedsPrivateBrand(ParseNode* member) {
9789 return member->is<ClassMethod>() &&
9790 member->as<ClassMethod>().name().isKind(ParseNodeKind::PrivateName) &&
9791 !member->as<ClassMethod>().isStatic();
9794 mozilla::Maybe<MemberInitializers> BytecodeEmitter::setupMemberInitializers(
9795 ListNode* classMembers, FieldPlacement placement) {
9796 bool isStatic = placement == FieldPlacement::Static;
9798 size_t numFields = 0;
9799 size_t numPrivateInitializers = 0;
9800 bool hasPrivateBrand = false;
9801 for (ParseNode* member : classMembers->contents()) {
9802 if (NeedsFieldInitializer(member, isStatic)) {
9803 numFields++;
9804 } else if (NeedsAccessorInitializer(member, isStatic)) {
9805 numPrivateInitializers++;
9806 hasPrivateBrand = true;
9807 } else if (NeedsPrivateBrand(member)) {
9808 hasPrivateBrand = true;
9812 // If there are more initializers than can be represented, return invalid.
9813 if (numFields + numPrivateInitializers >
9814 MemberInitializers::MaxInitializers) {
9815 return Nothing();
9817 return Some(
9818 MemberInitializers(hasPrivateBrand, numFields + numPrivateInitializers));
9821 // Purpose of .fieldKeys:
9822 // Computed field names (`["x"] = 2;`) must be ran at class-evaluation time,
9823 // not object construction time. The transformation to do so is roughly as
9824 // follows:
9826 // class C {
9827 // [keyExpr] = valueExpr;
9828 // }
9829 // -->
9830 // let .fieldKeys = [keyExpr];
9831 // let .initializers = [
9832 // () => {
9833 // this[.fieldKeys[0]] = valueExpr;
9834 // }
9835 // ];
9836 // class C {
9837 // constructor() {
9838 // .initializers[0]();
9839 // }
9840 // }
9842 // BytecodeEmitter::emitCreateFieldKeys does `let .fieldKeys = [...];`
9843 // BytecodeEmitter::emitPropertyList fills in the elements of the array.
9844 // See GeneralParser::fieldInitializer for the `this[.fieldKeys[0]]` part.
9845 bool BytecodeEmitter::emitCreateFieldKeys(ListNode* obj,
9846 FieldPlacement placement) {
9847 bool isStatic = placement == FieldPlacement::Static;
9848 auto isFieldWithComputedName = [isStatic](ParseNode* propdef) {
9849 return propdef->is<ClassField>() &&
9850 propdef->as<ClassField>().isStatic() == isStatic &&
9851 propdef->as<ClassField>().name().getKind() ==
9852 ParseNodeKind::ComputedName;
9855 size_t numFieldKeys = std::count_if(
9856 obj->contents().begin(), obj->contents().end(), isFieldWithComputedName);
9857 if (numFieldKeys == 0) {
9858 return true;
9861 auto fieldKeys =
9862 isStatic ? TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_()
9863 : TaggedParserAtomIndex::WellKnown::dot_fieldKeys_();
9864 NameOpEmitter noe(this, fieldKeys, NameOpEmitter::Kind::Initialize);
9865 if (!noe.prepareForRhs()) {
9866 return false;
9869 if (!emitUint32Operand(JSOp::NewArray, numFieldKeys)) {
9870 // [stack] ARRAY
9871 return false;
9874 if (!noe.emitAssignment()) {
9875 // [stack] ARRAY
9876 return false;
9879 if (!emit1(JSOp::Pop)) {
9880 // [stack]
9881 return false;
9884 return true;
9887 static bool HasInitializer(ParseNode* node, bool isStaticContext) {
9888 return (node->is<ClassField>() &&
9889 node->as<ClassField>().isStatic() == isStaticContext) ||
9890 (isStaticContext && node->is<StaticClassBlock>());
9893 static FunctionNode* GetInitializer(ParseNode* node, bool isStaticContext) {
9894 MOZ_ASSERT(HasInitializer(node, isStaticContext));
9895 MOZ_ASSERT_IF(!node->is<ClassField>(), isStaticContext);
9896 return node->is<ClassField>() ? node->as<ClassField>().initializer()
9897 : node->as<StaticClassBlock>().function();
9900 static bool IsPrivateInstanceAccessor(const ClassMethod* classMethod) {
9901 return !classMethod->isStatic() &&
9902 classMethod->name().isKind(ParseNodeKind::PrivateName) &&
9903 classMethod->accessorType() != AccessorType::None;
9906 bool BytecodeEmitter::emitCreateMemberInitializers(ClassEmitter& ce,
9907 ListNode* obj,
9908 FieldPlacement placement
9909 #ifdef ENABLE_DECORATORS
9911 bool hasHeritage
9912 #endif
9914 // FieldPlacement::Instance, hasHeritage == false
9915 // [stack] HOMEOBJ
9917 // FieldPlacement::Instance, hasHeritage == true
9918 // [stack] HOMEOBJ HERITAGE
9920 // FieldPlacement::Static
9921 // [stack] CTOR HOMEOBJ
9922 #ifdef ENABLE_DECORATORS
9923 MOZ_ASSERT_IF(placement == FieldPlacement::Static, !hasHeritage);
9924 #endif
9925 mozilla::Maybe<MemberInitializers> memberInitializers =
9926 setupMemberInitializers(obj, placement);
9927 if (!memberInitializers) {
9928 ReportAllocationOverflow(fc);
9929 return false;
9932 size_t numInitializers = memberInitializers->numMemberInitializers;
9933 if (numInitializers == 0) {
9934 return true;
9937 bool isStatic = placement == FieldPlacement::Static;
9938 if (!ce.prepareForMemberInitializers(numInitializers, isStatic)) {
9939 // [stack] HOMEOBJ HERITAGE? ARRAY
9940 // or:
9941 // [stack] CTOR HOMEOBJ ARRAY
9942 return false;
9945 // Private accessors could be used in the field initializers, so make sure
9946 // accessor initializers appear earlier in the .initializers array so they
9947 // run first. Static private methods are not initialized using initializers
9948 // (emitPropertyList emits bytecode to stamp them onto the constructor), so
9949 // skip this step if isStatic.
9950 if (!isStatic) {
9951 if (!emitPrivateMethodInitializers(ce, obj)) {
9952 return false;
9956 for (ParseNode* propdef : obj->contents()) {
9957 if (!HasInitializer(propdef, isStatic)) {
9958 continue;
9961 FunctionNode* initializer = GetInitializer(propdef, isStatic);
9963 if (!ce.prepareForMemberInitializer()) {
9964 return false;
9966 if (!emitTree(initializer)) {
9967 // [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA
9968 // or:
9969 // [stack] CTOR HOMEOBJ ARRAY LAMBDA
9970 return false;
9972 if (initializer->funbox()->needsHomeObject()) {
9973 MOZ_ASSERT(initializer->funbox()->allowSuperProperty());
9974 if (!ce.emitMemberInitializerHomeObject(isStatic)) {
9975 // [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA
9976 // or:
9977 // [stack] CTOR HOMEOBJ ARRAY LAMBDA
9978 return false;
9981 if (!ce.emitStoreMemberInitializer()) {
9982 // [stack] HOMEOBJ HERITAGE? ARRAY
9983 // or:
9984 // [stack] CTOR HOMEOBJ ARRAY
9985 return false;
9989 #ifdef ENABLE_DECORATORS
9990 // Index to use to append new initializers returned by decorators to the array
9991 if (!emitNumberOp(numInitializers)) {
9992 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX
9993 // or:
9994 // [stack] CTOR HOMEOBJ ARRAY INDEX
9995 return false;
9998 for (ParseNode* propdef : obj->contents()) {
9999 if (!propdef->is<ClassField>()) {
10000 continue;
10002 ClassField* field = &propdef->as<ClassField>();
10003 if (field->isStatic() != isStatic) {
10004 continue;
10006 if (field->decorators() && !field->decorators()->empty()) {
10007 DecoratorEmitter de(this);
10008 if (!field->hasAccessor()) {
10009 if (!de.emitApplyDecoratorsToFieldDefinition(
10010 &field->name(), field->decorators(), field->isStatic())) {
10011 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS
10012 // or:
10013 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS
10014 return false;
10016 } else {
10017 ClassMethod* accessorGetterNode = field->accessorGetterNode();
10018 auto accessorGetterKeyAtom =
10019 accessorGetterNode->left()->as<NameNode>().atom();
10020 ClassMethod* accessorSetterNode = field->accessorSetterNode();
10021 auto accessorSetterKeyAtom =
10022 accessorSetterNode->left()->as<NameNode>().atom();
10023 if (!IsPrivateInstanceAccessor(accessorGetterNode)) {
10024 if (!emitTree(&accessorGetterNode->method())) {
10025 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER
10026 // or:
10027 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER
10028 return false;
10030 if (!emitTree(&accessorSetterNode->method())) {
10031 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER SETTER
10032 // or:
10033 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER SETTER
10034 return false;
10036 } else {
10037 MOZ_ASSERT(IsPrivateInstanceAccessor(accessorSetterNode));
10038 auto getAccessor = [this](
10039 ClassMethod* classMethod,
10040 TaggedParserAtomIndex& updatedAtom) -> bool {
10041 // [stack]
10043 // Synthesize a name for the lexical variable that will store the
10044 // private method body.
10045 TaggedParserAtomIndex name =
10046 classMethod->name().as<NameNode>().atom();
10047 AccessorType accessorType = classMethod->accessorType();
10048 StringBuffer storedMethodName(fc);
10049 if (!storedMethodName.append(parserAtoms(), name)) {
10050 return false;
10052 if (!storedMethodName.append(accessorType == AccessorType::Getter
10053 ? ".getter"
10054 : ".setter")) {
10055 return false;
10057 updatedAtom = storedMethodName.finishParserAtom(parserAtoms(), fc);
10058 if (!updatedAtom) {
10059 return false;
10062 return emitGetName(updatedAtom);
10063 // [stack] ACCESSOR
10066 if (!getAccessor(accessorGetterNode, accessorGetterKeyAtom)) {
10067 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER
10068 // or:
10069 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER
10070 return false;
10073 if (!getAccessor(accessorSetterNode, accessorSetterKeyAtom)) {
10074 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER SETTER
10075 // or:
10076 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER SETTER
10077 return false;
10081 if (!de.emitApplyDecoratorsToAccessorDefinition(
10082 &field->name(), field->decorators(), field->isStatic())) {
10083 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER SETTER INITS
10084 // or:
10085 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER SETTER INITS
10086 return false;
10089 if (!emitUnpickN(2)) {
10090 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER SETTER
10091 // or:
10092 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER SETTER
10093 return false;
10096 if (!IsPrivateInstanceAccessor(accessorGetterNode)) {
10097 if (!isStatic) {
10098 if (!emitPickN(hasHeritage ? 6 : 5)) {
10099 // [stack] HERITAGE? ARRAY INDEX INITS GETTER SETTER HOMEOBJ
10100 return false;
10102 } else {
10103 if (!emitPickN(6)) {
10104 // [stack] HOMEOBJ ARRAY INDEX INITS GETTER SETTER CTOR
10105 return false;
10107 if (!emitPickN(6)) {
10108 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ
10109 return false;
10113 PropertyEmitter::Kind kind = field->isStatic()
10114 ? PropertyEmitter::Kind::Static
10115 : PropertyEmitter::Kind::Prototype;
10116 if (!accessorGetterNode->name().isKind(ParseNodeKind::PrivateName)) {
10117 MOZ_ASSERT(
10118 !accessorSetterNode->name().isKind(ParseNodeKind::PrivateName));
10120 if (!ce.prepareForPropValue(propdef->pn_pos.begin, kind)) {
10121 // [stack] HERITAGE? ARRAY INDEX INITS GETTER SETTER HOMEOBJ
10122 // or:
10123 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ CTOR
10124 return false;
10126 if (!emitPickN(isStatic ? 3 : 1)) {
10127 // [stack] HERITAGE? ARRAY INDEX INITS GETTER HOMEOBJ SETTER
10128 // or:
10129 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR SETTER
10130 return false;
10132 if (!ce.emitInit(AccessorType::Setter, accessorSetterKeyAtom)) {
10133 // [stack] HERITAGE? ARRAY INDEX INITS GETTER HOMEOBJ
10134 // or:
10135 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ
10136 return false;
10139 if (!ce.prepareForPropValue(propdef->pn_pos.begin, kind)) {
10140 // [stack] HERITAGE? ARRAY INDEX INITS GETTER HOMEOBJ
10141 // or:
10142 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR
10143 return false;
10145 if (!emitPickN(isStatic ? 3 : 1)) {
10146 // [stack] HERITAGE? ARRAY INDEX INITS HOMEOBJ GETTER
10147 // or:
10148 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ CTOR GETTER
10149 return false;
10151 if (!ce.emitInit(AccessorType::Getter, accessorGetterKeyAtom)) {
10152 // [stack] HERITAGE? ARRAY INDEX INITS HOMEOBJ
10153 // or:
10154 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ
10155 return false;
10157 } else {
10158 MOZ_ASSERT(isStatic);
10159 // The getter and setter share the same name.
10160 if (!emitNewPrivateName(accessorSetterKeyAtom,
10161 accessorSetterKeyAtom)) {
10162 return false;
10164 if (!ce.prepareForPrivateStaticMethod(propdef->pn_pos.begin)) {
10165 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ CTOR
10166 return false;
10168 if (!emitGetPrivateName(
10169 &accessorSetterNode->name().as<NameNode>())) {
10170 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ CTOR
10171 // KEY
10172 return false;
10174 if (!emitPickN(4)) {
10175 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR KEY
10176 // SETTER
10177 return false;
10179 if (!ce.emitPrivateStaticMethod(AccessorType::Setter)) {
10180 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ
10181 return false;
10184 if (!ce.prepareForPrivateStaticMethod(propdef->pn_pos.begin)) {
10185 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR
10186 return false;
10188 if (!emitGetPrivateName(
10189 &accessorGetterNode->name().as<NameNode>())) {
10190 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR KEY
10191 return false;
10193 if (!emitPickN(4)) {
10194 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ CTOR KEY GETTER
10195 return false;
10197 if (!ce.emitPrivateStaticMethod(AccessorType::Getter)) {
10198 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ
10199 return false;
10203 if (!isStatic) {
10204 if (!emitUnpickN(hasHeritage ? 4 : 3)) {
10205 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS
10206 return false;
10208 } else {
10209 if (!emitUnpickN(4)) {
10210 // [stack] HOMEOBJ ARRAY INDEX INITS CTOR
10211 return false;
10213 if (!emitUnpickN(4)) {
10214 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS
10215 return false;
10218 } else {
10219 MOZ_ASSERT(IsPrivateInstanceAccessor(accessorSetterNode));
10221 if (!emitLexicalInitialization(accessorSetterKeyAtom)) {
10222 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER SETTER
10223 // or:
10224 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER SETTER
10225 return false;
10228 if (!emitPopN(1)) {
10229 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER
10230 // or:
10231 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER
10232 return false;
10235 if (!emitLexicalInitialization(accessorGetterKeyAtom)) {
10236 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER
10237 // or:
10238 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER
10239 return false;
10242 if (!emitPopN(1)) {
10243 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS
10244 // or:
10245 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS
10246 return false;
10250 if (!emit1(JSOp::InitElemInc)) {
10251 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX
10252 // or:
10253 // [stack] CTOR HOMEOBJ ARRAY INDEX
10254 return false;
10259 // Pop INDEX
10260 if (!emitPopN(1)) {
10261 // [stack] HOMEOBJ HERITAGE? ARRAY
10262 // or:
10263 // [stack] CTOR HOMEOBJ ARRAY
10264 return false;
10266 #endif
10268 if (!ce.emitMemberInitializersEnd()) {
10269 // [stack] HOMEOBJ HERITAGE?
10270 // or:
10271 // [stack] CTOR HOMEOBJ
10272 return false;
10275 return true;
10278 bool BytecodeEmitter::emitPrivateMethodInitializers(ClassEmitter& ce,
10279 ListNode* obj) {
10280 for (ParseNode* propdef : obj->contents()) {
10281 if (!propdef->is<ClassMethod>()) {
10282 continue;
10284 auto* classMethod = &propdef->as<ClassMethod>();
10286 // Skip over anything which isn't a private instance accessor.
10287 if (!IsPrivateInstanceAccessor(classMethod)) {
10288 continue;
10291 if (!ce.prepareForMemberInitializer()) {
10292 // [stack] HOMEOBJ HERITAGE? ARRAY
10293 // or:
10294 // [stack] CTOR HOMEOBJ ARRAY
10295 return false;
10298 // Synthesize a name for the lexical variable that will store the
10299 // private method body.
10300 TaggedParserAtomIndex name = classMethod->name().as<NameNode>().atom();
10301 AccessorType accessorType = classMethod->accessorType();
10302 StringBuffer storedMethodName(fc);
10303 if (!storedMethodName.append(parserAtoms(), name)) {
10304 return false;
10306 if (!storedMethodName.append(
10307 accessorType == AccessorType::Getter ? ".getter" : ".setter")) {
10308 return false;
10310 auto storedMethodAtom =
10311 storedMethodName.finishParserAtom(parserAtoms(), fc);
10313 // Emit the private method body and store it as a lexical var.
10314 if (!emitFunction(&classMethod->method())) {
10315 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
10316 // or:
10317 // [stack] CTOR HOMEOBJ ARRAY METHOD
10318 return false;
10320 // The private method body needs to access the home object,
10321 // and the CE knows where that is on the stack.
10322 if (classMethod->method().funbox()->needsHomeObject()) {
10323 if (!ce.emitMemberInitializerHomeObject(false)) {
10324 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
10325 // or:
10326 // [stack] CTOR HOMEOBJ ARRAY METHOD
10327 return false;
10330 if (!emitLexicalInitialization(storedMethodAtom)) {
10331 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
10332 // or:
10333 // [stack] CTOR HOMEOBJ ARRAY METHOD
10334 return false;
10336 if (!emit1(JSOp::Pop)) {
10337 // [stack] HOMEOBJ HERITAGE? ARRAY
10338 // or:
10339 // [stack] CTOR HOMEOBJ ARRAY
10340 return false;
10343 if (!emitPrivateMethodInitializer(classMethod, storedMethodAtom)) {
10344 // [stack] HOMEOBJ HERITAGE? ARRAY
10345 // or:
10346 // [stack] CTOR HOMEOBJ ARRAY
10347 return false;
10350 // Store the emitted initializer function into the .initializers array.
10351 if (!ce.emitStoreMemberInitializer()) {
10352 // [stack] HOMEOBJ HERITAGE? ARRAY
10353 // or:
10354 // [stack] CTOR HOMEOBJ ARRAY
10355 return false;
10359 return true;
10362 bool BytecodeEmitter::emitPrivateMethodInitializer(
10363 ClassMethod* classMethod, TaggedParserAtomIndex storedMethodAtom) {
10364 MOZ_ASSERT(IsPrivateInstanceAccessor(classMethod));
10366 auto* name = &classMethod->name().as<NameNode>();
10368 // Emit the synthesized initializer function.
10369 FunctionNode* funNode = classMethod->initializerIfPrivate();
10370 MOZ_ASSERT(funNode);
10371 FunctionBox* funbox = funNode->funbox();
10372 FunctionEmitter fe(this, funbox, funNode->syntaxKind(),
10373 FunctionEmitter::IsHoisted::No);
10374 if (!fe.prepareForNonLazy()) {
10375 // [stack]
10376 return false;
10379 BytecodeEmitter bce2(this, funbox);
10380 if (!bce2.init(funNode->pn_pos)) {
10381 return false;
10383 ParamsBodyNode* paramsBody = funNode->body();
10384 FunctionScriptEmitter fse(&bce2, funbox, Nothing(), Nothing());
10385 if (!fse.prepareForParameters()) {
10386 // [stack]
10387 return false;
10389 if (!bce2.emitFunctionFormalParameters(paramsBody)) {
10390 // [stack]
10391 return false;
10393 if (!fse.prepareForBody()) {
10394 // [stack]
10395 return false;
10398 if (!bce2.emit1(JSOp::FunctionThis)) {
10399 // [stack] THIS
10400 return false;
10402 if (!bce2.emitGetPrivateName(name)) {
10403 // [stack] THIS NAME
10404 return false;
10406 if (!bce2.emitGetName(storedMethodAtom)) {
10407 // [stack] THIS NAME METHOD
10408 return false;
10411 switch (name->privateNameKind()) {
10412 case PrivateNameKind::Setter:
10413 if (!bce2.emit1(JSOp::InitHiddenElemSetter)) {
10414 // [stack] THIS
10415 return false;
10417 if (!bce2.emitGetPrivateName(name)) {
10418 // [stack] THIS NAME
10419 return false;
10421 if (!bce2.emitAtomOp(
10422 JSOp::GetIntrinsic,
10423 TaggedParserAtomIndex::WellKnown::NoPrivateGetter())) {
10424 // [stack] THIS NAME FUN
10425 return false;
10427 if (!bce2.emit1(JSOp::InitHiddenElemGetter)) {
10428 // [stack] THIS
10429 return false;
10431 break;
10432 case PrivateNameKind::Getter:
10433 case PrivateNameKind::GetterSetter:
10434 if (classMethod->accessorType() == AccessorType::Getter) {
10435 if (!bce2.emit1(JSOp::InitHiddenElemGetter)) {
10436 // [stack] THIS
10437 return false;
10439 } else {
10440 if (!bce2.emit1(JSOp::InitHiddenElemSetter)) {
10441 // [stack] THIS
10442 return false;
10445 break;
10446 default:
10447 MOZ_CRASH("Invalid op");
10450 // Pop remaining THIS.
10451 if (!bce2.emit1(JSOp::Pop)) {
10452 // [stack]
10453 return false;
10456 if (!fse.emitEndBody()) {
10457 // [stack]
10458 return false;
10460 if (!fse.intoStencil()) {
10461 return false;
10464 if (!fe.emitNonLazyEnd()) {
10465 // [stack] HOMEOBJ HERITAGE? ARRAY FUN
10466 // or:
10467 // [stack] CTOR HOMEOBJ ARRAY FUN
10468 return false;
10471 return true;
10474 const MemberInitializers& BytecodeEmitter::findMemberInitializersForCall() {
10475 for (BytecodeEmitter* current = this; current; current = current->parent) {
10476 if (current->sc->isFunctionBox()) {
10477 FunctionBox* funbox = current->sc->asFunctionBox();
10479 if (funbox->isArrow()) {
10480 continue;
10483 // If we found a non-arrow / non-constructor we were never allowed to
10484 // expect fields in the first place.
10485 MOZ_RELEASE_ASSERT(funbox->isClassConstructor());
10487 return funbox->useMemberInitializers() ? funbox->memberInitializers()
10488 : MemberInitializers::Empty();
10492 MOZ_RELEASE_ASSERT(compilationState.scopeContext.memberInitializers);
10493 return *compilationState.scopeContext.memberInitializers;
10496 bool BytecodeEmitter::emitInitializeInstanceMembers(
10497 bool isDerivedClassConstructor) {
10498 const MemberInitializers& memberInitializers =
10499 findMemberInitializersForCall();
10500 MOZ_ASSERT(memberInitializers.valid);
10502 if (memberInitializers.hasPrivateBrand) {
10503 // This is guaranteed to run after super(), so we don't need TDZ checks.
10504 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
10505 // [stack] THIS
10506 return false;
10508 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_privateBrand_())) {
10509 // [stack] THIS BRAND
10510 return false;
10512 if (isDerivedClassConstructor) {
10513 if (!emitCheckPrivateField(ThrowCondition::ThrowHas,
10514 ThrowMsgKind::PrivateBrandDoubleInit)) {
10515 // [stack] THIS BRAND BOOL
10516 return false;
10518 if (!emit1(JSOp::Pop)) {
10519 // [stack] THIS BRAND
10520 return false;
10523 if (!emit1(JSOp::Null)) {
10524 // [stack] THIS BRAND NULL
10525 return false;
10527 if (!emit1(JSOp::InitHiddenElem)) {
10528 // [stack] THIS
10529 return false;
10531 if (!emit1(JSOp::Pop)) {
10532 // [stack]
10533 return false;
10537 size_t numInitializers = memberInitializers.numMemberInitializers;
10538 if (numInitializers > 0) {
10539 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) {
10540 // [stack] ARRAY
10541 return false;
10544 for (size_t index = 0; index < numInitializers; index++) {
10545 if (index < numInitializers - 1) {
10546 // We Dup to keep the array around (it is consumed in the bytecode
10547 // below) for next iterations of this loop, except for the last
10548 // iteration, which avoids an extra Pop at the end of the loop.
10549 if (!emit1(JSOp::Dup)) {
10550 // [stack] ARRAY ARRAY
10551 return false;
10555 if (!emitNumberOp(index)) {
10556 // [stack] ARRAY? ARRAY INDEX
10557 return false;
10560 if (!emit1(JSOp::GetElem)) {
10561 // [stack] ARRAY? FUNC
10562 return false;
10565 // This is guaranteed to run after super(), so we don't need TDZ checks.
10566 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
10567 // [stack] ARRAY? FUNC THIS
10568 return false;
10571 // Callee is always internal function.
10572 if (!emitCall(JSOp::CallIgnoresRv, 0)) {
10573 // [stack] ARRAY? RVAL
10574 return false;
10577 if (!emit1(JSOp::Pop)) {
10578 // [stack] ARRAY?
10579 return false;
10582 #ifdef ENABLE_DECORATORS
10583 // Decorators Proposal
10584 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-initializeinstanceelements
10585 // 4. For each element e of elements, do
10586 // 4.a. If elementRecord.[[Kind]] is field or accessor, then
10587 // 4.a.i. Perform ? InitializeFieldOrAccessor(O, elementRecord).
10590 // TODO: (See Bug 1817993) At the moment, we're applying the initialization
10591 // logic in two steps. The pre-decorator initialization code runs, stores
10592 // the initial value, and then we retrieve it here and apply the
10593 // initializers added by decorators. We should unify these two steps.
10594 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) {
10595 // [stack] ARRAY
10596 return false;
10599 if (!emit1(JSOp::Dup)) {
10600 // [stack] ARRAY ARRAY
10601 return false;
10604 if (!emitAtomOp(JSOp::GetProp,
10605 TaggedParserAtomIndex::WellKnown::length())) {
10606 // [stack] ARRAY LENGTH
10607 return false;
10610 if (!emitNumberOp(static_cast<double>(numInitializers))) {
10611 // [stack] ARRAY LENGTH INDEX
10612 return false;
10615 InternalWhileEmitter wh(this);
10616 // At this point, we have no context to determine offsets in the
10617 // code for this while statement. Ideally, it would correspond to
10618 // the field we're initializing.
10619 if (!wh.emitCond()) {
10620 // [stack] ARRAY LENGTH INDEX
10621 return false;
10624 if (!emit1(JSOp::Dup)) {
10625 // [stack] ARRAY LENGTH INDEX INDEX
10626 return false;
10629 if (!emitDupAt(2)) {
10630 // [stack] ARRAY LENGTH INDEX INDEX LENGTH
10631 return false;
10634 if (!emit1(JSOp::Lt)) {
10635 // [stack] ARRAY LENGTH INDEX BOOL
10636 return false;
10639 if (!wh.emitBody()) {
10640 // [stack] ARRAY LENGTH INDEX
10641 return false;
10644 if (!emitDupAt(2)) {
10645 // [stack] ARRAY LENGTH INDEX ARRAY
10646 return false;
10649 if (!emitDupAt(1)) {
10650 // [stack] ARRAY LENGTH INDEX ARRAY INDEX
10651 return false;
10654 // Retrieve initializers for this field
10655 if (!emit1(JSOp::GetElem)) {
10656 // [stack] ARRAY LENGTH INDEX INITIALIZERS
10657 return false;
10660 // This is guaranteed to run after super(), so we don't need TDZ checks.
10661 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
10662 // [stack] ARRAY LENGTH INDEX INITIALIZERS THIS
10663 return false;
10666 if (!emit1(JSOp::Swap)) {
10667 // [stack] ARRAY LENGTH INDEX THIS INITIALIZERS
10668 return false;
10671 DecoratorEmitter de(this);
10672 if (!de.emitInitializeFieldOrAccessor()) {
10673 // [stack] ARRAY LENGTH INDEX
10674 return false;
10677 if (!emit1(JSOp::Inc)) {
10678 // [stack] ARRAY LENGTH INDEX
10679 return false;
10682 if (!wh.emitEnd()) {
10683 // [stack] ARRAY LENGTH INDEX
10684 return false;
10687 if (!emitPopN(3)) {
10688 // [stack]
10689 return false;
10691 // 5. Return unused.
10692 #endif
10694 return true;
10697 bool BytecodeEmitter::emitInitializeStaticFields(ListNode* classMembers) {
10698 auto isStaticField = [](ParseNode* propdef) {
10699 return HasInitializer(propdef, true);
10701 size_t numFields =
10702 std::count_if(classMembers->contents().begin(),
10703 classMembers->contents().end(), isStaticField);
10705 if (numFields == 0) {
10706 return true;
10709 if (!emitGetName(
10710 TaggedParserAtomIndex::WellKnown::dot_staticInitializers_())) {
10711 // [stack] CTOR ARRAY
10712 return false;
10715 for (size_t fieldIndex = 0; fieldIndex < numFields; fieldIndex++) {
10716 bool hasNext = fieldIndex < numFields - 1;
10717 if (hasNext) {
10718 // We Dup to keep the array around (it is consumed in the bytecode below)
10719 // for next iterations of this loop, except for the last iteration, which
10720 // avoids an extra Pop at the end of the loop.
10721 if (!emit1(JSOp::Dup)) {
10722 // [stack] CTOR ARRAY ARRAY
10723 return false;
10727 if (!emitNumberOp(fieldIndex)) {
10728 // [stack] CTOR ARRAY? ARRAY INDEX
10729 return false;
10732 if (!emit1(JSOp::GetElem)) {
10733 // [stack] CTOR ARRAY? FUNC
10734 return false;
10737 if (!emitDupAt(1 + hasNext)) {
10738 // [stack] CTOR ARRAY? FUNC CTOR
10739 return false;
10742 // Callee is always internal function.
10743 if (!emitCall(JSOp::CallIgnoresRv, 0)) {
10744 // [stack] CTOR ARRAY? RVAL
10745 return false;
10748 if (!emit1(JSOp::Pop)) {
10749 // [stack] CTOR ARRAY?
10750 return false;
10754 #ifdef ENABLE_DECORATORS
10755 // Decorators Proposal
10756 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-initializeinstanceelements
10757 // 4. For each element e of elements, do
10758 // 4.a. If elementRecord.[[Kind]] is field or accessor, then
10759 // 4.a.i. Perform ? InitializeFieldOrAccessor(O, elementRecord).
10762 // TODO: (See Bug 1817993) At the moment, we're applying the initialization
10763 // logic in two steps. The pre-decorator initialization code runs, stores
10764 // the initial value, and then we retrieve it here and apply the
10765 // initializers added by decorators. We should unify these two steps.
10766 if (!emitGetName(
10767 TaggedParserAtomIndex::WellKnown::dot_staticInitializers_())) {
10768 // [stack] CTOR ARRAY
10769 return false;
10772 if (!emit1(JSOp::Dup)) {
10773 // [stack] CTOR ARRAY ARRAY
10774 return false;
10777 if (!emitAtomOp(JSOp::GetProp, TaggedParserAtomIndex::WellKnown::length())) {
10778 // [stack] CTOR ARRAY LENGTH
10779 return false;
10782 if (!emitNumberOp(static_cast<double>(numFields))) {
10783 // [stack] CTOR ARRAY LENGTH INDEX
10784 return false;
10787 InternalWhileEmitter wh(this);
10788 // At this point, we have no context to determine offsets in the
10789 // code for this while statement. Ideally, it would correspond to
10790 // the field we're initializing.
10791 if (!wh.emitCond()) {
10792 // [stack] CTOR ARRAY LENGTH INDEX
10793 return false;
10796 if (!emit1(JSOp::Dup)) {
10797 // [stack] CTOR ARRAY LENGTH INDEX INDEX
10798 return false;
10801 if (!emitDupAt(2)) {
10802 // [stack] CTOR ARRAY LENGTH INDEX INDEX LENGTH
10803 return false;
10806 if (!emit1(JSOp::Lt)) {
10807 // [stack] CTOR ARRAY LENGTH INDEX BOOL
10808 return false;
10811 if (!wh.emitBody()) {
10812 // [stack] CTOR ARRAY LENGTH INDEX
10813 return false;
10816 if (!emitDupAt(2)) {
10817 // [stack] CTOR ARRAY LENGTH INDEX ARRAY
10818 return false;
10821 if (!emitDupAt(1)) {
10822 // [stack] CTOR ARRAY LENGTH INDEX ARRAY INDEX
10823 return false;
10826 // Retrieve initializers for this field
10827 if (!emit1(JSOp::GetElem)) {
10828 // [stack] CTOR ARRAY LENGTH INDEX INITIALIZERS
10829 return false;
10832 if (!emitDupAt(4)) {
10833 // [stack] CTOR ARRAY LENGTH INDEX INITIALIZERS CTOR
10834 return false;
10837 if (!emit1(JSOp::Swap)) {
10838 // [stack] CTOR ARRAY LENGTH INDEX CTOR INITIALIZERS
10839 return false;
10842 DecoratorEmitter de(this);
10843 if (!de.emitInitializeFieldOrAccessor()) {
10844 // [stack] CTOR ARRAY LENGTH INDEX
10845 return false;
10848 if (!emit1(JSOp::Inc)) {
10849 // [stack] CTOR ARRAY LENGTH INDEX
10850 return false;
10853 if (!wh.emitEnd()) {
10854 // [stack] CTOR ARRAY LENGTH INDEX
10855 return false;
10858 if (!emitPopN(3)) {
10859 // [stack] CTOR
10860 return false;
10862 // 5. Return unused.
10863 #endif
10865 // Overwrite |.staticInitializers| and |.staticFieldKeys| with undefined to
10866 // avoid keeping the arrays alive indefinitely.
10867 auto clearStaticFieldSlot = [&](TaggedParserAtomIndex name) {
10868 NameOpEmitter noe(this, name, NameOpEmitter::Kind::SimpleAssignment);
10869 if (!noe.prepareForRhs()) {
10870 // [stack] ENV? VAL?
10871 return false;
10874 if (!emit1(JSOp::Undefined)) {
10875 // [stack] ENV? VAL? UNDEFINED
10876 return false;
10879 if (!noe.emitAssignment()) {
10880 // [stack] VAL
10881 return false;
10884 if (!emit1(JSOp::Pop)) {
10885 // [stack]
10886 return false;
10889 return true;
10892 if (!clearStaticFieldSlot(
10893 TaggedParserAtomIndex::WellKnown::dot_staticInitializers_())) {
10894 return false;
10897 auto isStaticFieldWithComputedName = [](ParseNode* propdef) {
10898 return propdef->is<ClassField>() && propdef->as<ClassField>().isStatic() &&
10899 propdef->as<ClassField>().name().getKind() ==
10900 ParseNodeKind::ComputedName;
10903 if (std::any_of(classMembers->contents().begin(),
10904 classMembers->contents().end(),
10905 isStaticFieldWithComputedName)) {
10906 if (!clearStaticFieldSlot(
10907 TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_())) {
10908 return false;
10912 return true;
10915 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
10916 // the comment on emitSwitch.
10917 MOZ_NEVER_INLINE bool BytecodeEmitter::emitObject(ListNode* objNode) {
10918 // Note: this method uses the ObjLiteralWriter and emits ObjLiteralStencil
10919 // objects into the GCThingList, which will evaluate them into real GC objects
10920 // or shapes during JSScript::fullyInitFromEmitter. Eventually we want
10921 // JSOp::Object to be a real opcode, but for now, performance constraints
10922 // limit us to evaluating object literals at the end of parse, when we're
10923 // allowed to allocate GC things.
10925 // There are four cases here, in descending order of preference:
10927 // 1. The list of property names is "normal" and constant (no computed
10928 // values, no integer indices), the values are all simple constants
10929 // (numbers, booleans, strings), *and* this occurs in a run-once
10930 // (singleton) context. In this case, we can emit ObjLiteral
10931 // instructions to build an object with values, and the object will be
10932 // attached to a JSOp::Object opcode, whose semantics are for the backend
10933 // to simply steal the object from the script.
10935 // 2. The list of property names is "normal" and constant as above, *and* this
10936 // occurs in a run-once (singleton) context, but some values are complex
10937 // (computed expressions, sub-objects, functions, etc.). In this case, we
10938 // can still use JSOp::Object (because singleton context), but the object
10939 // has |undefined| property values and InitProp ops are emitted to set the
10940 // values.
10942 // 3. The list of property names is "normal" and constant as above, but this
10943 // occurs in a non-run-once (non-singleton) context. In this case, we can
10944 // use the ObjLiteral functionality to describe an *empty* object (all
10945 // values left undefined) with the right fields, which will become a
10946 // JSOp::NewObject opcode using the object's shape to speed up the creation
10947 // of the object each time it executes. The emitted bytecode still needs
10948 // InitProp ops to set the values in this case.
10950 // 4. Any other case. As a fallback, we use NewInit to create a new, empty
10951 // object (i.e., `{}`) and then emit bytecode to initialize its properties
10952 // one-by-one.
10954 bool useObjLiteral = false;
10955 bool useObjLiteralValues = false;
10956 isPropertyListObjLiteralCompatible(objNode, &useObjLiteralValues,
10957 &useObjLiteral);
10959 // [stack]
10961 ObjectEmitter oe(this);
10962 if (useObjLiteral) {
10963 bool singleton = checkSingletonContext() &&
10964 !objNode->hasNonConstInitializer() && objNode->head();
10965 JSOp op;
10966 if (singleton) {
10967 // Case 1 or 2.
10968 op = JSOp::Object;
10969 } else {
10970 // Case 3.
10971 useObjLiteralValues = false;
10972 op = JSOp::NewObject;
10975 // Use an ObjLiteral op. This will record ObjLiteral insns in the
10976 // objLiteralWriter's buffer and add a fixup to the list of ObjLiteral
10977 // fixups so that at GC-publish time at the end of parse, the full object
10978 // (case 1 or 2) or shape (case 3) can be allocated and the bytecode can be
10979 // patched to refer to it.
10980 if (!emitPropertyListObjLiteral(objNode, op, useObjLiteralValues)) {
10981 // [stack] OBJ
10982 return false;
10984 // Put the ObjectEmitter in the right state. This tells it that there will
10985 // already be an object on the stack as a result of the (eventual)
10986 // NewObject or Object op, and prepares it to emit values if needed.
10987 if (!oe.emitObjectWithTemplateOnStack()) {
10988 // [stack] OBJ
10989 return false;
10991 if (!useObjLiteralValues) {
10992 // Case 2 or 3 above: we still need to emit bytecode to fill in the
10993 // object's property values.
10994 if (!emitPropertyList(objNode, oe, ObjectLiteral)) {
10995 // [stack] OBJ
10996 return false;
10999 } else {
11000 // Case 4 above: no ObjLiteral use, just bytecode to build the object from
11001 // scratch.
11002 if (!oe.emitObject(objNode->count())) {
11003 // [stack] OBJ
11004 return false;
11006 if (!emitPropertyList(objNode, oe, ObjectLiteral)) {
11007 // [stack] OBJ
11008 return false;
11012 if (!oe.emitEnd()) {
11013 // [stack] OBJ
11014 return false;
11017 return true;
11020 bool BytecodeEmitter::emitArrayLiteral(ListNode* array) {
11021 // Emit JSOp::Object if the array consists entirely of primitive values and we
11022 // are in a singleton context.
11023 if (checkSingletonContext() && !array->hasNonConstInitializer() &&
11024 !array->empty() && isArrayObjLiteralCompatible(array)) {
11025 return emitObjLiteralArray(array);
11028 return emitArray(array);
11031 bool BytecodeEmitter::emitArray(ListNode* array) {
11033 * Emit code for [a, b, c] that is equivalent to constructing a new
11034 * array and in source order evaluating each element value and adding
11035 * it to the array, without invoking latent setters. We use the
11036 * JSOp::NewInit and JSOp::InitElemArray bytecodes to ignore setters and
11037 * to avoid dup'ing and popping the array as each element is added, as
11038 * JSOp::SetElem/JSOp::SetProp would do.
11041 uint32_t nspread = 0;
11042 for (ParseNode* elem : array->contents()) {
11043 if (elem->isKind(ParseNodeKind::Spread)) {
11044 nspread++;
11048 // Array literal's length is limited to NELEMENTS_LIMIT in parser.
11049 static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT <= INT32_MAX,
11050 "array literals' maximum length must not exceed limits "
11051 "required by BaselineCompiler::emit_NewArray, "
11052 "BaselineCompiler::emit_InitElemArray, "
11053 "and DoSetElemFallback's handling of JSOp::InitElemArray");
11055 uint32_t count = array->count();
11056 MOZ_ASSERT(count >= nspread);
11057 MOZ_ASSERT(count <= NativeObject::MAX_DENSE_ELEMENTS_COUNT,
11058 "the parser must throw an error if the array exceeds maximum "
11059 "length");
11061 // For arrays with spread, this is a very pessimistic allocation, the
11062 // minimum possible final size.
11063 if (!emitUint32Operand(JSOp::NewArray, count - nspread)) {
11064 // [stack] ARRAY
11065 return false;
11068 uint32_t index = 0;
11069 bool afterSpread = false;
11070 for (ParseNode* elem : array->contents()) {
11071 if (elem->isKind(ParseNodeKind::Spread)) {
11072 if (!afterSpread) {
11073 afterSpread = true;
11074 if (!emitNumberOp(index)) {
11075 // [stack] ARRAY INDEX
11076 return false;
11080 ParseNode* expr = elem->as<UnaryNode>().kid();
11081 SelfHostedIter selfHostedIter = getSelfHostedIterFor(expr);
11083 if (!updateSourceCoordNotes(elem->pn_pos.begin)) {
11084 return false;
11086 if (!emitIterable(expr, selfHostedIter)) {
11087 // [stack] ARRAY INDEX ITERABLE
11088 return false;
11090 if (!emitIterator(selfHostedIter)) {
11091 // [stack] ARRAY INDEX NEXT ITER
11092 return false;
11094 if (!emit2(JSOp::Pick, 3)) {
11095 // [stack] INDEX NEXT ITER ARRAY
11096 return false;
11098 if (!emit2(JSOp::Pick, 3)) {
11099 // [stack] NEXT ITER ARRAY INDEX
11100 return false;
11102 if (!emitSpread(selfHostedIter)) {
11103 // [stack] ARRAY INDEX
11104 return false;
11106 } else {
11107 if (!updateSourceCoordNotesIfNonLiteral(elem)) {
11108 return false;
11110 if (elem->isKind(ParseNodeKind::Elision)) {
11111 if (!emit1(JSOp::Hole)) {
11112 return false;
11114 } else {
11115 if (!emitTree(elem, ValueUsage::WantValue)) {
11116 // [stack] ARRAY INDEX? VALUE
11117 return false;
11121 if (afterSpread) {
11122 if (!emit1(JSOp::InitElemInc)) {
11123 // [stack] ARRAY (INDEX+1)
11124 return false;
11126 } else {
11127 if (!emitUint32Operand(JSOp::InitElemArray, index)) {
11128 // [stack] ARRAY
11129 return false;
11134 index++;
11136 MOZ_ASSERT(index == count);
11137 if (afterSpread) {
11138 if (!emit1(JSOp::Pop)) {
11139 // [stack] ARRAY
11140 return false;
11143 return true;
11146 bool BytecodeEmitter::emitSpreadIntoArray(UnaryNode* elem) {
11147 MOZ_ASSERT(elem->isKind(ParseNodeKind::Spread));
11149 if (!updateSourceCoordNotes(elem->pn_pos.begin)) {
11150 // [stack] VALUE
11151 return false;
11154 SelfHostedIter selfHostedIter = getSelfHostedIterFor(elem->kid());
11155 MOZ_ASSERT(selfHostedIter == SelfHostedIter::Deny ||
11156 selfHostedIter == SelfHostedIter::AllowContent);
11158 if (!emitIterator(selfHostedIter)) {
11159 // [stack] NEXT ITER
11160 return false;
11163 if (!emitUint32Operand(JSOp::NewArray, 0)) {
11164 // [stack] NEXT ITER ARRAY
11165 return false;
11168 if (!emitNumberOp(0)) {
11169 // [stack] NEXT ITER ARRAY INDEX
11170 return false;
11173 if (!emitSpread(selfHostedIter)) {
11174 // [stack] ARRAY INDEX
11175 return false;
11178 if (!emit1(JSOp::Pop)) {
11179 // [stack] ARRAY
11180 return false;
11182 return true;
11185 #ifdef ENABLE_RECORD_TUPLE
11186 bool BytecodeEmitter::emitRecordLiteral(ListNode* record) {
11187 if (!emitUint32Operand(JSOp::InitRecord, record->count())) {
11188 // [stack] RECORD
11189 return false;
11192 for (ParseNode* propdef : record->contents()) {
11193 if (propdef->isKind(ParseNodeKind::Spread)) {
11194 if (!emitTree(propdef->as<UnaryNode>().kid())) {
11195 // [stack] RECORD SPREADEE
11196 return false;
11198 if (!emit1(JSOp::AddRecordSpread)) {
11199 // [stack] RECORD
11200 return false;
11202 } else {
11203 BinaryNode* prop = &propdef->as<BinaryNode>();
11205 ParseNode* key = prop->left();
11206 ParseNode* value = prop->right();
11208 switch (key->getKind()) {
11209 case ParseNodeKind::ObjectPropertyName:
11210 if (!emitStringOp(JSOp::String, key->as<NameNode>().atom())) {
11211 return false;
11213 break;
11214 case ParseNodeKind::ComputedName:
11215 if (!emitTree(key->as<UnaryNode>().kid())) {
11216 return false;
11218 break;
11219 default:
11220 MOZ_ASSERT(key->isKind(ParseNodeKind::StringExpr) ||
11221 key->isKind(ParseNodeKind::NumberExpr) ||
11222 key->isKind(ParseNodeKind::BigIntExpr));
11223 if (!emitTree(key)) {
11224 return false;
11226 break;
11228 // [stack] RECORD KEY
11230 if (!emitTree(value)) {
11231 // [stack] RECORD KEY VALUE
11232 return false;
11235 if (!emit1(JSOp::AddRecordProperty)) {
11236 // [stack] RECORD
11237 return false;
11242 if (!emit1(JSOp::FinishRecord)) {
11243 // [stack] RECORD
11244 return false;
11247 return true;
11250 bool BytecodeEmitter::emitTupleLiteral(ListNode* tuple) {
11251 if (!emitUint32Operand(JSOp::InitTuple, tuple->count())) {
11252 // [stack] TUPLE
11253 return false;
11256 for (ParseNode* elt : tuple->contents()) {
11257 if (elt->isKind(ParseNodeKind::Spread)) {
11258 ParseNode* expr = elt->as<UnaryNode>().kid();
11259 auto selfHostedIter = getSelfHostedIterFor(expr);
11261 if (!emitIterable(expr, selfHostedIter)) {
11262 // [stack] TUPLE ITERABLE
11263 return false;
11265 if (!emitIterator(selfHostedIter)) {
11266 // [stack] TUPLE NEXT ITER
11267 return false;
11269 if (!emit2(JSOp::Pick, 2)) {
11270 // [stack] NEXT ITER TUPLE
11271 return false;
11273 if (!emitSpread(selfHostedIter, /* spreadeeStackItems = */ 1,
11274 JSOp::AddTupleElement)) {
11275 // [stack] TUPLE
11276 return false;
11278 } else {
11279 // Update location to throw errors about non-primitive elements
11280 // in the correct position.
11281 if (!updateSourceCoordNotesIfNonLiteral(elt)) {
11282 return false;
11285 if (!emitTree(elt)) {
11286 // [stack] TUPLE VALUE
11287 return false;
11290 if (!emit1(JSOp::AddTupleElement)) {
11291 // [stack] TUPLE
11292 return false;
11297 if (!emit1(JSOp::FinishTuple)) {
11298 // [stack] TUPLE
11299 return false;
11302 return true;
11304 #endif
11306 static inline JSOp UnaryOpParseNodeKindToJSOp(ParseNodeKind pnk) {
11307 switch (pnk) {
11308 case ParseNodeKind::ThrowStmt:
11309 return JSOp::Throw;
11310 case ParseNodeKind::VoidExpr:
11311 return JSOp::Void;
11312 case ParseNodeKind::NotExpr:
11313 return JSOp::Not;
11314 case ParseNodeKind::BitNotExpr:
11315 return JSOp::BitNot;
11316 case ParseNodeKind::PosExpr:
11317 return JSOp::Pos;
11318 case ParseNodeKind::NegExpr:
11319 return JSOp::Neg;
11320 default:
11321 MOZ_CRASH("unexpected unary op");
11325 bool BytecodeEmitter::emitUnary(UnaryNode* unaryNode) {
11326 if (!updateSourceCoordNotes(unaryNode->pn_pos.begin)) {
11327 return false;
11330 JSOp op = UnaryOpParseNodeKindToJSOp(unaryNode->getKind());
11331 ValueUsage valueUsage =
11332 op == JSOp::Void ? ValueUsage::IgnoreValue : ValueUsage::WantValue;
11333 if (!emitTree(unaryNode->kid(), valueUsage)) {
11334 return false;
11336 return emit1(op);
11339 bool BytecodeEmitter::emitTypeof(UnaryNode* typeofNode, JSOp op) {
11340 MOZ_ASSERT(op == JSOp::Typeof || op == JSOp::TypeofExpr);
11342 if (!updateSourceCoordNotes(typeofNode->pn_pos.begin)) {
11343 return false;
11346 if (!emitTree(typeofNode->kid())) {
11347 return false;
11350 return emit1(op);
11353 bool BytecodeEmitter::emitFunctionFormalParameters(ParamsBodyNode* paramsBody) {
11354 FunctionBox* funbox = sc->asFunctionBox();
11356 bool hasRest = funbox->hasRest();
11358 FunctionParamsEmitter fpe(this, funbox);
11359 for (ParseNode* arg : paramsBody->parameters()) {
11360 ParseNode* bindingElement = arg;
11361 ParseNode* initializer = nullptr;
11362 if (arg->isKind(ParseNodeKind::AssignExpr)) {
11363 bindingElement = arg->as<BinaryNode>().left();
11364 initializer = arg->as<BinaryNode>().right();
11366 bool hasInitializer = !!initializer;
11367 bool isRest =
11368 hasRest && arg->pn_next == *std::end(paramsBody->parameters());
11369 bool isDestructuring = !bindingElement->isKind(ParseNodeKind::Name);
11371 // Left-hand sides are either simple names or destructuring patterns.
11372 MOZ_ASSERT(bindingElement->isKind(ParseNodeKind::Name) ||
11373 bindingElement->isKind(ParseNodeKind::ArrayExpr) ||
11374 bindingElement->isKind(ParseNodeKind::ObjectExpr));
11376 auto emitDefaultInitializer = [this, &initializer, &bindingElement]() {
11377 // [stack]
11379 if (!this->emitInitializer(initializer, bindingElement)) {
11380 // [stack] DEFAULT
11381 return false;
11383 return true;
11386 auto emitDestructuring = [this, &bindingElement]() {
11387 // [stack] ARG
11389 if (!this->emitDestructuringOps(&bindingElement->as<ListNode>(),
11390 DestructuringFlavor::Declaration)) {
11391 // [stack] ARG
11392 return false;
11395 return true;
11398 if (isRest) {
11399 if (isDestructuring) {
11400 if (!fpe.prepareForDestructuringRest()) {
11401 // [stack]
11402 return false;
11404 if (!emitDestructuring()) {
11405 // [stack]
11406 return false;
11408 if (!fpe.emitDestructuringRestEnd()) {
11409 // [stack]
11410 return false;
11412 } else {
11413 auto paramName = bindingElement->as<NameNode>().name();
11414 if (!fpe.emitRest(paramName)) {
11415 // [stack]
11416 return false;
11420 continue;
11423 if (isDestructuring) {
11424 if (hasInitializer) {
11425 if (!fpe.prepareForDestructuringDefaultInitializer()) {
11426 // [stack]
11427 return false;
11429 if (!emitDefaultInitializer()) {
11430 // [stack]
11431 return false;
11433 if (!fpe.prepareForDestructuringDefault()) {
11434 // [stack]
11435 return false;
11437 if (!emitDestructuring()) {
11438 // [stack]
11439 return false;
11441 if (!fpe.emitDestructuringDefaultEnd()) {
11442 // [stack]
11443 return false;
11445 } else {
11446 if (!fpe.prepareForDestructuring()) {
11447 // [stack]
11448 return false;
11450 if (!emitDestructuring()) {
11451 // [stack]
11452 return false;
11454 if (!fpe.emitDestructuringEnd()) {
11455 // [stack]
11456 return false;
11460 continue;
11463 if (hasInitializer) {
11464 if (!fpe.prepareForDefault()) {
11465 // [stack]
11466 return false;
11468 if (!emitDefaultInitializer()) {
11469 // [stack]
11470 return false;
11472 auto paramName = bindingElement->as<NameNode>().name();
11473 if (!fpe.emitDefaultEnd(paramName)) {
11474 // [stack]
11475 return false;
11478 continue;
11481 auto paramName = bindingElement->as<NameNode>().name();
11482 if (!fpe.emitSimple(paramName)) {
11483 // [stack]
11484 return false;
11488 return true;
11491 bool BytecodeEmitter::emitInitializeFunctionSpecialNames() {
11492 FunctionBox* funbox = sc->asFunctionBox();
11494 // [stack]
11496 auto emitInitializeFunctionSpecialName =
11497 [](BytecodeEmitter* bce, TaggedParserAtomIndex name, JSOp op) {
11498 // A special name must be slotful, either on the frame or on the
11499 // call environment.
11500 MOZ_ASSERT(bce->lookupName(name).hasKnownSlot());
11502 NameOpEmitter noe(bce, name, NameOpEmitter::Kind::Initialize);
11503 if (!noe.prepareForRhs()) {
11504 // [stack]
11505 return false;
11507 if (!bce->emit1(op)) {
11508 // [stack] THIS/ARGUMENTS/NEW.TARGET
11509 return false;
11511 if (!noe.emitAssignment()) {
11512 // [stack] THIS/ARGUMENTS/NEW.TARGET
11513 return false;
11515 if (!bce->emit1(JSOp::Pop)) {
11516 // [stack]
11517 return false;
11520 return true;
11523 // Do nothing if the function doesn't have an arguments binding.
11524 if (funbox->needsArgsObj()) {
11525 // Self-hosted code should use the more efficient ArgumentsLength and
11526 // GetArgument intrinsics instead of `arguments`.
11527 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
11528 if (!emitInitializeFunctionSpecialName(
11529 this, TaggedParserAtomIndex::WellKnown::arguments(),
11530 JSOp::Arguments)) {
11531 // [stack]
11532 return false;
11536 // Do nothing if the function doesn't have a this-binding (this
11537 // happens for instance if it doesn't use this/eval or if it's an
11538 // arrow function).
11539 if (funbox->functionHasThisBinding()) {
11540 if (!emitInitializeFunctionSpecialName(
11541 this, TaggedParserAtomIndex::WellKnown::dot_this_(),
11542 JSOp::FunctionThis)) {
11543 return false;
11547 // Do nothing if the function doesn't have a new.target-binding (this happens
11548 // for instance if it doesn't use new.target/eval or if it's an arrow
11549 // function).
11550 if (funbox->functionHasNewTargetBinding()) {
11551 if (!emitInitializeFunctionSpecialName(
11552 this, TaggedParserAtomIndex::WellKnown::dot_newTarget_(),
11553 JSOp::NewTarget)) {
11554 return false;
11558 // Do nothing if the function doesn't implicitly return a promise result.
11559 if (funbox->needsPromiseResult()) {
11560 if (!emitInitializeFunctionSpecialName(
11561 this, TaggedParserAtomIndex::WellKnown::dot_generator_(),
11562 JSOp::Generator)) {
11563 // [stack]
11564 return false;
11567 return true;
11570 bool BytecodeEmitter::emitLexicalInitialization(NameNode* name) {
11571 return emitLexicalInitialization(name->name());
11574 bool BytecodeEmitter::emitLexicalInitialization(TaggedParserAtomIndex name) {
11575 NameOpEmitter noe(this, name, NameOpEmitter::Kind::Initialize);
11576 if (!noe.prepareForRhs()) {
11577 return false;
11580 // The caller has pushed the RHS to the top of the stack. Assert that the
11581 // binding can be initialized without a binding object on the stack, and that
11582 // no JSOp::BindName or JSOp::BindGName ops were emitted.
11583 MOZ_ASSERT(noe.loc().isLexical() || noe.loc().isSynthetic() ||
11584 noe.loc().isPrivateMethod());
11585 MOZ_ASSERT(!noe.emittedBindOp());
11587 if (!noe.emitAssignment()) {
11588 return false;
11591 return true;
11594 static MOZ_ALWAYS_INLINE ParseNode* FindConstructor(ListNode* classMethods) {
11595 for (ParseNode* classElement : classMethods->contents()) {
11596 ParseNode* unwrappedElement = classElement;
11597 if (unwrappedElement->is<LexicalScopeNode>()) {
11598 unwrappedElement = unwrappedElement->as<LexicalScopeNode>().scopeBody();
11600 if (unwrappedElement->is<ClassMethod>()) {
11601 ClassMethod& method = unwrappedElement->as<ClassMethod>();
11602 ParseNode& methodName = method.name();
11603 if (!method.isStatic() &&
11604 (methodName.isKind(ParseNodeKind::ObjectPropertyName) ||
11605 methodName.isKind(ParseNodeKind::StringExpr)) &&
11606 methodName.as<NameNode>().atom() ==
11607 TaggedParserAtomIndex::WellKnown::constructor()) {
11608 return classElement;
11612 return nullptr;
11615 bool BytecodeEmitter::emitNewPrivateName(TaggedParserAtomIndex bindingName,
11616 TaggedParserAtomIndex symbolName) {
11617 if (!emitAtomOp(JSOp::NewPrivateName, symbolName)) {
11618 // [stack] HERITAGE PRIVATENAME
11619 return false;
11622 // Add a binding for #name => privatename
11623 if (!emitLexicalInitialization(bindingName)) {
11624 // [stack] HERITAGE PRIVATENAME
11625 return false;
11628 // Pop Private name off the stack.
11629 if (!emit1(JSOp::Pop)) {
11630 // [stack] HERITAGE
11631 return false;
11634 return true;
11637 bool BytecodeEmitter::emitNewPrivateNames(
11638 TaggedParserAtomIndex privateBrandName, ListNode* classMembers) {
11639 bool hasPrivateBrand = false;
11641 for (ParseNode* classElement : classMembers->contents()) {
11642 ParseNode* elementName;
11643 if (classElement->is<ClassMethod>()) {
11644 elementName = &classElement->as<ClassMethod>().name();
11645 } else if (classElement->is<ClassField>()) {
11646 elementName = &classElement->as<ClassField>().name();
11647 } else {
11648 continue;
11651 if (!elementName->isKind(ParseNodeKind::PrivateName)) {
11652 continue;
11655 // Non-static private methods' private names are optimized away.
11656 bool isOptimized = false;
11657 if (classElement->is<ClassMethod>() &&
11658 !classElement->as<ClassMethod>().isStatic()) {
11659 hasPrivateBrand = true;
11660 if (classElement->as<ClassMethod>().accessorType() ==
11661 AccessorType::None) {
11662 isOptimized = true;
11666 if (!isOptimized) {
11667 auto privateName = elementName->as<NameNode>().name();
11668 if (!emitNewPrivateName(privateName, privateName)) {
11669 return false;
11674 if (hasPrivateBrand) {
11675 // We don't make a private name for every optimized method, but we need one
11676 // private name per class, the `.privateBrand`.
11677 if (!emitNewPrivateName(
11678 TaggedParserAtomIndex::WellKnown::dot_privateBrand_(),
11679 privateBrandName)) {
11680 return false;
11683 return true;
11686 // This follows ES6 14.5.14 (ClassDefinitionEvaluation) and ES6 14.5.15
11687 // (BindingClassDeclarationEvaluation).
11688 bool BytecodeEmitter::emitClass(
11689 ClassNode* classNode,
11690 ClassNameKind nameKind /* = ClassNameKind::BindingName */,
11691 TaggedParserAtomIndex
11692 nameForAnonymousClass /* = TaggedParserAtomIndex::null() */) {
11693 MOZ_ASSERT((nameKind == ClassNameKind::InferredName) ==
11694 bool(nameForAnonymousClass));
11696 ParseNode* heritageExpression = classNode->heritage();
11697 ListNode* classMembers = classNode->memberList();
11698 ParseNode* constructor = FindConstructor(classMembers);
11700 // If |nameKind != ClassNameKind::ComputedName|
11701 // [stack]
11702 // Else
11703 // [stack] NAME
11705 ClassEmitter ce(this);
11706 TaggedParserAtomIndex innerName;
11707 ClassEmitter::Kind kind = ClassEmitter::Kind::Expression;
11708 if (ClassNames* names = classNode->names()) {
11709 MOZ_ASSERT(nameKind == ClassNameKind::BindingName);
11710 innerName = names->innerBinding()->name();
11711 MOZ_ASSERT(innerName);
11713 if (names->outerBinding()) {
11714 MOZ_ASSERT(names->outerBinding()->name());
11715 MOZ_ASSERT(names->outerBinding()->name() == innerName);
11716 kind = ClassEmitter::Kind::Declaration;
11720 if (LexicalScopeNode* scopeBindings = classNode->scopeBindings()) {
11721 if (!ce.emitScope(scopeBindings->scopeBindings())) {
11722 // [stack]
11723 return false;
11727 bool isDerived = !!heritageExpression;
11728 if (isDerived) {
11729 if (!updateSourceCoordNotes(classNode->pn_pos.begin)) {
11730 return false;
11732 if (!markStepBreakpoint()) {
11733 return false;
11735 if (!emitTree(heritageExpression)) {
11736 // [stack] HERITAGE
11737 return false;
11741 // The class body scope holds any private names. Those mustn't be visible in
11742 // the heritage expression and hence the scope must be emitted after the
11743 // heritage expression.
11744 if (ClassBodyScopeNode* bodyScopeBindings = classNode->bodyScopeBindings()) {
11745 if (!ce.emitBodyScope(bodyScopeBindings->scopeBindings())) {
11746 // [stack] HERITAGE
11747 return false;
11750 // The spec does not say anything about private brands being symbols. It's
11751 // an implementation detail. So we can give the special private brand
11752 // symbol any description we want and users won't normally see it. For
11753 // debugging, use the class name.
11754 auto privateBrandName = innerName;
11755 if (!innerName) {
11756 privateBrandName = nameForAnonymousClass
11757 ? nameForAnonymousClass
11758 : TaggedParserAtomIndex::WellKnown::anonymous();
11760 if (!emitNewPrivateNames(privateBrandName, classMembers)) {
11761 return false;
11765 bool hasNameOnStack = nameKind == ClassNameKind::ComputedName;
11766 if (isDerived) {
11767 if (!ce.emitDerivedClass(innerName, nameForAnonymousClass,
11768 hasNameOnStack)) {
11769 // [stack] HERITAGE HOMEOBJ
11770 return false;
11772 } else {
11773 if (!ce.emitClass(innerName, nameForAnonymousClass, hasNameOnStack)) {
11774 // [stack] HOMEOBJ
11775 return false;
11779 // Stack currently has HOMEOBJ followed by optional HERITAGE. When HERITAGE
11780 // is not used, an implicit value of %FunctionPrototype% is implied.
11782 // See |Parser::classMember(...)| for the reason why |.initializers| is
11783 // created within its own scope.
11784 Maybe<LexicalScopeEmitter> lse;
11785 FunctionNode* ctor;
11786 if (constructor->is<LexicalScopeNode>()) {
11787 LexicalScopeNode* constructorScope = &constructor->as<LexicalScopeNode>();
11789 // The constructor scope should only contain the |.initializers| binding.
11790 MOZ_ASSERT(!constructorScope->isEmptyScope());
11791 MOZ_ASSERT(constructorScope->scopeBindings()->length == 1);
11792 MOZ_ASSERT(GetScopeDataTrailingNames(constructorScope->scopeBindings())[0]
11793 .name() ==
11794 TaggedParserAtomIndex::WellKnown::dot_initializers_());
11796 auto needsInitializer = [](ParseNode* propdef) {
11797 return NeedsFieldInitializer(propdef, false) ||
11798 NeedsAccessorInitializer(propdef, false);
11801 // As an optimization omit the |.initializers| binding when no instance
11802 // fields or private methods are present.
11803 bool needsInitializers =
11804 std::any_of(classMembers->contents().begin(),
11805 classMembers->contents().end(), needsInitializer);
11806 if (needsInitializers) {
11807 lse.emplace(this);
11808 if (!lse->emitScope(ScopeKind::Lexical,
11809 constructorScope->scopeBindings())) {
11810 return false;
11813 // Any class with field initializers will have a constructor
11814 if (!emitCreateMemberInitializers(ce, classMembers,
11815 FieldPlacement::Instance
11816 #ifdef ENABLE_DECORATORS
11818 isDerived
11819 #endif
11820 )) {
11821 return false;
11825 ctor = &constructorScope->scopeBody()->as<ClassMethod>().method();
11826 } else {
11827 // The |.initializers| binding is never emitted when in self-hosting mode.
11828 MOZ_ASSERT(emitterMode == BytecodeEmitter::SelfHosting);
11829 ctor = &constructor->as<ClassMethod>().method();
11832 bool needsHomeObject = ctor->funbox()->needsHomeObject();
11833 // HERITAGE is consumed inside emitFunction.
11834 if (nameKind == ClassNameKind::InferredName) {
11835 if (!setFunName(ctor->funbox(), nameForAnonymousClass)) {
11836 return false;
11839 if (!emitFunction(ctor, isDerived)) {
11840 // [stack] HOMEOBJ CTOR
11841 return false;
11843 if (lse.isSome()) {
11844 if (!lse->emitEnd()) {
11845 return false;
11847 lse.reset();
11849 if (!ce.emitInitConstructor(needsHomeObject)) {
11850 // [stack] CTOR HOMEOBJ
11851 return false;
11854 if (!emitCreateFieldKeys(classMembers, FieldPlacement::Instance)) {
11855 return false;
11858 if (!emitCreateMemberInitializers(ce, classMembers, FieldPlacement::Static
11859 #ifdef ENABLE_DECORATORS
11861 false
11862 #endif
11863 )) {
11864 return false;
11867 if (!emitCreateFieldKeys(classMembers, FieldPlacement::Static)) {
11868 return false;
11871 if (!emitPropertyList(classMembers, ce, ClassBody)) {
11872 // [stack] CTOR HOMEOBJ
11873 return false;
11876 if (!ce.emitBinding()) {
11877 // [stack] CTOR
11878 return false;
11881 if (!emitInitializeStaticFields(classMembers)) {
11882 // [stack] CTOR
11883 return false;
11886 #if ENABLE_DECORATORS
11887 if (!ce.prepareForDecorators()) {
11888 // [stack] CTOR
11889 return false;
11891 if (classNode->decorators() != nullptr) {
11892 DecoratorEmitter de(this);
11893 NameNode* className =
11894 classNode->names() ? classNode->names()->innerBinding() : nullptr;
11895 if (!de.emitApplyDecoratorsToClassDefinition(className,
11896 classNode->decorators())) {
11897 // [stack] CTOR
11898 return false;
11901 #endif
11903 if (!ce.emitEnd(kind)) {
11904 // [stack] # class declaration
11905 // [stack]
11906 // [stack] # class expression
11907 // [stack] CTOR
11908 return false;
11911 return true;
11914 bool BytecodeEmitter::emitExportDefault(BinaryNode* exportNode) {
11915 MOZ_ASSERT(exportNode->isKind(ParseNodeKind::ExportDefaultStmt));
11917 ParseNode* valueNode = exportNode->left();
11918 if (valueNode->isDirectRHSAnonFunction()) {
11919 MOZ_ASSERT(exportNode->right());
11921 if (!emitAnonymousFunctionWithName(
11922 valueNode, TaggedParserAtomIndex::WellKnown::default_())) {
11923 return false;
11925 } else {
11926 if (!emitTree(valueNode)) {
11927 return false;
11931 if (ParseNode* binding = exportNode->right()) {
11932 if (!emitLexicalInitialization(&binding->as<NameNode>())) {
11933 return false;
11936 if (!emit1(JSOp::Pop)) {
11937 return false;
11941 return true;
11944 bool BytecodeEmitter::emitTree(
11945 ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */,
11946 EmitLineNumberNote emitLineNote /* = EMIT_LINENOTE */) {
11947 AutoCheckRecursionLimit recursion(fc);
11948 if (!recursion.check(fc)) {
11949 return false;
11952 /* Emit notes to tell the current bytecode's source line number.
11953 However, a couple trees require special treatment; see the
11954 relevant emitter functions for details. */
11955 if (emitLineNote == EMIT_LINENOTE &&
11956 !ParseNodeRequiresSpecialLineNumberNotes(pn)) {
11957 if (!updateLineNumberNotes(pn->pn_pos.begin)) {
11958 return false;
11962 switch (pn->getKind()) {
11963 case ParseNodeKind::Function:
11964 if (!emitFunction(&pn->as<FunctionNode>())) {
11965 return false;
11967 break;
11969 case ParseNodeKind::ParamsBody:
11970 MOZ_ASSERT_UNREACHABLE(
11971 "ParamsBody should be handled in emitFunctionScript.");
11972 break;
11974 case ParseNodeKind::IfStmt:
11975 if (!emitIf(&pn->as<TernaryNode>())) {
11976 return false;
11978 break;
11980 case ParseNodeKind::SwitchStmt:
11981 if (!emitSwitch(&pn->as<SwitchStatement>())) {
11982 return false;
11984 break;
11986 case ParseNodeKind::WhileStmt:
11987 if (!emitWhile(&pn->as<BinaryNode>())) {
11988 return false;
11990 break;
11992 case ParseNodeKind::DoWhileStmt:
11993 if (!emitDo(&pn->as<BinaryNode>())) {
11994 return false;
11996 break;
11998 case ParseNodeKind::ForStmt:
11999 if (!emitFor(&pn->as<ForNode>())) {
12000 return false;
12002 break;
12004 case ParseNodeKind::BreakStmt:
12005 // Ensure that the column of the 'break' is set properly.
12006 if (!updateSourceCoordNotes(pn->pn_pos.begin)) {
12007 return false;
12009 if (!markStepBreakpoint()) {
12010 return false;
12013 if (!emitBreak(pn->as<BreakStatement>().label())) {
12014 return false;
12016 break;
12018 case ParseNodeKind::ContinueStmt:
12019 // Ensure that the column of the 'continue' is set properly.
12020 if (!updateSourceCoordNotes(pn->pn_pos.begin)) {
12021 return false;
12023 if (!markStepBreakpoint()) {
12024 return false;
12027 if (!emitContinue(pn->as<ContinueStatement>().label())) {
12028 return false;
12030 break;
12032 case ParseNodeKind::WithStmt:
12033 if (!emitWith(&pn->as<BinaryNode>())) {
12034 return false;
12036 break;
12038 case ParseNodeKind::TryStmt:
12039 if (!emitTry(&pn->as<TryNode>())) {
12040 return false;
12042 break;
12044 case ParseNodeKind::Catch:
12045 if (!emitCatch(&pn->as<BinaryNode>())) {
12046 return false;
12048 break;
12050 case ParseNodeKind::VarStmt:
12051 if (!emitDeclarationList(&pn->as<ListNode>())) {
12052 return false;
12054 break;
12056 case ParseNodeKind::ReturnStmt:
12057 if (!emitReturn(&pn->as<UnaryNode>())) {
12058 return false;
12060 break;
12062 case ParseNodeKind::YieldStarExpr:
12063 if (!emitYieldStar(pn->as<UnaryNode>().kid())) {
12064 return false;
12066 break;
12068 case ParseNodeKind::Generator:
12069 if (!emit1(JSOp::Generator)) {
12070 return false;
12072 break;
12074 case ParseNodeKind::InitialYield:
12075 if (!emitInitialYield(&pn->as<UnaryNode>())) {
12076 return false;
12078 break;
12080 case ParseNodeKind::YieldExpr:
12081 if (!emitYield(&pn->as<UnaryNode>())) {
12082 return false;
12084 break;
12086 case ParseNodeKind::AwaitExpr:
12087 if (!emitAwaitInInnermostScope(&pn->as<UnaryNode>())) {
12088 return false;
12090 break;
12092 case ParseNodeKind::StatementList:
12093 if (!emitStatementList(&pn->as<ListNode>())) {
12094 return false;
12096 break;
12098 case ParseNodeKind::EmptyStmt:
12099 break;
12101 case ParseNodeKind::ExpressionStmt:
12102 if (!emitExpressionStatement(&pn->as<UnaryNode>())) {
12103 return false;
12105 break;
12107 case ParseNodeKind::LabelStmt:
12108 if (!emitLabeledStatement(&pn->as<LabeledStatement>())) {
12109 return false;
12111 break;
12113 case ParseNodeKind::CommaExpr:
12114 if (!emitSequenceExpr(&pn->as<ListNode>(), valueUsage)) {
12115 return false;
12117 break;
12119 case ParseNodeKind::InitExpr:
12120 case ParseNodeKind::AssignExpr:
12121 case ParseNodeKind::AddAssignExpr:
12122 case ParseNodeKind::SubAssignExpr:
12123 case ParseNodeKind::BitOrAssignExpr:
12124 case ParseNodeKind::BitXorAssignExpr:
12125 case ParseNodeKind::BitAndAssignExpr:
12126 case ParseNodeKind::LshAssignExpr:
12127 case ParseNodeKind::RshAssignExpr:
12128 case ParseNodeKind::UrshAssignExpr:
12129 case ParseNodeKind::MulAssignExpr:
12130 case ParseNodeKind::DivAssignExpr:
12131 case ParseNodeKind::ModAssignExpr:
12132 case ParseNodeKind::PowAssignExpr: {
12133 BinaryNode* assignNode = &pn->as<BinaryNode>();
12134 if (!emitAssignmentOrInit(assignNode->getKind(), assignNode->left(),
12135 assignNode->right())) {
12136 return false;
12138 break;
12141 case ParseNodeKind::CoalesceAssignExpr:
12142 case ParseNodeKind::OrAssignExpr:
12143 case ParseNodeKind::AndAssignExpr:
12144 if (!emitShortCircuitAssignment(&pn->as<AssignmentNode>())) {
12145 return false;
12147 break;
12149 case ParseNodeKind::ConditionalExpr:
12150 if (!emitConditionalExpression(pn->as<ConditionalExpression>(),
12151 valueUsage)) {
12152 return false;
12154 break;
12156 case ParseNodeKind::OrExpr:
12157 case ParseNodeKind::CoalesceExpr:
12158 case ParseNodeKind::AndExpr:
12159 if (!emitShortCircuit(&pn->as<ListNode>(), valueUsage)) {
12160 return false;
12162 break;
12164 case ParseNodeKind::AddExpr:
12165 case ParseNodeKind::SubExpr:
12166 case ParseNodeKind::BitOrExpr:
12167 case ParseNodeKind::BitXorExpr:
12168 case ParseNodeKind::BitAndExpr:
12169 case ParseNodeKind::StrictEqExpr:
12170 case ParseNodeKind::EqExpr:
12171 case ParseNodeKind::StrictNeExpr:
12172 case ParseNodeKind::NeExpr:
12173 case ParseNodeKind::LtExpr:
12174 case ParseNodeKind::LeExpr:
12175 case ParseNodeKind::GtExpr:
12176 case ParseNodeKind::GeExpr:
12177 case ParseNodeKind::InExpr:
12178 case ParseNodeKind::InstanceOfExpr:
12179 case ParseNodeKind::LshExpr:
12180 case ParseNodeKind::RshExpr:
12181 case ParseNodeKind::UrshExpr:
12182 case ParseNodeKind::MulExpr:
12183 case ParseNodeKind::DivExpr:
12184 case ParseNodeKind::ModExpr:
12185 if (!emitLeftAssociative(&pn->as<ListNode>())) {
12186 return false;
12188 break;
12190 case ParseNodeKind::PrivateInExpr:
12191 if (!emitPrivateInExpr(&pn->as<ListNode>())) {
12192 return false;
12194 break;
12196 case ParseNodeKind::PowExpr:
12197 if (!emitRightAssociative(&pn->as<ListNode>())) {
12198 return false;
12200 break;
12202 case ParseNodeKind::TypeOfNameExpr:
12203 if (!emitTypeof(&pn->as<UnaryNode>(), JSOp::Typeof)) {
12204 return false;
12206 break;
12208 case ParseNodeKind::TypeOfExpr:
12209 if (!emitTypeof(&pn->as<UnaryNode>(), JSOp::TypeofExpr)) {
12210 return false;
12212 break;
12214 case ParseNodeKind::ThrowStmt:
12215 if (!updateSourceCoordNotes(pn->pn_pos.begin)) {
12216 return false;
12218 if (!markStepBreakpoint()) {
12219 return false;
12221 [[fallthrough]];
12222 case ParseNodeKind::VoidExpr:
12223 case ParseNodeKind::NotExpr:
12224 case ParseNodeKind::BitNotExpr:
12225 case ParseNodeKind::PosExpr:
12226 case ParseNodeKind::NegExpr:
12227 if (!emitUnary(&pn->as<UnaryNode>())) {
12228 return false;
12230 break;
12232 case ParseNodeKind::PreIncrementExpr:
12233 case ParseNodeKind::PreDecrementExpr:
12234 case ParseNodeKind::PostIncrementExpr:
12235 case ParseNodeKind::PostDecrementExpr:
12236 if (!emitIncOrDec(&pn->as<UnaryNode>(), valueUsage)) {
12237 return false;
12239 break;
12241 case ParseNodeKind::DeleteNameExpr:
12242 if (!emitDeleteName(&pn->as<UnaryNode>())) {
12243 return false;
12245 break;
12247 case ParseNodeKind::DeletePropExpr:
12248 if (!emitDeleteProperty(&pn->as<UnaryNode>())) {
12249 return false;
12251 break;
12253 case ParseNodeKind::DeleteElemExpr:
12254 if (!emitDeleteElement(&pn->as<UnaryNode>())) {
12255 return false;
12257 break;
12259 case ParseNodeKind::DeleteExpr:
12260 if (!emitDeleteExpression(&pn->as<UnaryNode>())) {
12261 return false;
12263 break;
12265 case ParseNodeKind::DeleteOptionalChainExpr:
12266 if (!emitDeleteOptionalChain(&pn->as<UnaryNode>())) {
12267 return false;
12269 break;
12271 case ParseNodeKind::OptionalChain:
12272 if (!emitOptionalChain(&pn->as<UnaryNode>(), valueUsage)) {
12273 return false;
12275 break;
12277 case ParseNodeKind::DotExpr: {
12278 PropertyAccess* prop = &pn->as<PropertyAccess>();
12279 bool isSuper = prop->isSuper();
12280 PropOpEmitter poe(this, PropOpEmitter::Kind::Get,
12281 isSuper ? PropOpEmitter::ObjKind::Super
12282 : PropOpEmitter::ObjKind::Other);
12283 if (!poe.prepareForObj()) {
12284 return false;
12286 if (isSuper) {
12287 UnaryNode* base = &prop->expression().as<UnaryNode>();
12288 if (!emitGetThisForSuperBase(base)) {
12289 // [stack] THIS
12290 return false;
12292 } else {
12293 if (!emitPropLHS(prop)) {
12294 // [stack] OBJ
12295 return false;
12298 if (!poe.emitGet(prop->key().atom())) {
12299 // [stack] PROP
12300 return false;
12302 break;
12305 case ParseNodeKind::ElemExpr: {
12306 PropertyByValue* elem = &pn->as<PropertyByValue>();
12307 bool isSuper = elem->isSuper();
12308 MOZ_ASSERT(!elem->key().isKind(ParseNodeKind::PrivateName));
12309 ElemOpEmitter eoe(this, ElemOpEmitter::Kind::Get,
12310 isSuper ? ElemOpEmitter::ObjKind::Super
12311 : ElemOpEmitter::ObjKind::Other);
12312 if (!emitElemObjAndKey(elem, isSuper, eoe)) {
12313 // [stack] # if Super
12314 // [stack] THIS KEY
12315 // [stack] # otherwise
12316 // [stack] OBJ KEY
12317 return false;
12319 if (!eoe.emitGet()) {
12320 // [stack] ELEM
12321 return false;
12324 break;
12327 case ParseNodeKind::PrivateMemberExpr: {
12328 PrivateMemberAccess* privateExpr = &pn->as<PrivateMemberAccess>();
12329 PrivateOpEmitter xoe(this, PrivateOpEmitter::Kind::Get,
12330 privateExpr->privateName().name());
12331 if (!emitTree(&privateExpr->expression())) {
12332 // [stack] OBJ
12333 return false;
12335 if (!xoe.emitReference()) {
12336 // [stack] OBJ NAME
12337 return false;
12339 if (!xoe.emitGet()) {
12340 // [stack] VALUE
12341 return false;
12344 break;
12347 case ParseNodeKind::NewExpr:
12348 case ParseNodeKind::TaggedTemplateExpr:
12349 case ParseNodeKind::CallExpr:
12350 case ParseNodeKind::SuperCallExpr:
12351 if (!emitCallOrNew(&pn->as<CallNode>(), valueUsage)) {
12352 return false;
12354 break;
12356 case ParseNodeKind::LexicalScope:
12357 if (!emitLexicalScope(&pn->as<LexicalScopeNode>())) {
12358 return false;
12360 break;
12362 case ParseNodeKind::ConstDecl:
12363 case ParseNodeKind::LetDecl:
12364 if (!emitDeclarationList(&pn->as<ListNode>())) {
12365 return false;
12367 break;
12369 case ParseNodeKind::ImportDecl:
12370 MOZ_ASSERT(sc->isModuleContext());
12371 break;
12373 case ParseNodeKind::ExportStmt: {
12374 MOZ_ASSERT(sc->isModuleContext());
12375 UnaryNode* node = &pn->as<UnaryNode>();
12376 ParseNode* decl = node->kid();
12377 if (decl->getKind() != ParseNodeKind::ExportSpecList) {
12378 if (!emitTree(decl)) {
12379 return false;
12382 break;
12385 case ParseNodeKind::ExportDefaultStmt:
12386 MOZ_ASSERT(sc->isModuleContext());
12387 if (!emitExportDefault(&pn->as<BinaryNode>())) {
12388 return false;
12390 break;
12392 case ParseNodeKind::ExportFromStmt:
12393 MOZ_ASSERT(sc->isModuleContext());
12394 break;
12396 case ParseNodeKind::CallSiteObj:
12397 if (!emitCallSiteObject(&pn->as<CallSiteNode>())) {
12398 return false;
12400 break;
12402 case ParseNodeKind::ArrayExpr:
12403 if (!emitArrayLiteral(&pn->as<ListNode>())) {
12404 return false;
12406 break;
12408 case ParseNodeKind::ObjectExpr:
12409 if (!emitObject(&pn->as<ListNode>())) {
12410 return false;
12412 break;
12414 case ParseNodeKind::Name:
12415 if (!emitGetName(&pn->as<NameNode>())) {
12416 return false;
12418 break;
12420 case ParseNodeKind::PrivateName:
12421 if (!emitGetPrivateName(&pn->as<NameNode>())) {
12422 return false;
12424 break;
12426 case ParseNodeKind::TemplateStringListExpr:
12427 if (!emitTemplateString(&pn->as<ListNode>())) {
12428 return false;
12430 break;
12432 case ParseNodeKind::TemplateStringExpr:
12433 case ParseNodeKind::StringExpr:
12434 if (!emitStringOp(JSOp::String, pn->as<NameNode>().atom())) {
12435 return false;
12437 break;
12439 case ParseNodeKind::NumberExpr:
12440 if (!emitNumberOp(pn->as<NumericLiteral>().value())) {
12441 return false;
12443 break;
12445 case ParseNodeKind::BigIntExpr:
12446 if (!emitBigIntOp(&pn->as<BigIntLiteral>())) {
12447 return false;
12449 break;
12451 case ParseNodeKind::RegExpExpr: {
12452 GCThingIndex index;
12453 if (!perScriptData().gcThingList().append(&pn->as<RegExpLiteral>(),
12454 &index)) {
12455 return false;
12457 if (!emitRegExp(index)) {
12458 return false;
12460 break;
12463 case ParseNodeKind::TrueExpr:
12464 if (!emit1(JSOp::True)) {
12465 return false;
12467 break;
12468 case ParseNodeKind::FalseExpr:
12469 if (!emit1(JSOp::False)) {
12470 return false;
12472 break;
12473 case ParseNodeKind::NullExpr:
12474 if (!emit1(JSOp::Null)) {
12475 return false;
12477 break;
12478 case ParseNodeKind::RawUndefinedExpr:
12479 if (!emit1(JSOp::Undefined)) {
12480 return false;
12482 break;
12484 case ParseNodeKind::ThisExpr:
12485 if (!emitThisLiteral(&pn->as<ThisLiteral>())) {
12486 return false;
12488 break;
12490 case ParseNodeKind::DebuggerStmt:
12491 if (!updateSourceCoordNotes(pn->pn_pos.begin)) {
12492 return false;
12494 if (!markStepBreakpoint()) {
12495 return false;
12497 if (!emit1(JSOp::Debugger)) {
12498 return false;
12500 break;
12502 case ParseNodeKind::ClassDecl:
12503 if (!emitClass(&pn->as<ClassNode>())) {
12504 return false;
12506 break;
12508 case ParseNodeKind::NewTargetExpr:
12509 if (!emitNewTarget(&pn->as<NewTargetNode>())) {
12510 return false;
12512 break;
12514 case ParseNodeKind::ImportMetaExpr:
12515 if (!emit1(JSOp::ImportMeta)) {
12516 return false;
12518 break;
12520 case ParseNodeKind::CallImportExpr: {
12521 BinaryNode* spec = &pn->as<BinaryNode>().right()->as<BinaryNode>();
12523 if (!emitTree(spec->left())) {
12524 // [stack] specifier
12525 return false;
12528 if (!spec->right()->isKind(ParseNodeKind::PosHolder)) {
12529 // [stack] specifier options
12530 if (!emitTree(spec->right())) {
12531 return false;
12533 } else {
12534 // [stack] specifier undefined
12535 if (!emit1(JSOp::Undefined)) {
12536 return false;
12540 if (!emit1(JSOp::DynamicImport)) {
12541 return false;
12544 break;
12547 case ParseNodeKind::SetThis:
12548 if (!emitSetThis(&pn->as<BinaryNode>())) {
12549 return false;
12551 break;
12553 #ifdef ENABLE_RECORD_TUPLE
12554 case ParseNodeKind::RecordExpr:
12555 if (!emitRecordLiteral(&pn->as<ListNode>())) {
12556 return false;
12558 break;
12560 case ParseNodeKind::TupleExpr:
12561 if (!emitTupleLiteral(&pn->as<ListNode>())) {
12562 return false;
12564 break;
12565 #endif
12567 case ParseNodeKind::PropertyNameExpr:
12568 case ParseNodeKind::PosHolder:
12569 MOZ_FALLTHROUGH_ASSERT(
12570 "Should never try to emit ParseNodeKind::PosHolder or ::Property");
12572 default:
12573 MOZ_ASSERT(0);
12576 return true;
12579 static bool AllocSrcNote(FrontendContext* fc, SrcNotesVector& notes,
12580 unsigned size, unsigned* index) {
12581 size_t oldLength = notes.length();
12583 if (MOZ_UNLIKELY(oldLength + size > MaxSrcNotesLength)) {
12584 ReportAllocationOverflow(fc);
12585 return false;
12588 if (!notes.growByUninitialized(size)) {
12589 return false;
12592 *index = oldLength;
12593 return true;
12596 bool BytecodeEmitter::addTryNote(TryNoteKind kind, uint32_t stackDepth,
12597 BytecodeOffset start, BytecodeOffset end) {
12598 MOZ_ASSERT(!inPrologue());
12599 return bytecodeSection().tryNoteList().append(kind, stackDepth, start, end);
12602 bool BytecodeEmitter::newSrcNote(SrcNoteType type, unsigned* indexp) {
12603 SrcNotesVector& notes = bytecodeSection().notes();
12604 unsigned index;
12607 * Compute delta from the last annotated bytecode's offset. If it's too
12608 * big to fit in sn, allocate one or more xdelta notes and reset sn.
12610 BytecodeOffset offset = bytecodeSection().offset();
12611 ptrdiff_t delta = (offset - bytecodeSection().lastNoteOffset()).value();
12612 bytecodeSection().setLastNoteOffset(offset);
12614 auto allocator = [&](unsigned size) -> SrcNote* {
12615 if (!AllocSrcNote(fc, notes, size, &index)) {
12616 return nullptr;
12618 return &notes[index];
12621 if (!SrcNoteWriter::writeNote(type, delta, allocator)) {
12622 return false;
12625 if (indexp) {
12626 *indexp = index;
12629 if (type == SrcNoteType::NewLine || type == SrcNoteType::SetLine) {
12630 lastLineOnlySrcNoteIndex = index;
12631 } else {
12632 lastLineOnlySrcNoteIndex = LastSrcNoteIsNotLineOnly;
12635 return true;
12638 bool BytecodeEmitter::newSrcNote2(SrcNoteType type, ptrdiff_t offset,
12639 unsigned* indexp) {
12640 unsigned index;
12641 if (!newSrcNote(type, &index)) {
12642 return false;
12644 if (!newSrcNoteOperand(offset)) {
12645 return false;
12647 if (indexp) {
12648 *indexp = index;
12650 return true;
12653 bool BytecodeEmitter::convertLastNewLineToNewLineColumn(
12654 JS::LimitedColumnNumberOneOrigin column) {
12655 SrcNotesVector& notes = bytecodeSection().notes();
12656 MOZ_ASSERT(lastLineOnlySrcNoteIndex == notes.length() - 1);
12657 SrcNote* sn = &notes[lastLineOnlySrcNoteIndex];
12658 MOZ_ASSERT(sn->type() == SrcNoteType::NewLine);
12660 SrcNoteWriter::convertNote(sn, SrcNoteType::NewLineColumn);
12661 if (!newSrcNoteOperand(SrcNote::NewLineColumn::toOperand(column))) {
12662 return false;
12665 lastLineOnlySrcNoteIndex = LastSrcNoteIsNotLineOnly;
12666 return true;
12669 bool BytecodeEmitter::convertLastSetLineToSetLineColumn(
12670 JS::LimitedColumnNumberOneOrigin column) {
12671 SrcNotesVector& notes = bytecodeSection().notes();
12672 // The Line operand is either 1 byte or 4 bytes.
12673 MOZ_ASSERT(lastLineOnlySrcNoteIndex == notes.length() - 1 - 1 ||
12674 lastLineOnlySrcNoteIndex == notes.length() - 1 - 4);
12675 SrcNote* sn = &notes[lastLineOnlySrcNoteIndex];
12676 MOZ_ASSERT(sn->type() == SrcNoteType::SetLine);
12678 SrcNoteWriter::convertNote(sn, SrcNoteType::SetLineColumn);
12679 if (!newSrcNoteOperand(SrcNote::SetLineColumn::columnToOperand(column))) {
12680 return false;
12683 lastLineOnlySrcNoteIndex = LastSrcNoteIsNotLineOnly;
12684 return true;
12687 bool BytecodeEmitter::newSrcNoteOperand(ptrdiff_t operand) {
12688 if (!SrcNote::isRepresentableOperand(operand)) {
12689 reportError(nullptr, JSMSG_NEED_DIET, "script");
12690 return false;
12693 SrcNotesVector& notes = bytecodeSection().notes();
12695 auto allocator = [&](unsigned size) -> SrcNote* {
12696 unsigned index;
12697 if (!AllocSrcNote(fc, notes, size, &index)) {
12698 return nullptr;
12700 return &notes[index];
12703 return SrcNoteWriter::writeOperand(operand, allocator);
12706 bool BytecodeEmitter::intoScriptStencil(ScriptIndex scriptIndex) {
12707 js::UniquePtr<ImmutableScriptData> immutableScriptData =
12708 createImmutableScriptData();
12709 if (!immutableScriptData) {
12710 return false;
12713 MOZ_ASSERT(outermostScope().hasNonSyntacticScopeOnChain() ==
12714 sc->hasNonSyntacticScope());
12716 auto& things = perScriptData().gcThingList().objects();
12717 if (!compilationState.appendGCThings(fc, scriptIndex, things)) {
12718 return false;
12721 // Hand over the ImmutableScriptData instance generated by BCE.
12722 auto* sharedData =
12723 SharedImmutableScriptData::createWith(fc, std::move(immutableScriptData));
12724 if (!sharedData) {
12725 return false;
12728 // De-duplicate the bytecode within the runtime.
12729 if (!compilationState.sharedData.addAndShare(fc, scriptIndex, sharedData)) {
12730 return false;
12733 ScriptStencil& script = compilationState.scriptData[scriptIndex];
12734 script.setHasSharedData();
12736 // Update flags specific to functions.
12737 if (sc->isFunctionBox()) {
12738 FunctionBox* funbox = sc->asFunctionBox();
12739 MOZ_ASSERT(&script == &funbox->functionStencil());
12740 funbox->copyUpdatedImmutableFlags();
12741 MOZ_ASSERT(script.isFunction());
12742 } else {
12743 ScriptStencilExtra& scriptExtra = compilationState.scriptExtra[scriptIndex];
12744 sc->copyScriptExtraFields(scriptExtra);
12747 return true;
12750 SelfHostedIter BytecodeEmitter::getSelfHostedIterFor(ParseNode* parseNode) {
12751 if (emitterMode == BytecodeEmitter::SelfHosting &&
12752 parseNode->isKind(ParseNodeKind::CallExpr)) {
12753 auto* callee = parseNode->as<CallNode>().callee();
12754 if (callee->isName(TaggedParserAtomIndex::WellKnown::allowContentIter())) {
12755 return SelfHostedIter::AllowContent;
12757 if (callee->isName(
12758 TaggedParserAtomIndex::WellKnown::allowContentIterWith())) {
12759 return SelfHostedIter::AllowContentWith;
12761 if (callee->isName(
12762 TaggedParserAtomIndex::WellKnown::allowContentIterWithNext())) {
12763 return SelfHostedIter::AllowContentWithNext;
12767 return SelfHostedIter::Deny;
12770 #if defined(DEBUG) || defined(JS_JITSPEW)
12771 void BytecodeEmitter::dumpAtom(TaggedParserAtomIndex index) const {
12772 parserAtoms().dump(index);
12774 #endif