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/. */
8 * JS bytecode generation.
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
26 #include "jstypes.h" // JS_BIT
28 #include "frontend/AbstractScopePtr.h" // ScopeIndex
29 #include "frontend/BytecodeControlStructures.h" // NestableControl, BreakableControl, LabelControl, LoopControl, TryFinallyControl
30 #include "frontend/CallOrNewEmitter.h" // CallOrNewEmitter
31 #include "frontend/CForEmitter.h" // CForEmitter
32 #include "frontend/DecoratorEmitter.h" // DecoratorEmitter
33 #include "frontend/DefaultEmitter.h" // DefaultEmitter
34 #include "frontend/DoWhileEmitter.h" // DoWhileEmitter
35 #include "frontend/ElemOpEmitter.h" // ElemOpEmitter
36 #include "frontend/EmitterScope.h" // EmitterScope
37 #include "frontend/ExpressionStatementEmitter.h" // ExpressionStatementEmitter
38 #include "frontend/ForInEmitter.h" // ForInEmitter
39 #include "frontend/ForOfEmitter.h" // ForOfEmitter
40 #include "frontend/FunctionEmitter.h" // FunctionEmitter, FunctionScriptEmitter, FunctionParamsEmitter
41 #include "frontend/IfEmitter.h" // IfEmitter, InternalIfEmitter, CondEmitter
42 #include "frontend/LabelEmitter.h" // LabelEmitter
43 #include "frontend/LexicalScopeEmitter.h" // LexicalScopeEmitter
44 #include "frontend/ModuleSharedContext.h" // ModuleSharedContext
45 #include "frontend/NameAnalysisTypes.h" // PrivateNameKind
46 #include "frontend/NameFunctions.h" // NameFunctions
47 #include "frontend/NameOpEmitter.h" // NameOpEmitter
48 #include "frontend/ObjectEmitter.h" // PropertyEmitter, ObjectEmitter, ClassEmitter
49 #include "frontend/OptionalEmitter.h" // OptionalEmitter
50 #include "frontend/ParseNode.h" // ParseNodeKind, ParseNode and subclasses
51 #include "frontend/Parser.h" // Parser
52 #include "frontend/ParserAtom.h" // ParserAtomsTable, ParserAtom
53 #include "frontend/PrivateOpEmitter.h" // PrivateOpEmitter
54 #include "frontend/PropOpEmitter.h" // PropOpEmitter
55 #include "frontend/SourceNotes.h" // SrcNote, SrcNoteType, SrcNoteWriter
56 #include "frontend/SwitchEmitter.h" // SwitchEmitter
57 #include "frontend/TaggedParserAtomIndexHasher.h" // TaggedParserAtomIndexHasher
58 #include "frontend/TDZCheckCache.h" // TDZCheckCache
59 #include "frontend/TryEmitter.h" // TryEmitter
60 #include "frontend/WhileEmitter.h" // WhileEmitter
61 #include "js/ColumnNumber.h" // JS::LimitedColumnNumberZeroOrigin, JS::ColumnNumberOffset
62 #include "js/friend/ErrorMessages.h" // JSMSG_*
63 #include "js/friend/StackLimits.h" // AutoCheckRecursionLimit
64 #include "util/StringBuffer.h" // StringBuffer
65 #include "vm/BytecodeUtil.h" // JOF_*, IsArgOp, IsLocalOp, SET_UINT24, SET_ICINDEX, BytecodeFallsThrough, BytecodeIsJumpTarget
66 #include "vm/CompletionKind.h" // CompletionKind
67 #include "vm/FunctionPrefixKind.h" // FunctionPrefixKind
68 #include "vm/GeneratorObject.h" // AbstractGeneratorObject
69 #include "vm/Opcodes.h" // JSOp, JSOpLength_*
70 #include "vm/PropMap.h" // SharedPropMap::MaxPropsForNonDictionary
71 #include "vm/Scope.h" // GetScopeDataTrailingNames
72 #include "vm/SharedStencil.h" // ScopeNote
73 #include "vm/ThrowMsgKind.h" // ThrowMsgKind
76 using namespace js::frontend
;
78 using mozilla::AssertedCast
;
79 using mozilla::AsVariant
;
80 using mozilla::DebugOnly
;
82 using mozilla::Nothing
;
83 using mozilla::NumberEqualsInt32
;
84 using mozilla::NumberIsInt32
;
85 using mozilla::PodCopy
;
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
) {
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
) {
125 // Suppress for synthesized class constructors.
126 if (sc
->isFunctionBox()) {
127 FunctionBox
* funbox
= sc
->asFunctionBox();
128 return funbox
->isSyntheticFunction() && funbox
->isClassConstructor();
134 BytecodeEmitter::BytecodeEmitter(BytecodeEmitter
* parent
, FrontendContext
* fc
,
136 const ErrorReporter
& errorReporter
,
137 CompilationState
& compilationState
,
138 EmitterMode emitterMode
)
142 bytecodeSection_(fc
, sc
->extent().lineno
, sc
->extent().column
),
143 perScriptData_(fc
, compilationState
),
144 errorReporter_(errorReporter
),
145 compilationState(compilationState
),
146 suppressBreakpointsAndSourceNotes(
147 ShouldSuppressBreakpointsAndSourceNotes(sc
, emitterMode
)),
148 emitterMode(emitterMode
) {
149 MOZ_ASSERT_IF(parent
, fc
== parent
->fc
);
152 BytecodeEmitter::BytecodeEmitter(BytecodeEmitter
* parent
, SharedContext
* sc
)
153 : BytecodeEmitter(parent
, parent
->fc
, sc
, parent
->errorReporter_
,
154 parent
->compilationState
, parent
->emitterMode
) {}
156 BytecodeEmitter::BytecodeEmitter(FrontendContext
* fc
,
157 const EitherParser
& parser
, SharedContext
* sc
,
158 CompilationState
& compilationState
,
159 EmitterMode emitterMode
)
160 : BytecodeEmitter(nullptr, fc
, sc
, parser
.errorReporter(), compilationState
,
165 void BytecodeEmitter::initFromBodyPosition(TokenPos bodyPosition
) {
166 setScriptStartOffsetIfUnset(bodyPosition
.begin
);
167 setFunctionBodyEndPos(bodyPosition
.end
);
170 bool BytecodeEmitter::init() {
172 if (!compilationState
.prepareSharedDataStorage(fc
)) {
176 return perScriptData_
.init(fc
);
179 bool BytecodeEmitter::init(TokenPos bodyPosition
) {
180 initFromBodyPosition(bodyPosition
);
184 template <typename T
>
185 T
* BytecodeEmitter::findInnermostNestableControl() const {
186 return NestableControl::findNearest
<T
>(innermostNestableControl
);
189 template <typename T
, typename Predicate
/* (T*) -> bool */>
190 T
* BytecodeEmitter::findInnermostNestableControl(Predicate predicate
) const {
191 return NestableControl::findNearest
<T
>(innermostNestableControl
, predicate
);
194 NameLocation
BytecodeEmitter::lookupName(TaggedParserAtomIndex name
) {
195 return innermostEmitterScope()->lookup(this, name
);
198 void BytecodeEmitter::lookupPrivate(TaggedParserAtomIndex name
,
200 Maybe
<NameLocation
>& brandLoc
) {
201 innermostEmitterScope()->lookupPrivate(this, name
, loc
, brandLoc
);
204 Maybe
<NameLocation
> BytecodeEmitter::locationOfNameBoundInScope(
205 TaggedParserAtomIndex name
, EmitterScope
* target
) {
206 return innermostEmitterScope()->locationBoundInScope(name
, target
);
209 template <typename T
>
210 Maybe
<NameLocation
> BytecodeEmitter::locationOfNameBoundInScopeType(
211 TaggedParserAtomIndex name
, EmitterScope
* source
) {
212 EmitterScope
* aScope
= source
;
213 while (!aScope
->scope(this).is
<T
>()) {
214 aScope
= aScope
->enclosingInFrame();
216 return source
->locationBoundInScope(name
, aScope
);
219 bool BytecodeEmitter::markStepBreakpoint() {
220 if (skipBreakpointSrcNotes()) {
224 if (!newSrcNote(SrcNoteType::BreakpointStepSep
)) {
228 // We track the location of the most recent separator for use in
229 // markSimpleBreakpoint. Note that this means that the position must already
230 // be set before markStepBreakpoint is called.
231 bytecodeSection().updateSeparatorPosition();
236 bool BytecodeEmitter::markSimpleBreakpoint() {
237 if (skipBreakpointSrcNotes()) {
241 // If a breakable call ends up being the same location as the most recent
242 // expression start, we need to skip marking it breakable in order to avoid
243 // having two breakpoints with the same line/column position.
244 // Note: This assumes that the position for the call has already been set.
245 if (!bytecodeSection().isDuplicateLocation()) {
246 if (!newSrcNote(SrcNoteType::Breakpoint
)) {
254 bool BytecodeEmitter::emitCheck(JSOp op
, ptrdiff_t delta
,
255 BytecodeOffset
* offset
) {
256 size_t oldLength
= bytecodeSection().code().length();
257 *offset
= BytecodeOffset(oldLength
);
259 size_t newLength
= oldLength
+ size_t(delta
);
260 if (MOZ_UNLIKELY(newLength
> MaxBytecodeLength
)) {
261 ReportAllocationOverflow(fc
);
265 if (!bytecodeSection().code().growByUninitialized(delta
)) {
269 if (BytecodeOpHasIC(op
)) {
270 // Even if every bytecode op is a JOF_IC op and the function has ARGC_LIMIT
271 // arguments, numICEntries cannot overflow.
272 static_assert(MaxBytecodeLength
+ 1 /* this */ + ARGC_LIMIT
<= UINT32_MAX
,
273 "numICEntries must not overflow");
274 bytecodeSection().incrementNumICEntries();
281 bool BytecodeEmitter::checkStrictOrSloppy(JSOp op
) {
282 if (IsCheckStrictOp(op
) && !sc
->strict()) {
285 if (IsCheckSloppyOp(op
) && sc
->strict()) {
292 bool BytecodeEmitter::emit1(JSOp op
) {
293 MOZ_ASSERT(checkStrictOrSloppy(op
));
295 BytecodeOffset offset
;
296 if (!emitCheck(op
, 1, &offset
)) {
300 jsbytecode
* code
= bytecodeSection().code(offset
);
301 code
[0] = jsbytecode(op
);
302 bytecodeSection().updateDepth(op
, offset
);
306 bool BytecodeEmitter::emit2(JSOp op
, uint8_t op1
) {
307 MOZ_ASSERT(checkStrictOrSloppy(op
));
309 BytecodeOffset offset
;
310 if (!emitCheck(op
, 2, &offset
)) {
314 jsbytecode
* code
= bytecodeSection().code(offset
);
315 code
[0] = jsbytecode(op
);
316 code
[1] = jsbytecode(op1
);
317 bytecodeSection().updateDepth(op
, offset
);
321 bool BytecodeEmitter::emit3(JSOp op
, jsbytecode op1
, jsbytecode op2
) {
322 MOZ_ASSERT(checkStrictOrSloppy(op
));
324 /* These should filter through emitVarOp. */
325 MOZ_ASSERT(!IsArgOp(op
));
326 MOZ_ASSERT(!IsLocalOp(op
));
328 BytecodeOffset offset
;
329 if (!emitCheck(op
, 3, &offset
)) {
333 jsbytecode
* code
= bytecodeSection().code(offset
);
334 code
[0] = jsbytecode(op
);
337 bytecodeSection().updateDepth(op
, offset
);
341 bool BytecodeEmitter::emitN(JSOp op
, size_t extra
, BytecodeOffset
* offset
) {
342 MOZ_ASSERT(checkStrictOrSloppy(op
));
343 ptrdiff_t length
= 1 + ptrdiff_t(extra
);
346 if (!emitCheck(op
, length
, &off
)) {
350 jsbytecode
* code
= bytecodeSection().code(off
);
351 code
[0] = jsbytecode(op
);
352 /* The remaining |extra| bytes are set by the caller */
355 * Don't updateDepth if op's use-count comes from the immediate
356 * operand yet to be stored in the extra bytes after op.
358 if (CodeSpec(op
).nuses
>= 0) {
359 bytecodeSection().updateDepth(op
, off
);
368 bool BytecodeEmitter::emitJumpTargetOp(JSOp op
, BytecodeOffset
* off
) {
369 MOZ_ASSERT(BytecodeIsJumpTarget(op
));
371 // Record the current IC-entry index at start of this op.
372 uint32_t numEntries
= bytecodeSection().numICEntries();
374 size_t n
= GetOpLength(op
) - 1;
375 MOZ_ASSERT(GetOpLength(op
) >= 1 + ICINDEX_LEN
);
377 if (!emitN(op
, n
, off
)) {
381 SET_ICINDEX(bytecodeSection().code(*off
), numEntries
);
385 bool BytecodeEmitter::emitJumpTarget(JumpTarget
* target
) {
386 BytecodeOffset off
= bytecodeSection().offset();
388 // Alias consecutive jump targets.
389 if (bytecodeSection().lastTargetOffset().valid() &&
390 off
== bytecodeSection().lastTargetOffset() +
391 BytecodeOffsetDiff(JSOpLength_JumpTarget
)) {
392 target
->offset
= bytecodeSection().lastTargetOffset();
396 target
->offset
= off
;
397 bytecodeSection().setLastTargetOffset(off
);
399 BytecodeOffset opOff
;
400 return emitJumpTargetOp(JSOp::JumpTarget
, &opOff
);
403 bool BytecodeEmitter::emitJumpNoFallthrough(JSOp op
, JumpList
* jump
) {
404 BytecodeOffset offset
;
405 if (!emitCheck(op
, 5, &offset
)) {
409 jsbytecode
* code
= bytecodeSection().code(offset
);
410 code
[0] = jsbytecode(op
);
411 MOZ_ASSERT(!jump
->offset
.valid() ||
412 (0 <= jump
->offset
.value() && jump
->offset
< offset
));
413 jump
->push(bytecodeSection().code(BytecodeOffset(0)), offset
);
414 bytecodeSection().updateDepth(op
, offset
);
418 bool BytecodeEmitter::emitJump(JSOp op
, JumpList
* jump
) {
419 if (!emitJumpNoFallthrough(op
, jump
)) {
422 if (BytecodeFallsThrough(op
)) {
423 JumpTarget fallthrough
;
424 if (!emitJumpTarget(&fallthrough
)) {
431 void BytecodeEmitter::patchJumpsToTarget(JumpList jump
, JumpTarget target
) {
433 !jump
.offset
.valid() ||
434 (0 <= jump
.offset
.value() && jump
.offset
<= bytecodeSection().offset()));
435 MOZ_ASSERT(0 <= target
.offset
.value() &&
436 target
.offset
<= bytecodeSection().offset());
438 jump
.offset
.valid() &&
439 target
.offset
+ BytecodeOffsetDiff(4) <= bytecodeSection().offset(),
440 BytecodeIsJumpTarget(JSOp(*bytecodeSection().code(target
.offset
))));
441 jump
.patchAll(bytecodeSection().code(BytecodeOffset(0)), target
);
444 bool BytecodeEmitter::emitJumpTargetAndPatch(JumpList jump
) {
445 if (!jump
.offset
.valid()) {
449 if (!emitJumpTarget(&target
)) {
452 patchJumpsToTarget(jump
, target
);
456 bool BytecodeEmitter::emitCall(JSOp op
, uint16_t argc
,
457 const Maybe
<uint32_t>& sourceCoordOffset
) {
458 if (sourceCoordOffset
.isSome()) {
459 if (!updateSourceCoordNotes(*sourceCoordOffset
)) {
463 return emit3(op
, ARGC_LO(argc
), ARGC_HI(argc
));
466 bool BytecodeEmitter::emitCall(JSOp op
, uint16_t argc
, ParseNode
* pn
) {
467 return emitCall(op
, argc
, pn
? Some(pn
->pn_pos
.begin
) : Nothing());
470 bool BytecodeEmitter::emitDupAt(unsigned slotFromTop
, unsigned count
) {
471 MOZ_ASSERT(slotFromTop
< unsigned(bytecodeSection().stackDepth()));
472 MOZ_ASSERT(slotFromTop
+ 1 >= count
);
474 if (slotFromTop
== 0 && count
== 1) {
475 return emit1(JSOp::Dup
);
478 if (slotFromTop
== 1 && count
== 2) {
479 return emit1(JSOp::Dup2
);
482 if (slotFromTop
>= Bit(24)) {
483 reportError(nullptr, JSMSG_TOO_MANY_LOCALS
);
487 for (unsigned i
= 0; i
< count
; i
++) {
489 if (!emitN(JSOp::DupAt
, 3, &off
)) {
493 jsbytecode
* pc
= bytecodeSection().code(off
);
494 SET_UINT24(pc
, slotFromTop
);
500 bool BytecodeEmitter::emitPopN(unsigned n
) {
504 return emit1(JSOp::Pop
);
507 // 2 JSOp::Pop instructions (2 bytes) are shorter than JSOp::PopN (3 bytes).
509 return emit1(JSOp::Pop
) && emit1(JSOp::Pop
);
512 return emitUint16Operand(JSOp::PopN
, n
);
515 bool BytecodeEmitter::emitPickN(uint8_t n
) {
519 return emit1(JSOp::Swap
);
522 return emit2(JSOp::Pick
, n
);
525 bool BytecodeEmitter::emitUnpickN(uint8_t n
) {
529 return emit1(JSOp::Swap
);
532 return emit2(JSOp::Unpick
, n
);
535 bool BytecodeEmitter::emitCheckIsObj(CheckIsObjectKind kind
) {
536 return emit2(JSOp::CheckIsObj
, uint8_t(kind
));
539 bool BytecodeEmitter::emitBuiltinObject(BuiltinObjectKind kind
) {
540 return emit2(JSOp::BuiltinObject
, uint8_t(kind
));
543 /* Updates line number notes, not column notes. */
544 bool BytecodeEmitter::updateLineNumberNotes(uint32_t offset
) {
545 if (skipLocationSrcNotes()) {
549 const ErrorReporter
& er
= errorReporter();
550 std::optional
<bool> onThisLineStatus
=
551 er
.isOnThisLine(offset
, bytecodeSection().currentLine());
552 if (!onThisLineStatus
.has_value()) {
553 er
.errorNoOffset(JSMSG_OUT_OF_MEMORY
);
557 bool onThisLine
= *onThisLineStatus
;
560 unsigned line
= er
.lineAt(offset
);
561 unsigned delta
= line
- bytecodeSection().currentLine();
563 // If we use a `SetLine` note below, we want it to be relative to the
564 // scripts initial line number for better chance of sharing.
565 unsigned initialLine
= sc
->extent().lineno
;
566 MOZ_ASSERT(line
>= initialLine
);
569 * Encode any change in the current source line number by using
570 * either several SrcNoteType::NewLine notes or just one
571 * SrcNoteType::SetLine note, whichever consumes less space.
573 * NB: We handle backward line number deltas (possible with for
574 * loops where the update part is emitted after the body, but its
575 * line number is <= any line number in the body) here by letting
576 * unsigned delta_ wrap to a very large number, which triggers a
577 * SrcNoteType::SetLine.
579 bytecodeSection().setCurrentLine(line
, offset
);
580 if (delta
>= SrcNote::SetLine::lengthFor(line
, initialLine
)) {
581 if (!newSrcNote2(SrcNoteType::SetLine
,
582 SrcNote::SetLine::toOperand(line
, initialLine
))) {
587 if (!newSrcNote(SrcNoteType::NewLine
)) {
590 } while (--delta
!= 0);
593 bytecodeSection().updateSeparatorPositionIfPresent();
598 /* Updates the line number and column number information in the source notes. */
599 bool BytecodeEmitter::updateSourceCoordNotes(uint32_t offset
) {
600 if (skipLocationSrcNotes()) {
604 if (!updateLineNumberNotes(offset
)) {
608 JS::LimitedColumnNumberZeroOrigin columnIndex
=
609 errorReporter().columnAt(offset
);
611 // Assert colspan is always representable.
612 static_assert((0 - ptrdiff_t(JS::LimitedColumnNumberZeroOrigin::Limit
)) >=
613 SrcNote::ColSpan::MinColSpan
);
614 static_assert((ptrdiff_t(JS::LimitedColumnNumberZeroOrigin::Limit
) - 0) <=
615 SrcNote::ColSpan::MaxColSpan
);
617 JS::ColumnNumberOffset colspan
= columnIndex
- bytecodeSection().lastColumn();
619 if (colspan
!= JS::ColumnNumberOffset::zero()) {
620 if (lastLineOnlySrcNoteIndex
!= LastSrcNoteIsNotLineOnly
) {
621 MOZ_ASSERT(bytecodeSection().lastColumn() ==
622 JS::LimitedColumnNumberZeroOrigin::zero());
624 const SrcNotesVector
& notes
= bytecodeSection().notes();
625 SrcNoteType type
= notes
[lastLineOnlySrcNoteIndex
].type();
626 if (type
== SrcNoteType::NewLine
) {
627 if (!convertLastNewLineToNewLineColumn(columnIndex
)) {
631 MOZ_ASSERT(type
== SrcNoteType::SetLine
);
632 if (!convertLastSetLineToSetLineColumn(columnIndex
)) {
637 if (!newSrcNote2(SrcNoteType::ColSpan
,
638 SrcNote::ColSpan::toOperand(colspan
))) {
642 bytecodeSection().setLastColumn(columnIndex
, offset
);
643 bytecodeSection().updateSeparatorPositionIfPresent();
648 bool BytecodeEmitter::updateSourceCoordNotesIfNonLiteral(ParseNode
* node
) {
649 if (node
->isLiteral()) {
652 return updateSourceCoordNotes(node
->pn_pos
.begin
);
655 uint32_t BytecodeEmitter::getOffsetForLoop(ParseNode
* nextpn
) {
656 // Try to give the JSOp::LoopHead the same line number as the next
657 // instruction. nextpn is often a block, in which case the next instruction
658 // typically comes from the first statement inside.
659 if (nextpn
->is
<LexicalScopeNode
>()) {
660 nextpn
= nextpn
->as
<LexicalScopeNode
>().scopeBody();
662 if (nextpn
->isKind(ParseNodeKind::StatementList
)) {
663 if (ParseNode
* firstStatement
= nextpn
->as
<ListNode
>().head()) {
664 nextpn
= firstStatement
;
668 return nextpn
->pn_pos
.begin
;
671 bool BytecodeEmitter::emitUint16Operand(JSOp op
, uint32_t operand
) {
672 MOZ_ASSERT(operand
<= UINT16_MAX
);
673 if (!emit3(op
, UINT16_LO(operand
), UINT16_HI(operand
))) {
679 bool BytecodeEmitter::emitUint32Operand(JSOp op
, uint32_t operand
) {
681 if (!emitN(op
, 4, &off
)) {
684 SET_UINT32(bytecodeSection().code(off
), operand
);
688 bool BytecodeEmitter::emitGoto(NestableControl
* target
, GotoKind kind
) {
689 NonLocalExitControl
nle(this, kind
== GotoKind::Continue
690 ? NonLocalExitKind::Continue
691 : NonLocalExitKind::Break
);
692 return nle
.emitNonLocalJump(target
);
695 AbstractScopePtr
BytecodeEmitter::innermostScope() const {
696 return innermostEmitterScope()->scope(this);
699 ScopeIndex
BytecodeEmitter::innermostScopeIndex() const {
700 return *innermostEmitterScope()->scopeIndex(this);
703 bool BytecodeEmitter::emitGCIndexOp(JSOp op
, GCThingIndex index
) {
704 MOZ_ASSERT(checkStrictOrSloppy(op
));
706 constexpr size_t OpLength
= 1 + GCTHING_INDEX_LEN
;
707 MOZ_ASSERT(GetOpLength(op
) == OpLength
);
709 BytecodeOffset offset
;
710 if (!emitCheck(op
, OpLength
, &offset
)) {
714 jsbytecode
* code
= bytecodeSection().code(offset
);
715 code
[0] = jsbytecode(op
);
716 SET_GCTHING_INDEX(code
, index
);
717 bytecodeSection().updateDepth(op
, offset
);
721 bool BytecodeEmitter::emitAtomOp(JSOp op
, TaggedParserAtomIndex atom
) {
724 // .generator lookups should be emitted as JSOp::GetAliasedVar instead of
725 // JSOp::GetName etc, to bypass |with| objects on the scope chain.
726 // It's safe to emit .this lookups though because |with| objects skip
728 MOZ_ASSERT_IF(op
== JSOp::GetName
|| op
== JSOp::GetGName
,
729 atom
!= TaggedParserAtomIndex::WellKnown::dot_generator_());
732 if (!makeAtomIndex(atom
, ParserAtom::Atomize::Yes
, &index
)) {
736 return emitAtomOp(op
, index
);
739 bool BytecodeEmitter::emitAtomOp(JSOp op
, GCThingIndex atomIndex
) {
740 MOZ_ASSERT(JOF_OPTYPE(op
) == JOF_ATOM
);
742 auto atom
= perScriptData().gcThingList().getAtom(atomIndex
);
743 MOZ_ASSERT(compilationState
.parserAtoms
.isInstantiatedAsJSAtom(atom
));
745 return emitGCIndexOp(op
, atomIndex
);
748 bool BytecodeEmitter::emitStringOp(JSOp op
, TaggedParserAtomIndex atom
) {
751 if (!makeAtomIndex(atom
, ParserAtom::Atomize::No
, &index
)) {
755 return emitStringOp(op
, index
);
758 bool BytecodeEmitter::emitStringOp(JSOp op
, GCThingIndex atomIndex
) {
759 MOZ_ASSERT(JOF_OPTYPE(op
) == JOF_STRING
);
760 return emitGCIndexOp(op
, atomIndex
);
763 bool BytecodeEmitter::emitInternedScopeOp(GCThingIndex index
, JSOp op
) {
764 MOZ_ASSERT(JOF_OPTYPE(op
) == JOF_SCOPE
);
765 MOZ_ASSERT(index
< perScriptData().gcThingList().length());
766 return emitGCIndexOp(op
, index
);
769 bool BytecodeEmitter::emitInternedObjectOp(GCThingIndex index
, JSOp op
) {
770 MOZ_ASSERT(JOF_OPTYPE(op
) == JOF_OBJECT
);
771 MOZ_ASSERT(index
< perScriptData().gcThingList().length());
772 return emitGCIndexOp(op
, index
);
775 bool BytecodeEmitter::emitRegExp(GCThingIndex index
) {
776 return emitGCIndexOp(JSOp::RegExp
, index
);
779 bool BytecodeEmitter::emitLocalOp(JSOp op
, uint32_t slot
) {
780 MOZ_ASSERT(JOF_OPTYPE(op
) != JOF_ENVCOORD
);
781 MOZ_ASSERT(IsLocalOp(op
));
784 if (!emitN(op
, LOCALNO_LEN
, &off
)) {
788 SET_LOCALNO(bytecodeSection().code(off
), slot
);
792 bool BytecodeEmitter::emitArgOp(JSOp op
, uint16_t slot
) {
793 MOZ_ASSERT(IsArgOp(op
));
795 if (!emitN(op
, ARGNO_LEN
, &off
)) {
799 SET_ARGNO(bytecodeSection().code(off
), slot
);
803 bool BytecodeEmitter::emitEnvCoordOp(JSOp op
, EnvironmentCoordinate ec
) {
804 MOZ_ASSERT(JOF_OPTYPE(op
) == JOF_ENVCOORD
||
805 JOF_OPTYPE(op
) == JOF_DEBUGCOORD
);
807 constexpr size_t N
= ENVCOORD_HOPS_LEN
+ ENVCOORD_SLOT_LEN
;
808 MOZ_ASSERT(GetOpLength(op
) == 1 + N
);
811 if (!emitN(op
, N
, &off
)) {
815 jsbytecode
* pc
= bytecodeSection().code(off
);
816 SET_ENVCOORD_HOPS(pc
, ec
.hops());
817 pc
+= ENVCOORD_HOPS_LEN
;
818 SET_ENVCOORD_SLOT(pc
, ec
.slot());
819 pc
+= ENVCOORD_SLOT_LEN
;
823 JSOp
BytecodeEmitter::strictifySetNameOp(JSOp op
) {
827 op
= JSOp::StrictSetName
;
832 op
= JSOp::StrictSetGName
;
840 bool BytecodeEmitter::checkSideEffects(ParseNode
* pn
, bool* answer
) {
841 AutoCheckRecursionLimit
recursion(fc
);
842 if (!recursion
.check(fc
)) {
848 switch (pn
->getKind()) {
849 // Trivial cases with no side effects.
850 case ParseNodeKind::EmptyStmt
:
851 case ParseNodeKind::TrueExpr
:
852 case ParseNodeKind::FalseExpr
:
853 case ParseNodeKind::NullExpr
:
854 case ParseNodeKind::RawUndefinedExpr
:
855 case ParseNodeKind::Elision
:
856 case ParseNodeKind::Generator
:
857 MOZ_ASSERT(pn
->is
<NullaryNode
>());
861 case ParseNodeKind::ObjectPropertyName
:
862 case ParseNodeKind::PrivateName
: // no side effects, unlike
863 // ParseNodeKind::Name
864 case ParseNodeKind::StringExpr
:
865 case ParseNodeKind::TemplateStringExpr
:
866 MOZ_ASSERT(pn
->is
<NameNode
>());
870 case ParseNodeKind::RegExpExpr
:
871 MOZ_ASSERT(pn
->is
<RegExpLiteral
>());
875 case ParseNodeKind::NumberExpr
:
876 MOZ_ASSERT(pn
->is
<NumericLiteral
>());
880 case ParseNodeKind::BigIntExpr
:
881 MOZ_ASSERT(pn
->is
<BigIntLiteral
>());
885 // |this| can throw in derived class constructors, including nested arrow
886 // functions or eval.
887 case ParseNodeKind::ThisExpr
:
888 MOZ_ASSERT(pn
->is
<UnaryNode
>());
889 *answer
= sc
->needsThisTDZChecks();
892 // |new.target| doesn't have any side-effects.
893 case ParseNodeKind::NewTargetExpr
: {
894 MOZ_ASSERT(pn
->is
<NewTargetNode
>());
899 // Trivial binary nodes with more token pos holders.
900 case ParseNodeKind::ImportMetaExpr
: {
901 MOZ_ASSERT(pn
->as
<BinaryNode
>().left()->isKind(ParseNodeKind::PosHolder
));
903 pn
->as
<BinaryNode
>().right()->isKind(ParseNodeKind::PosHolder
));
908 case ParseNodeKind::BreakStmt
:
909 MOZ_ASSERT(pn
->is
<BreakStatement
>());
913 case ParseNodeKind::ContinueStmt
:
914 MOZ_ASSERT(pn
->is
<ContinueStatement
>());
918 case ParseNodeKind::DebuggerStmt
:
919 MOZ_ASSERT(pn
->is
<DebuggerStatement
>());
923 // Watch out for getters!
924 case ParseNodeKind::OptionalDotExpr
:
925 case ParseNodeKind::DotExpr
:
926 MOZ_ASSERT(pn
->is
<BinaryNode
>());
930 // Unary cases with side effects only if the child has them.
931 case ParseNodeKind::TypeOfExpr
:
932 case ParseNodeKind::VoidExpr
:
933 case ParseNodeKind::NotExpr
:
934 return checkSideEffects(pn
->as
<UnaryNode
>().kid(), answer
);
936 // Even if the name expression is effect-free, performing ToPropertyKey on
937 // it might not be effect-free:
939 // RegExp.prototype.toString = () => { throw 42; };
940 // ({ [/regex/]: 0 }); // ToPropertyKey(/regex/) throws 42
943 // ({ [new.target]: 0 });
945 // Q.toString = () => { throw 17; };
946 // new Q; // new.target will be Q, ToPropertyKey(Q) throws 17
947 case ParseNodeKind::ComputedName
:
948 MOZ_ASSERT(pn
->is
<UnaryNode
>());
952 // Looking up or evaluating the associated name could throw.
953 case ParseNodeKind::TypeOfNameExpr
:
954 MOZ_ASSERT(pn
->is
<UnaryNode
>());
958 // This unary case has side effects on the enclosing object, sure. But
959 // that's not the question this function answers: it's whether the
960 // operation may have a side effect on something *other* than the result
961 // of the overall operation in which it's embedded. The answer to that
962 // is no, because an object literal having a mutated prototype only
963 // produces a value, without affecting anything else.
964 case ParseNodeKind::MutateProto
:
965 return checkSideEffects(pn
->as
<UnaryNode
>().kid(), answer
);
967 // Unary cases with obvious side effects.
968 case ParseNodeKind::PreIncrementExpr
:
969 case ParseNodeKind::PostIncrementExpr
:
970 case ParseNodeKind::PreDecrementExpr
:
971 case ParseNodeKind::PostDecrementExpr
:
972 case ParseNodeKind::ThrowStmt
:
973 MOZ_ASSERT(pn
->is
<UnaryNode
>());
977 // These might invoke valueOf/toString, even with a subexpression without
978 // side effects! Consider |+{ valueOf: null, toString: null }|.
979 case ParseNodeKind::BitNotExpr
:
980 case ParseNodeKind::PosExpr
:
981 case ParseNodeKind::NegExpr
:
982 MOZ_ASSERT(pn
->is
<UnaryNode
>());
986 // This invokes the (user-controllable) iterator protocol.
987 case ParseNodeKind::Spread
:
988 MOZ_ASSERT(pn
->is
<UnaryNode
>());
992 case ParseNodeKind::InitialYield
:
993 case ParseNodeKind::YieldStarExpr
:
994 case ParseNodeKind::YieldExpr
:
995 case ParseNodeKind::AwaitExpr
:
996 MOZ_ASSERT(pn
->is
<UnaryNode
>());
1000 // Deletion generally has side effects, even if isolated cases have none.
1001 case ParseNodeKind::DeleteNameExpr
:
1002 case ParseNodeKind::DeletePropExpr
:
1003 case ParseNodeKind::DeleteElemExpr
:
1004 case ParseNodeKind::DeleteOptionalChainExpr
:
1005 MOZ_ASSERT(pn
->is
<UnaryNode
>());
1009 // Deletion of a non-Reference expression has side effects only through
1010 // evaluating the expression.
1011 case ParseNodeKind::DeleteExpr
: {
1012 ParseNode
* expr
= pn
->as
<UnaryNode
>().kid();
1013 return checkSideEffects(expr
, answer
);
1016 case ParseNodeKind::ExpressionStmt
:
1017 return checkSideEffects(pn
->as
<UnaryNode
>().kid(), answer
);
1019 // Binary cases with obvious side effects.
1020 case ParseNodeKind::InitExpr
:
1024 case ParseNodeKind::AssignExpr
:
1025 case ParseNodeKind::AddAssignExpr
:
1026 case ParseNodeKind::SubAssignExpr
:
1027 case ParseNodeKind::CoalesceAssignExpr
:
1028 case ParseNodeKind::OrAssignExpr
:
1029 case ParseNodeKind::AndAssignExpr
:
1030 case ParseNodeKind::BitOrAssignExpr
:
1031 case ParseNodeKind::BitXorAssignExpr
:
1032 case ParseNodeKind::BitAndAssignExpr
:
1033 case ParseNodeKind::LshAssignExpr
:
1034 case ParseNodeKind::RshAssignExpr
:
1035 case ParseNodeKind::UrshAssignExpr
:
1036 case ParseNodeKind::MulAssignExpr
:
1037 case ParseNodeKind::DivAssignExpr
:
1038 case ParseNodeKind::ModAssignExpr
:
1039 case ParseNodeKind::PowAssignExpr
:
1040 MOZ_ASSERT(pn
->is
<AssignmentNode
>());
1044 case ParseNodeKind::SetThis
:
1045 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1049 case ParseNodeKind::StatementList
:
1050 // Strict equality operations and short circuit operators are well-behaved
1051 // and perform no conversions.
1052 case ParseNodeKind::CoalesceExpr
:
1053 case ParseNodeKind::OrExpr
:
1054 case ParseNodeKind::AndExpr
:
1055 case ParseNodeKind::StrictEqExpr
:
1056 case ParseNodeKind::StrictNeExpr
:
1057 // Any subexpression of a comma expression could be effectful.
1058 case ParseNodeKind::CommaExpr
:
1059 MOZ_ASSERT(!pn
->as
<ListNode
>().empty());
1061 // Subcomponents of a literal may be effectful.
1062 case ParseNodeKind::ArrayExpr
:
1063 case ParseNodeKind::ObjectExpr
:
1064 for (ParseNode
* item
: pn
->as
<ListNode
>().contents()) {
1065 if (!checkSideEffects(item
, answer
)) {
1074 #ifdef ENABLE_RECORD_TUPLE
1075 case ParseNodeKind::RecordExpr
:
1076 case ParseNodeKind::TupleExpr
:
1077 MOZ_CRASH("Record and Tuple are not supported yet");
1080 #ifdef ENABLE_DECORATORS
1081 case ParseNodeKind::DecoratorList
:
1082 MOZ_CRASH("Decorators are not supported yet");
1085 // Most other binary operations (parsed as lists in SpiderMonkey) may
1086 // perform conversions triggering side effects. Math operations perform
1087 // ToNumber and may fail invoking invalid user-defined toString/valueOf:
1088 // |5 < { toString: null }|. |instanceof| throws if provided a
1089 // non-object constructor: |null instanceof null|. |in| throws if given
1090 // a non-object RHS: |5 in null|.
1091 case ParseNodeKind::BitOrExpr
:
1092 case ParseNodeKind::BitXorExpr
:
1093 case ParseNodeKind::BitAndExpr
:
1094 case ParseNodeKind::EqExpr
:
1095 case ParseNodeKind::NeExpr
:
1096 case ParseNodeKind::LtExpr
:
1097 case ParseNodeKind::LeExpr
:
1098 case ParseNodeKind::GtExpr
:
1099 case ParseNodeKind::GeExpr
:
1100 case ParseNodeKind::InstanceOfExpr
:
1101 case ParseNodeKind::InExpr
:
1102 case ParseNodeKind::PrivateInExpr
:
1103 case ParseNodeKind::LshExpr
:
1104 case ParseNodeKind::RshExpr
:
1105 case ParseNodeKind::UrshExpr
:
1106 case ParseNodeKind::AddExpr
:
1107 case ParseNodeKind::SubExpr
:
1108 case ParseNodeKind::MulExpr
:
1109 case ParseNodeKind::DivExpr
:
1110 case ParseNodeKind::ModExpr
:
1111 case ParseNodeKind::PowExpr
:
1112 MOZ_ASSERT(pn
->as
<ListNode
>().count() >= 2);
1116 case ParseNodeKind::PropertyDefinition
:
1117 case ParseNodeKind::Case
: {
1118 BinaryNode
* node
= &pn
->as
<BinaryNode
>();
1119 if (!checkSideEffects(node
->left(), answer
)) {
1125 return checkSideEffects(node
->right(), answer
);
1129 case ParseNodeKind::ElemExpr
:
1130 case ParseNodeKind::OptionalElemExpr
:
1131 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1135 // Throws if the operand is not of the right class. Can also call a private
1137 case ParseNodeKind::PrivateMemberExpr
:
1138 case ParseNodeKind::OptionalPrivateMemberExpr
:
1142 // These affect visible names in this code, or in other code.
1143 case ParseNodeKind::ImportDecl
:
1144 case ParseNodeKind::ExportFromStmt
:
1145 case ParseNodeKind::ExportDefaultStmt
:
1146 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1151 case ParseNodeKind::ExportStmt
:
1152 MOZ_ASSERT(pn
->is
<UnaryNode
>());
1156 case ParseNodeKind::CallImportExpr
:
1157 case ParseNodeKind::CallImportSpec
:
1158 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1162 // Every part of a loop might be effect-free, but looping infinitely *is*
1163 // an effect. (Language lawyer trivia: C++ says threads can be assumed
1164 // to exit or have side effects, C++14 [intro.multithread]p27, so a C++
1165 // implementation's equivalent of the below could set |*answer = false;|
1166 // if all loop sub-nodes set |*answer = false|!)
1167 case ParseNodeKind::DoWhileStmt
:
1168 case ParseNodeKind::WhileStmt
:
1169 case ParseNodeKind::ForStmt
:
1170 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1174 // Declarations affect the name set of the relevant scope.
1175 case ParseNodeKind::VarStmt
:
1176 case ParseNodeKind::ConstDecl
:
1177 case ParseNodeKind::LetDecl
:
1178 MOZ_ASSERT(pn
->is
<ListNode
>());
1182 case ParseNodeKind::IfStmt
:
1183 case ParseNodeKind::ConditionalExpr
: {
1184 TernaryNode
* node
= &pn
->as
<TernaryNode
>();
1185 if (!checkSideEffects(node
->kid1(), answer
)) {
1191 if (!checkSideEffects(node
->kid2(), answer
)) {
1197 if ((pn
= node
->kid3())) {
1203 // Function calls can invoke non-local code.
1204 case ParseNodeKind::NewExpr
:
1205 case ParseNodeKind::CallExpr
:
1206 case ParseNodeKind::OptionalCallExpr
:
1207 case ParseNodeKind::TaggedTemplateExpr
:
1208 case ParseNodeKind::SuperCallExpr
:
1209 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1213 // Function arg lists can contain arbitrary expressions. Technically
1214 // this only causes side-effects if one of the arguments does, but since
1215 // the call being made will always trigger side-effects, it isn't needed.
1216 case ParseNodeKind::Arguments
:
1217 MOZ_ASSERT(pn
->is
<ListNode
>());
1221 case ParseNodeKind::OptionalChain
:
1222 MOZ_ASSERT(pn
->is
<UnaryNode
>());
1226 // Classes typically introduce names. Even if no name is introduced,
1227 // the heritage and/or class body (through computed property names)
1228 // usually have effects.
1229 case ParseNodeKind::ClassDecl
:
1230 MOZ_ASSERT(pn
->is
<ClassNode
>());
1234 // |with| calls |ToObject| on its expression and so throws if that value
1235 // is null/undefined.
1236 case ParseNodeKind::WithStmt
:
1237 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1241 case ParseNodeKind::ReturnStmt
:
1242 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1246 case ParseNodeKind::Name
:
1247 MOZ_ASSERT(pn
->is
<NameNode
>());
1251 // Shorthands could trigger getters: the |x| in the object literal in
1252 // |with ({ get x() { throw 42; } }) ({ x });|, for example, triggers
1253 // one. (Of course, it isn't necessary to use |with| for a shorthand to
1254 // trigger a getter.)
1255 case ParseNodeKind::Shorthand
:
1256 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1260 case ParseNodeKind::Function
:
1261 MOZ_ASSERT(pn
->is
<FunctionNode
>());
1263 * A named function, contrary to ES3, is no longer effectful, because
1264 * we bind its name lexically (using JSOp::Callee) instead of creating
1265 * an Object instance and binding a readonly, permanent property in it
1266 * (the object and binding can be detected and hijacked or captured).
1267 * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
1272 case ParseNodeKind::Module
:
1276 case ParseNodeKind::TryStmt
: {
1277 TryNode
* tryNode
= &pn
->as
<TryNode
>();
1278 if (!checkSideEffects(tryNode
->body(), answer
)) {
1284 if (LexicalScopeNode
* catchScope
= tryNode
->catchScope()) {
1285 if (!checkSideEffects(catchScope
, answer
)) {
1292 if (ParseNode
* finallyBlock
= tryNode
->finallyBlock()) {
1293 if (!checkSideEffects(finallyBlock
, answer
)) {
1300 case ParseNodeKind::Catch
: {
1301 BinaryNode
* catchClause
= &pn
->as
<BinaryNode
>();
1302 if (ParseNode
* name
= catchClause
->left()) {
1303 if (!checkSideEffects(name
, answer
)) {
1310 return checkSideEffects(catchClause
->right(), answer
);
1313 case ParseNodeKind::SwitchStmt
: {
1314 SwitchStatement
* switchStmt
= &pn
->as
<SwitchStatement
>();
1315 if (!checkSideEffects(&switchStmt
->discriminant(), answer
)) {
1319 checkSideEffects(&switchStmt
->lexicalForCaseList(), answer
);
1322 case ParseNodeKind::LabelStmt
:
1323 return checkSideEffects(pn
->as
<LabeledStatement
>().statement(), answer
);
1325 case ParseNodeKind::LexicalScope
:
1326 return checkSideEffects(pn
->as
<LexicalScopeNode
>().scopeBody(), answer
);
1328 // We could methodically check every interpolated expression, but it's
1329 // probably not worth the trouble. Treat template strings as effect-free
1330 // only if they don't contain any substitutions.
1331 case ParseNodeKind::TemplateStringListExpr
: {
1332 ListNode
* list
= &pn
->as
<ListNode
>();
1333 MOZ_ASSERT(!list
->empty());
1334 MOZ_ASSERT((list
->count() % 2) == 1,
1335 "template strings must alternate template and substitution "
1337 *answer
= list
->count() > 1;
1341 // This should be unreachable but is left as-is for now.
1342 case ParseNodeKind::ParamsBody
:
1346 case ParseNodeKind::ForIn
: // by ParseNodeKind::For
1347 case ParseNodeKind::ForOf
: // by ParseNodeKind::For
1348 case ParseNodeKind::ForHead
: // by ParseNodeKind::For
1349 case ParseNodeKind::DefaultConstructor
: // by ParseNodeKind::ClassDecl
1350 case ParseNodeKind::ClassBodyScope
: // by ParseNodeKind::ClassDecl
1351 case ParseNodeKind::ClassMethod
: // by ParseNodeKind::ClassDecl
1352 case ParseNodeKind::ClassField
: // by ParseNodeKind::ClassDecl
1353 case ParseNodeKind::ClassNames
: // by ParseNodeKind::ClassDecl
1354 case ParseNodeKind::StaticClassBlock
: // by ParseNodeKind::ClassDecl
1355 case ParseNodeKind::ClassMemberList
: // by ParseNodeKind::ClassDecl
1356 case ParseNodeKind::ImportSpecList
: // by ParseNodeKind::Import
1357 case ParseNodeKind::ImportSpec
: // by ParseNodeKind::Import
1358 case ParseNodeKind::ImportNamespaceSpec
: // by ParseNodeKind::Import
1359 case ParseNodeKind::ImportAssertion
: // by ParseNodeKind::Import
1360 case ParseNodeKind::ImportAssertionList
: // by ParseNodeKind::Import
1361 case ParseNodeKind::ImportModuleRequest
: // by ParseNodeKind::Import
1362 case ParseNodeKind::ExportBatchSpecStmt
: // by ParseNodeKind::Export
1363 case ParseNodeKind::ExportSpecList
: // by ParseNodeKind::Export
1364 case ParseNodeKind::ExportSpec
: // by ParseNodeKind::Export
1365 case ParseNodeKind::ExportNamespaceSpec
: // by ParseNodeKind::Export
1366 case ParseNodeKind::CallSiteObj
: // by ParseNodeKind::TaggedTemplate
1367 case ParseNodeKind::PosHolder
: // by ParseNodeKind::NewTarget
1368 case ParseNodeKind::SuperBase
: // by ParseNodeKind::Elem and others
1369 case ParseNodeKind::PropertyNameExpr
: // by ParseNodeKind::Dot
1370 MOZ_CRASH("handled by parent nodes");
1372 case ParseNodeKind::LastUnused
:
1373 case ParseNodeKind::Limit
:
1374 MOZ_CRASH("invalid node kind");
1378 "invalid, unenumerated ParseNodeKind value encountered in "
1379 "BytecodeEmitter::checkSideEffects");
1382 bool BytecodeEmitter::isInLoop() {
1383 return findInnermostNestableControl
<LoopControl
>();
1386 bool BytecodeEmitter::checkSingletonContext() {
1387 MOZ_ASSERT_IF(sc
->treatAsRunOnce(), sc
->isTopLevelContext());
1388 return sc
->treatAsRunOnce() && !isInLoop();
1391 bool BytecodeEmitter::needsImplicitThis() {
1392 // Short-circuit if there is an enclosing 'with' scope.
1397 // Otherwise see if the current point is under a 'with'.
1398 for (EmitterScope
* es
= innermostEmitterScope(); es
;
1399 es
= es
->enclosingInFrame()) {
1400 if (es
->scope(this).kind() == ScopeKind::With
) {
1408 size_t BytecodeEmitter::countThisEnvironmentHops() {
1409 unsigned numHops
= 0;
1411 for (BytecodeEmitter
* current
= this; current
; current
= current
->parent
) {
1412 for (EmitterScope
* es
= current
->innermostEmitterScope(); es
;
1413 es
= es
->enclosingInFrame()) {
1414 if (es
->scope(current
).is
<FunctionScope
>()) {
1415 if (!es
->scope(current
).isArrow()) {
1416 // The Parser is responsible for marking the environment as either
1417 // closed-over or used-by-eval which ensure that is must exist.
1418 MOZ_ASSERT(es
->scope(current
).hasEnvironment());
1422 if (es
->scope(current
).hasEnvironment()) {
1428 // The "this" environment exists outside of the compilation, but the
1429 // `ScopeContext` recorded the number of additional hops needed, so add
1431 MOZ_ASSERT(sc
->allowSuperProperty());
1432 numHops
+= compilationState
.scopeContext
.enclosingThisEnvironmentHops
;
1436 bool BytecodeEmitter::emitThisEnvironmentCallee() {
1437 // Get the innermost enclosing function that has a |this| binding.
1439 // Directly load callee from the frame if possible.
1440 if (sc
->isFunctionBox() && !sc
->asFunctionBox()->isArrow()) {
1441 return emit1(JSOp::Callee
);
1444 // We have to load the callee from the environment chain.
1445 size_t numHops
= countThisEnvironmentHops();
1448 ENVCOORD_HOPS_LIMIT
- 1 <= UINT8_MAX
,
1449 "JSOp::EnvCallee operand size should match ENVCOORD_HOPS_LIMIT");
1451 MOZ_ASSERT(numHops
< ENVCOORD_HOPS_LIMIT
- 1);
1453 return emit2(JSOp::EnvCallee
, numHops
);
1456 bool BytecodeEmitter::emitSuperBase() {
1457 if (!emitThisEnvironmentCallee()) {
1461 return emit1(JSOp::SuperBase
);
1464 void BytecodeEmitter::reportError(ParseNode
* pn
, unsigned errorNumber
, ...) {
1465 uint32_t offset
= pn
? pn
->pn_pos
.begin
: *scriptStartOffset
;
1468 va_start(args
, errorNumber
);
1470 errorReporter().errorWithNotesAtVA(nullptr, AsVariant(offset
), errorNumber
,
1476 void BytecodeEmitter::reportError(uint32_t offset
, unsigned errorNumber
, ...) {
1478 va_start(args
, errorNumber
);
1480 errorReporter().errorWithNotesAtVA(nullptr, AsVariant(offset
), errorNumber
,
1486 bool BytecodeEmitter::addObjLiteralData(ObjLiteralWriter
& writer
,
1487 GCThingIndex
* outIndex
) {
1488 if (!writer
.checkForDuplicatedNames(fc
)) {
1492 size_t len
= writer
.getCode().size();
1493 auto* code
= compilationState
.alloc
.newArrayUninitialized
<uint8_t>(len
);
1495 js::ReportOutOfMemory(fc
);
1498 memcpy(code
, writer
.getCode().data(), len
);
1500 ObjLiteralIndex
objIndex(compilationState
.objLiteralData
.length());
1501 if (uint32_t(objIndex
) >= TaggedScriptThingIndex::IndexLimit
) {
1502 ReportAllocationOverflow(fc
);
1505 if (!compilationState
.objLiteralData
.emplaceBack(code
, len
, writer
.getKind(),
1507 writer
.getPropertyCount())) {
1508 js::ReportOutOfMemory(fc
);
1512 return perScriptData().gcThingList().append(objIndex
, outIndex
);
1515 bool BytecodeEmitter::emitPrepareIteratorResult() {
1516 constexpr JSOp op
= JSOp::NewObject
;
1518 ObjLiteralWriter writer
;
1519 writer
.beginShape(op
);
1521 writer
.setPropNameNoDuplicateCheck(parserAtoms(),
1522 TaggedParserAtomIndex::WellKnown::value());
1523 if (!writer
.propWithUndefinedValue(fc
)) {
1526 writer
.setPropNameNoDuplicateCheck(parserAtoms(),
1527 TaggedParserAtomIndex::WellKnown::done());
1528 if (!writer
.propWithUndefinedValue(fc
)) {
1533 if (!addObjLiteralData(writer
, &shape
)) {
1537 return emitGCIndexOp(op
, shape
);
1540 bool BytecodeEmitter::emitFinishIteratorResult(bool done
) {
1541 if (!emitAtomOp(JSOp::InitProp
, TaggedParserAtomIndex::WellKnown::value())) {
1544 if (!emit1(done
? JSOp::True
: JSOp::False
)) {
1547 if (!emitAtomOp(JSOp::InitProp
, TaggedParserAtomIndex::WellKnown::done())) {
1553 bool BytecodeEmitter::emitGetNameAtLocation(TaggedParserAtomIndex name
,
1554 const NameLocation
& loc
) {
1555 NameOpEmitter
noe(this, name
, loc
, NameOpEmitter::Kind::Get
);
1556 if (!noe
.emitGet()) {
1563 bool BytecodeEmitter::emitGetName(NameNode
* name
) {
1564 MOZ_ASSERT(name
->isKind(ParseNodeKind::Name
));
1566 return emitGetName(name
->name());
1569 bool BytecodeEmitter::emitGetPrivateName(NameNode
* name
) {
1570 MOZ_ASSERT(name
->isKind(ParseNodeKind::PrivateName
));
1571 return emitGetPrivateName(name
->name());
1574 bool BytecodeEmitter::emitGetPrivateName(TaggedParserAtomIndex nameAtom
) {
1575 // The parser ensures the private name is present on the environment chain,
1576 // but its location can be Dynamic or Global when emitting debugger
1577 // eval-in-frame code.
1578 NameLocation location
= lookupName(nameAtom
);
1579 MOZ_ASSERT(location
.kind() == NameLocation::Kind::FrameSlot
||
1580 location
.kind() == NameLocation::Kind::EnvironmentCoordinate
||
1581 location
.kind() == NameLocation::Kind::Dynamic
||
1582 location
.kind() == NameLocation::Kind::Global
);
1584 return emitGetNameAtLocation(nameAtom
, location
);
1587 bool BytecodeEmitter::emitTDZCheckIfNeeded(TaggedParserAtomIndex name
,
1588 const NameLocation
& loc
,
1589 ValueIsOnStack isOnStack
) {
1590 // Dynamic accesses have TDZ checks built into their VM code and should
1591 // never emit explicit TDZ checks.
1592 MOZ_ASSERT(loc
.hasKnownSlot());
1593 MOZ_ASSERT(loc
.isLexical() || loc
.isPrivateMethod() || loc
.isSynthetic());
1595 // Private names are implemented as lexical bindings, but it's just an
1596 // implementation detail. Per spec there's no TDZ check when using them.
1597 if (parserAtoms().isPrivateName(name
)) {
1601 Maybe
<MaybeCheckTDZ
> check
=
1602 innermostTDZCheckCache
->needsTDZCheck(this, name
);
1607 // We've already emitted a check in this basic block.
1608 if (*check
== DontCheckTDZ
) {
1612 // If the value is not on the stack, we have to load it first.
1613 if (isOnStack
== ValueIsOnStack::No
) {
1614 if (loc
.kind() == NameLocation::Kind::FrameSlot
) {
1615 if (!emitLocalOp(JSOp::GetLocal
, loc
.frameSlot())) {
1619 if (!emitEnvCoordOp(JSOp::GetAliasedVar
, loc
.environmentCoordinate())) {
1625 // Emit the lexical check.
1626 if (loc
.kind() == NameLocation::Kind::FrameSlot
) {
1627 if (!emitLocalOp(JSOp::CheckLexical
, loc
.frameSlot())) {
1631 if (!emitEnvCoordOp(JSOp::CheckAliasedLexical
,
1632 loc
.environmentCoordinate())) {
1637 // Pop the value if needed.
1638 if (isOnStack
== ValueIsOnStack::No
) {
1639 if (!emit1(JSOp::Pop
)) {
1644 return innermostTDZCheckCache
->noteTDZCheck(this, name
, DontCheckTDZ
);
1647 bool BytecodeEmitter::emitPropLHS(PropertyAccess
* prop
) {
1648 MOZ_ASSERT(!prop
->isSuper());
1650 ParseNode
* expr
= &prop
->expression();
1652 if (!expr
->is
<PropertyAccess
>() || expr
->as
<PropertyAccess
>().isSuper()) {
1653 // The non-optimized case.
1654 return emitTree(expr
);
1657 // If the object operand is also a dotted property reference, reverse the
1658 // list linked via expression() temporarily so we can iterate over it from
1659 // the bottom up (reversing again as we go), to avoid excessive recursion.
1660 PropertyAccess
* pndot
= &expr
->as
<PropertyAccess
>();
1661 ParseNode
* pnup
= nullptr;
1664 // Reverse pndot->expression() to point up, not down.
1665 pndown
= &pndot
->expression();
1666 pndot
->setExpression(pnup
);
1667 if (!pndown
->is
<PropertyAccess
>() ||
1668 pndown
->as
<PropertyAccess
>().isSuper()) {
1672 pndot
= &pndown
->as
<PropertyAccess
>();
1675 // pndown is a primary expression, not a dotted property reference.
1676 if (!emitTree(pndown
)) {
1681 // Walk back up the list, emitting annotated name ops.
1682 if (!emitAtomOp(JSOp::GetProp
, pndot
->key().atom())) {
1686 // Reverse the pndot->expression() link again.
1687 pnup
= pndot
->maybeExpression();
1688 pndot
->setExpression(pndown
);
1693 pndot
= &pnup
->as
<PropertyAccess
>();
1698 bool BytecodeEmitter::emitPropIncDec(UnaryNode
* incDec
, ValueUsage valueUsage
) {
1699 PropertyAccess
* prop
= &incDec
->kid()->as
<PropertyAccess
>();
1700 bool isSuper
= prop
->isSuper();
1701 ParseNodeKind kind
= incDec
->getKind();
1704 kind
== ParseNodeKind::PostIncrementExpr
1705 ? PropOpEmitter::Kind::PostIncrement
1706 : kind
== ParseNodeKind::PreIncrementExpr
1707 ? PropOpEmitter::Kind::PreIncrement
1708 : kind
== ParseNodeKind::PostDecrementExpr
1709 ? PropOpEmitter::Kind::PostDecrement
1710 : PropOpEmitter::Kind::PreDecrement
,
1711 isSuper
? PropOpEmitter::ObjKind::Super
: PropOpEmitter::ObjKind::Other
);
1712 if (!poe
.prepareForObj()) {
1716 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
1717 if (!emitGetThisForSuperBase(base
)) {
1722 if (!emitPropLHS(prop
)) {
1727 if (!poe
.emitIncDec(prop
->key().atom(), valueUsage
)) {
1735 bool BytecodeEmitter::emitNameIncDec(UnaryNode
* incDec
, ValueUsage valueUsage
) {
1736 MOZ_ASSERT(incDec
->kid()->isKind(ParseNodeKind::Name
));
1738 ParseNodeKind kind
= incDec
->getKind();
1739 NameNode
* name
= &incDec
->kid()->as
<NameNode
>();
1740 NameOpEmitter
noe(this, name
->atom(),
1741 kind
== ParseNodeKind::PostIncrementExpr
1742 ? NameOpEmitter::Kind::PostIncrement
1743 : kind
== ParseNodeKind::PreIncrementExpr
1744 ? NameOpEmitter::Kind::PreIncrement
1745 : kind
== ParseNodeKind::PostDecrementExpr
1746 ? NameOpEmitter::Kind::PostDecrement
1747 : NameOpEmitter::Kind::PreDecrement
);
1748 if (!noe
.emitIncDec(valueUsage
)) {
1755 bool BytecodeEmitter::emitObjAndKey(ParseNode
* exprOrSuper
, ParseNode
* key
,
1756 ElemOpEmitter
& eoe
) {
1757 if (exprOrSuper
->isKind(ParseNodeKind::SuperBase
)) {
1758 if (!eoe
.prepareForObj()) {
1762 UnaryNode
* base
= &exprOrSuper
->as
<UnaryNode
>();
1763 if (!emitGetThisForSuperBase(base
)) {
1767 if (!eoe
.prepareForKey()) {
1771 if (!emitTree(key
)) {
1779 if (!eoe
.prepareForObj()) {
1783 if (!emitTree(exprOrSuper
)) {
1787 if (!eoe
.prepareForKey()) {
1791 if (!emitTree(key
)) {
1792 // [stack] OBJ? OBJ KEY
1799 bool BytecodeEmitter::emitElemOpBase(JSOp op
) {
1807 bool BytecodeEmitter::emitElemObjAndKey(PropertyByValue
* elem
, bool isSuper
,
1808 ElemOpEmitter
& eoe
) {
1809 MOZ_ASSERT(isSuper
== elem
->expression().isKind(ParseNodeKind::SuperBase
));
1810 return emitObjAndKey(&elem
->expression(), &elem
->key(), eoe
);
1813 static ElemOpEmitter::Kind
ConvertIncDecKind(ParseNodeKind kind
) {
1815 case ParseNodeKind::PostIncrementExpr
:
1816 return ElemOpEmitter::Kind::PostIncrement
;
1817 case ParseNodeKind::PreIncrementExpr
:
1818 return ElemOpEmitter::Kind::PreIncrement
;
1819 case ParseNodeKind::PostDecrementExpr
:
1820 return ElemOpEmitter::Kind::PostDecrement
;
1821 case ParseNodeKind::PreDecrementExpr
:
1822 return ElemOpEmitter::Kind::PreDecrement
;
1824 MOZ_CRASH("unexpected inc/dec node kind");
1828 static PrivateOpEmitter::Kind
PrivateConvertIncDecKind(ParseNodeKind kind
) {
1830 case ParseNodeKind::PostIncrementExpr
:
1831 return PrivateOpEmitter::Kind::PostIncrement
;
1832 case ParseNodeKind::PreIncrementExpr
:
1833 return PrivateOpEmitter::Kind::PreIncrement
;
1834 case ParseNodeKind::PostDecrementExpr
:
1835 return PrivateOpEmitter::Kind::PostDecrement
;
1836 case ParseNodeKind::PreDecrementExpr
:
1837 return PrivateOpEmitter::Kind::PreDecrement
;
1839 MOZ_CRASH("unexpected inc/dec node kind");
1843 bool BytecodeEmitter::emitElemIncDec(UnaryNode
* incDec
, ValueUsage valueUsage
) {
1844 PropertyByValue
* elemExpr
= &incDec
->kid()->as
<PropertyByValue
>();
1845 bool isSuper
= elemExpr
->isSuper();
1846 MOZ_ASSERT(!elemExpr
->key().isKind(ParseNodeKind::PrivateName
));
1847 ParseNodeKind kind
= incDec
->getKind();
1849 this, ConvertIncDecKind(kind
),
1850 isSuper
? ElemOpEmitter::ObjKind::Super
: ElemOpEmitter::ObjKind::Other
);
1851 if (!emitElemObjAndKey(elemExpr
, isSuper
, eoe
)) {
1852 // [stack] # if Super
1854 // [stack] # otherwise
1858 if (!eoe
.emitIncDec(valueUsage
)) {
1866 bool BytecodeEmitter::emitCallIncDec(UnaryNode
* incDec
) {
1867 MOZ_ASSERT(incDec
->isKind(ParseNodeKind::PreIncrementExpr
) ||
1868 incDec
->isKind(ParseNodeKind::PostIncrementExpr
) ||
1869 incDec
->isKind(ParseNodeKind::PreDecrementExpr
) ||
1870 incDec
->isKind(ParseNodeKind::PostDecrementExpr
));
1872 ParseNode
* call
= incDec
->kid();
1873 MOZ_ASSERT(call
->isKind(ParseNodeKind::CallExpr
));
1874 if (!emitTree(call
)) {
1875 // [stack] CALLRESULT
1878 if (!emit1(JSOp::ToNumeric
)) {
1883 // The increment/decrement has no side effects, so proceed to throw for
1884 // invalid assignment target.
1885 return emit2(JSOp::ThrowMsg
, uint8_t(ThrowMsgKind::AssignToCall
));
1888 bool BytecodeEmitter::emitPrivateIncDec(UnaryNode
* incDec
,
1889 ValueUsage valueUsage
) {
1890 PrivateMemberAccess
* privateExpr
= &incDec
->kid()->as
<PrivateMemberAccess
>();
1891 ParseNodeKind kind
= incDec
->getKind();
1892 PrivateOpEmitter
xoe(this, PrivateConvertIncDecKind(kind
),
1893 privateExpr
->privateName().name());
1894 if (!emitTree(&privateExpr
->expression())) {
1898 if (!xoe
.emitReference()) {
1902 if (!xoe
.emitIncDec(valueUsage
)) {
1910 bool BytecodeEmitter::emitDouble(double d
) {
1911 BytecodeOffset offset
;
1912 if (!emitCheck(JSOp::Double
, 9, &offset
)) {
1916 jsbytecode
* code
= bytecodeSection().code(offset
);
1917 code
[0] = jsbytecode(JSOp::Double
);
1918 SET_INLINE_VALUE(code
, DoubleValue(d
));
1919 bytecodeSection().updateDepth(JSOp::Double
, offset
);
1923 bool BytecodeEmitter::emitNumberOp(double dval
) {
1925 if (NumberIsInt32(dval
, &ival
)) {
1927 return emit1(JSOp::Zero
);
1930 return emit1(JSOp::One
);
1932 if ((int)(int8_t)ival
== ival
) {
1933 return emit2(JSOp::Int8
, uint8_t(int8_t(ival
)));
1936 uint32_t u
= uint32_t(ival
);
1938 if (!emitUint16Operand(JSOp::Uint16
, u
)) {
1941 } else if (u
< Bit(24)) {
1943 if (!emitN(JSOp::Uint24
, 3, &off
)) {
1946 SET_UINT24(bytecodeSection().code(off
), u
);
1949 if (!emitN(JSOp::Int32
, 4, &off
)) {
1952 SET_INT32(bytecodeSection().code(off
), ival
);
1957 return emitDouble(dval
);
1961 * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047.
1962 * LLVM is deciding to inline this function which uses a lot of stack space
1963 * into emitTree which is recursive and uses relatively little stack space.
1965 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitSwitch(SwitchStatement
* switchStmt
) {
1966 LexicalScopeNode
& lexical
= switchStmt
->lexicalForCaseList();
1967 MOZ_ASSERT(lexical
.isKind(ParseNodeKind::LexicalScope
));
1968 ListNode
* cases
= &lexical
.scopeBody()->as
<ListNode
>();
1969 MOZ_ASSERT(cases
->isKind(ParseNodeKind::StatementList
));
1971 SwitchEmitter
se(this);
1972 if (!se
.emitDiscriminant(switchStmt
->discriminant().pn_pos
.begin
)) {
1976 if (!markStepBreakpoint()) {
1979 if (!emitTree(&switchStmt
->discriminant())) {
1983 // Enter the scope before pushing the switch BreakableControl since all
1984 // breaks are under this scope.
1986 if (!lexical
.isEmptyScope()) {
1987 if (!se
.emitLexical(lexical
.scopeBindings())) {
1991 // A switch statement may contain hoisted functions inside its
1992 // cases. The hasTopLevelFunctionDeclarations flag is propagated from the
1993 // StatementList bodies of the cases to the case list.
1994 if (cases
->hasTopLevelFunctionDeclarations()) {
1995 for (ParseNode
* item
: cases
->contents()) {
1996 CaseClause
* caseClause
= &item
->as
<CaseClause
>();
1997 ListNode
* statements
= caseClause
->statementList();
1998 if (statements
->hasTopLevelFunctionDeclarations()) {
1999 if (!emitHoistedFunctionsInList(statements
)) {
2006 MOZ_ASSERT(!cases
->hasTopLevelFunctionDeclarations());
2009 SwitchEmitter::TableGenerator
tableGen(this);
2010 uint32_t caseCount
= cases
->count() - (switchStmt
->hasDefault() ? 1 : 0);
2011 if (caseCount
== 0) {
2014 for (ParseNode
* item
: cases
->contents()) {
2015 CaseClause
* caseClause
= &item
->as
<CaseClause
>();
2016 if (caseClause
->isDefault()) {
2020 ParseNode
* caseValue
= caseClause
->caseExpression();
2022 if (caseValue
->getKind() != ParseNodeKind::NumberExpr
) {
2023 tableGen
.setInvalid();
2028 if (!NumberEqualsInt32(caseValue
->as
<NumericLiteral
>().value(), &i
)) {
2029 tableGen
.setInvalid();
2033 if (!tableGen
.addNumber(i
)) {
2038 tableGen
.finish(caseCount
);
2041 if (!se
.validateCaseCount(caseCount
)) {
2045 bool isTableSwitch
= tableGen
.isValid();
2046 if (isTableSwitch
) {
2047 if (!se
.emitTable(tableGen
)) {
2051 if (!se
.emitCond()) {
2055 // Emit code for evaluating cases and jumping to case statements.
2056 for (ParseNode
* item
: cases
->contents()) {
2057 CaseClause
* caseClause
= &item
->as
<CaseClause
>();
2058 if (caseClause
->isDefault()) {
2062 if (!se
.prepareForCaseValue()) {
2066 ParseNode
* caseValue
= caseClause
->caseExpression();
2067 // If the expression is a literal, suppress line number emission so
2068 // that debugging works more naturally.
2070 caseValue
, ValueUsage::WantValue
,
2071 caseValue
->isLiteral() ? SUPPRESS_LINENOTE
: EMIT_LINENOTE
)) {
2075 if (!se
.emitCaseJump()) {
2081 // Emit code for each case's statements.
2082 for (ParseNode
* item
: cases
->contents()) {
2083 CaseClause
* caseClause
= &item
->as
<CaseClause
>();
2084 if (caseClause
->isDefault()) {
2085 if (!se
.emitDefaultBody()) {
2089 if (isTableSwitch
) {
2090 ParseNode
* caseValue
= caseClause
->caseExpression();
2091 MOZ_ASSERT(caseValue
->isKind(ParseNodeKind::NumberExpr
));
2093 NumericLiteral
* literal
= &caseValue
->as
<NumericLiteral
>();
2095 // Use NumberEqualsInt32 here because switches compare using
2096 // strict equality, which will equate -0 and +0. In contrast
2097 // NumberIsInt32 would return false for -0.
2099 MOZ_ASSERT(mozilla::NumberEqualsInt32(literal
->value(), &v
));
2101 int32_t i
= int32_t(literal
->value());
2103 if (!se
.emitCaseBody(i
, tableGen
)) {
2107 if (!se
.emitCaseBody()) {
2113 if (!emitTree(caseClause
->statementList())) {
2118 if (!se
.emitEnd()) {
2125 bool BytecodeEmitter::allocateResumeIndex(BytecodeOffset offset
,
2126 uint32_t* resumeIndex
) {
2127 static constexpr uint32_t MaxResumeIndex
= BitMask(24);
2130 MaxResumeIndex
< uint32_t(AbstractGeneratorObject::RESUME_INDEX_RUNNING
),
2131 "resumeIndex should not include magic AbstractGeneratorObject "
2132 "resumeIndex values");
2134 MaxResumeIndex
<= INT32_MAX
/ sizeof(uintptr_t),
2135 "resumeIndex * sizeof(uintptr_t) must fit in an int32. JIT code relies "
2136 "on this when loading resume entries from BaselineScript");
2138 *resumeIndex
= bytecodeSection().resumeOffsetList().length();
2139 if (*resumeIndex
> MaxResumeIndex
) {
2140 reportError(nullptr, JSMSG_TOO_MANY_RESUME_INDEXES
);
2144 return bytecodeSection().resumeOffsetList().append(offset
.value());
2147 bool BytecodeEmitter::allocateResumeIndexRange(
2148 mozilla::Span
<BytecodeOffset
> offsets
, uint32_t* firstResumeIndex
) {
2149 *firstResumeIndex
= 0;
2151 for (size_t i
= 0, len
= offsets
.size(); i
< len
; i
++) {
2152 uint32_t resumeIndex
;
2153 if (!allocateResumeIndex(offsets
[i
], &resumeIndex
)) {
2157 *firstResumeIndex
= resumeIndex
;
2164 bool BytecodeEmitter::emitYieldOp(JSOp op
) {
2165 if (op
== JSOp::FinalYieldRval
) {
2166 return emit1(JSOp::FinalYieldRval
);
2169 MOZ_ASSERT(op
== JSOp::InitialYield
|| op
== JSOp::Yield
||
2173 if (!emitN(op
, 3, &off
)) {
2177 if (op
== JSOp::InitialYield
|| op
== JSOp::Yield
) {
2178 bytecodeSection().addNumYields();
2181 uint32_t resumeIndex
;
2182 if (!allocateResumeIndex(bytecodeSection().offset(), &resumeIndex
)) {
2186 SET_RESUMEINDEX(bytecodeSection().code(off
), resumeIndex
);
2188 BytecodeOffset unusedOffset
;
2189 return emitJumpTargetOp(JSOp::AfterYield
, &unusedOffset
);
2192 bool BytecodeEmitter::emitPushResumeKind(GeneratorResumeKind kind
) {
2193 return emit2(JSOp::ResumeKind
, uint8_t(kind
));
2196 bool BytecodeEmitter::emitSetThis(BinaryNode
* setThisNode
) {
2197 // ParseNodeKind::SetThis is used to update |this| after a super() call
2198 // in a derived class constructor.
2200 MOZ_ASSERT(setThisNode
->isKind(ParseNodeKind::SetThis
));
2201 MOZ_ASSERT(setThisNode
->left()->isKind(ParseNodeKind::Name
));
2203 auto name
= setThisNode
->left()->as
<NameNode
>().name();
2205 // The 'this' binding is not lexical, but due to super() semantics this
2206 // initialization needs to be treated as a lexical one.
2207 NameLocation loc
= lookupName(name
);
2208 NameLocation lexicalLoc
;
2209 if (loc
.kind() == NameLocation::Kind::FrameSlot
) {
2210 lexicalLoc
= NameLocation::FrameSlot(BindingKind::Let
, loc
.frameSlot());
2211 } else if (loc
.kind() == NameLocation::Kind::EnvironmentCoordinate
) {
2212 EnvironmentCoordinate coord
= loc
.environmentCoordinate();
2213 uint8_t hops
= AssertedCast
<uint8_t>(coord
.hops());
2214 lexicalLoc
= NameLocation::EnvironmentCoordinate(BindingKind::Let
, hops
,
2217 MOZ_ASSERT(loc
.kind() == NameLocation::Kind::Dynamic
);
2221 NameOpEmitter
noe(this, name
, lexicalLoc
, NameOpEmitter::Kind::Initialize
);
2222 if (!noe
.prepareForRhs()) {
2227 // Emit the new |this| value.
2228 if (!emitTree(setThisNode
->right())) {
2233 // Get the original |this| and throw if we already initialized
2234 // it. Do *not* use the NameLocation argument, as that's the special
2235 // lexical location below to deal with super() semantics.
2236 if (!emitGetName(name
)) {
2237 // [stack] NEWTHIS THIS
2240 if (!emit1(JSOp::CheckThisReinit
)) {
2241 // [stack] NEWTHIS THIS
2244 if (!emit1(JSOp::Pop
)) {
2248 if (!noe
.emitAssignment()) {
2253 if (!emitInitializeInstanceMembers(true)) {
2260 bool BytecodeEmitter::defineHoistedTopLevelFunctions(ParseNode
* body
) {
2261 MOZ_ASSERT(inPrologue());
2262 MOZ_ASSERT(sc
->isGlobalContext() || (sc
->isEvalContext() && !sc
->strict()));
2263 MOZ_ASSERT(body
->is
<LexicalScopeNode
>() || body
->is
<ListNode
>());
2265 if (body
->is
<LexicalScopeNode
>()) {
2266 body
= body
->as
<LexicalScopeNode
>().scopeBody();
2267 MOZ_ASSERT(body
->is
<ListNode
>());
2270 if (!body
->as
<ListNode
>().hasTopLevelFunctionDeclarations()) {
2274 return emitHoistedFunctionsInList(&body
->as
<ListNode
>());
2277 // For Global and sloppy-Eval scripts, this performs most of the steps of the
2278 // spec's [GlobalDeclarationInstantiation] and [EvalDeclarationInstantiation]
2281 // Note that while strict-Eval is handled in the same part of the spec, it never
2282 // fails for global-redeclaration checks so those scripts initialize directly in
2284 bool BytecodeEmitter::emitDeclarationInstantiation(ParseNode
* body
) {
2285 if (sc
->isModuleContext()) {
2286 // ES Modules have dedicated variable and lexial environments and therefore
2287 // do not have to perform redeclaration checks. We initialize their bindings
2288 // elsewhere in bytecode.
2292 if (sc
->isEvalContext() && sc
->strict()) {
2293 // Strict Eval has a dedicated variables (and lexical) environment and
2294 // therefore does not have to perform redeclaration checks. We initialize
2295 // their bindings elsewhere in the bytecode.
2299 // If we have no variables bindings, then we are done!
2300 if (sc
->isGlobalContext()) {
2301 if (!sc
->asGlobalContext()->bindings
) {
2305 MOZ_ASSERT(sc
->isEvalContext());
2307 if (!sc
->asEvalContext()->bindings
) {
2313 // There should be no emitted functions yet.
2314 for (const auto& thing
: perScriptData().gcThingList().objects()) {
2315 MOZ_ASSERT(thing
.isEmptyGlobalScope() || thing
.isScope());
2319 // Emit the hoisted functions to gc-things list. There is no bytecode
2320 // generated yet to bind them.
2321 if (!defineHoistedTopLevelFunctions(body
)) {
2325 // Save the last GCThingIndex emitted. The hoisted functions are contained in
2326 // the gc-things list up until this point. This set of gc-things also contain
2327 // initial scopes (of which there must be at least one).
2328 MOZ_ASSERT(perScriptData().gcThingList().length() > 0);
2329 GCThingIndex lastFun
=
2330 GCThingIndex(perScriptData().gcThingList().length() - 1);
2333 for (const auto& thing
: perScriptData().gcThingList().objects()) {
2334 MOZ_ASSERT(thing
.isEmptyGlobalScope() || thing
.isScope() ||
2335 thing
.isFunction());
2339 // Check for declaration conflicts and initialize the bindings.
2340 // NOTE: The self-hosting top-level script should not populate the builtins
2341 // directly on the GlobalObject (and instead uses JSOp::GetIntrinsic for
2343 if (emitterMode
== BytecodeEmitter::EmitterMode::Normal
) {
2344 if (!emitGCIndexOp(JSOp::GlobalOrEvalDeclInstantiation
, lastFun
)) {
2352 bool BytecodeEmitter::emitScript(ParseNode
* body
) {
2353 setScriptStartOffsetIfUnset(body
->pn_pos
.begin
);
2355 MOZ_ASSERT(inPrologue());
2357 TDZCheckCache
tdzCache(this);
2358 EmitterScope
emitterScope(this);
2359 Maybe
<AsyncEmitter
> topLevelAwait
;
2360 if (sc
->isGlobalContext()) {
2361 if (!emitterScope
.enterGlobal(this, sc
->asGlobalContext())) {
2364 } else if (sc
->isEvalContext()) {
2365 if (!emitterScope
.enterEval(this, sc
->asEvalContext())) {
2369 MOZ_ASSERT(sc
->isModuleContext());
2370 if (!emitterScope
.enterModule(this, sc
->asModuleContext())) {
2373 if (sc
->asModuleContext()->isAsync()) {
2374 topLevelAwait
.emplace(this);
2378 setFunctionBodyEndPos(body
->pn_pos
.end
);
2380 bool isSloppyEval
= sc
->isEvalContext() && !sc
->strict();
2381 if (isSloppyEval
&& body
->is
<LexicalScopeNode
>() &&
2382 !body
->as
<LexicalScopeNode
>().isEmptyScope()) {
2383 // Sloppy eval scripts may emit hoisted functions bindings with a
2384 // `JSOp::GlobalOrEvalDeclInstantiation` opcode below. If this eval needs a
2385 // top-level lexical environment, we must ensure that environment is created
2386 // before those functions are created and bound.
2388 // This differs from the global-script case below because the global-lexical
2389 // environment exists outside the script itself. In the case of strict eval
2390 // scripts, the `emitterScope` above is already sufficient.
2391 EmitterScope
lexicalEmitterScope(this);
2392 LexicalScopeNode
* scope
= &body
->as
<LexicalScopeNode
>();
2394 if (!lexicalEmitterScope
.enterLexical(this, ScopeKind::Lexical
,
2395 scope
->scopeBindings())) {
2399 if (!emitDeclarationInstantiation(scope
->scopeBody())) {
2405 ParseNode
* scopeBody
= scope
->scopeBody();
2406 if (!emitLexicalScopeBody(scopeBody
)) {
2410 if (!updateSourceCoordNotes(scopeBody
->pn_pos
.end
)) {
2414 if (!lexicalEmitterScope
.leave(this)) {
2418 if (!emitDeclarationInstantiation(body
)) {
2421 if (topLevelAwait
) {
2422 if (!topLevelAwait
->prepareForModule()) {
2429 if (topLevelAwait
) {
2430 if (!topLevelAwait
->prepareForBody()) {
2435 if (!emitTree(body
)) {
2440 if (!updateSourceCoordNotes(body
->pn_pos
.end
)) {
2445 if (topLevelAwait
) {
2446 if (!topLevelAwait
->emitEndModule()) {
2451 if (!markSimpleBreakpoint()) {
2455 if (!emitReturnRval()) {
2459 if (!emitterScope
.leave(this)) {
2463 if (!NameFunctions(fc
, parserAtoms(), body
)) {
2467 // Create a Stencil and convert it into a JSScript.
2468 return intoScriptStencil(CompilationStencil::TopLevelIndex
);
2471 js::UniquePtr
<ImmutableScriptData
>
2472 BytecodeEmitter::createImmutableScriptData() {
2474 if (!getNslots(&nslots
)) {
2478 bool isFunction
= sc
->isFunctionBox();
2479 uint16_t funLength
= isFunction
? sc
->asFunctionBox()->length() : 0;
2481 mozilla::SaturateUint8 propertyCountEstimate
= propertyAdditionEstimate
;
2483 // Add fields to the property count estimate.
2484 if (isFunction
&& sc
->asFunctionBox()->useMemberInitializers()) {
2485 propertyCountEstimate
+=
2486 sc
->asFunctionBox()->memberInitializers().numMemberInitializers
;
2489 return ImmutableScriptData::new_(
2490 fc
, mainOffset(), maxFixedSlots
, nslots
, bodyScopeIndex
,
2491 bytecodeSection().numICEntries(), isFunction
, funLength
,
2492 propertyCountEstimate
.value(), bytecodeSection().code(),
2493 bytecodeSection().notes(), bytecodeSection().resumeOffsetList().span(),
2494 bytecodeSection().scopeNoteList().span(),
2495 bytecodeSection().tryNoteList().span());
2498 bool BytecodeEmitter::getNslots(uint32_t* nslots
) {
2500 maxFixedSlots
+ static_cast<uint64_t>(bytecodeSection().maxStackDepth());
2501 if (nslots64
> UINT32_MAX
) {
2502 reportError(nullptr, JSMSG_NEED_DIET
, "script");
2509 bool BytecodeEmitter::emitFunctionScript(FunctionNode
* funNode
) {
2510 MOZ_ASSERT(inPrologue());
2511 ParamsBodyNode
* paramsBody
= funNode
->body();
2512 FunctionBox
* funbox
= sc
->asFunctionBox();
2514 setScriptStartOffsetIfUnset(paramsBody
->pn_pos
.begin
);
2518 FunctionScriptEmitter
fse(this, funbox
, Some(paramsBody
->pn_pos
.begin
),
2519 Some(paramsBody
->pn_pos
.end
));
2520 if (!fse
.prepareForParameters()) {
2525 if (!emitFunctionFormalParameters(paramsBody
)) {
2530 if (!fse
.prepareForBody()) {
2535 if (!emitTree(paramsBody
->body())) {
2540 if (!fse
.emitEndBody()) {
2545 if (funbox
->index() == CompilationStencil::TopLevelIndex
) {
2546 if (!NameFunctions(fc
, parserAtoms(), funNode
)) {
2551 return fse
.intoStencil();
2554 bool BytecodeEmitter::emitDestructuringLHSRef(ParseNode
* target
,
2557 int depth
= bytecodeSection().stackDepth();
2560 switch (target
->getKind()) {
2561 case ParseNodeKind::Name
:
2562 case ParseNodeKind::ArrayExpr
:
2563 case ParseNodeKind::ObjectExpr
:
2564 // No need to recurse into ParseNodeKind::Array and ParseNodeKind::Object
2565 // subpatterns here, since emitSetOrInitializeDestructuring does the
2566 // recursion when setting or initializing the value. Getting reference
2571 case ParseNodeKind::DotExpr
: {
2572 PropertyAccess
* prop
= &target
->as
<PropertyAccess
>();
2573 bool isSuper
= prop
->isSuper();
2574 PropOpEmitter
poe(this, PropOpEmitter::Kind::SimpleAssignment
,
2575 isSuper
? PropOpEmitter::ObjKind::Super
2576 : PropOpEmitter::ObjKind::Other
);
2577 if (!poe
.prepareForObj()) {
2581 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
2582 if (!emitGetThisForSuperBase(base
)) {
2583 // [stack] THIS SUPERBASE
2587 if (!emitTree(&prop
->expression())) {
2592 if (!poe
.prepareForRhs()) {
2593 // [stack] # if Super
2594 // [stack] THIS SUPERBASE
2595 // [stack] # otherwise
2600 // SUPERBASE was pushed onto THIS in poe.prepareForRhs above.
2601 *emitted
= 1 + isSuper
;
2605 case ParseNodeKind::ElemExpr
: {
2606 PropertyByValue
* elem
= &target
->as
<PropertyByValue
>();
2607 bool isSuper
= elem
->isSuper();
2608 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
2609 ElemOpEmitter
eoe(this, ElemOpEmitter::Kind::SimpleAssignment
,
2610 isSuper
? ElemOpEmitter::ObjKind::Super
2611 : ElemOpEmitter::ObjKind::Other
);
2612 if (!emitElemObjAndKey(elem
, isSuper
, eoe
)) {
2613 // [stack] # if Super
2615 // [stack] # otherwise
2619 if (!eoe
.prepareForRhs()) {
2620 // [stack] # if Super
2621 // [stack] THIS KEY SUPERBASE
2622 // [stack] # otherwise
2627 // SUPERBASE was pushed onto KEY in eoe.prepareForRhs above.
2628 *emitted
= 2 + isSuper
;
2632 case ParseNodeKind::PrivateMemberExpr
: {
2633 PrivateMemberAccess
* privateExpr
= &target
->as
<PrivateMemberAccess
>();
2634 PrivateOpEmitter
xoe(this, PrivateOpEmitter::Kind::SimpleAssignment
,
2635 privateExpr
->privateName().name());
2636 if (!emitTree(&privateExpr
->expression())) {
2640 if (!xoe
.emitReference()) {
2644 *emitted
= xoe
.numReferenceSlots();
2648 case ParseNodeKind::CallExpr
:
2649 MOZ_ASSERT_UNREACHABLE(
2650 "Parser::reportIfNotValidSimpleAssignmentTarget "
2651 "rejects function calls as assignment "
2652 "targets in destructuring assignments");
2656 MOZ_CRASH("emitDestructuringLHSRef: bad lhs kind");
2659 MOZ_ASSERT(bytecodeSection().stackDepth() == depth
+ int(*emitted
));
2664 bool BytecodeEmitter::emitSetOrInitializeDestructuring(
2665 ParseNode
* target
, DestructuringFlavor flav
) {
2666 // Now emit the lvalue opcode sequence. If the lvalue is a nested
2667 // destructuring initialiser-form, call ourselves to handle it, then pop
2668 // the matched value. Otherwise emit an lvalue bytecode sequence followed
2669 // by an assignment op.
2671 switch (target
->getKind()) {
2672 case ParseNodeKind::ArrayExpr
:
2673 case ParseNodeKind::ObjectExpr
:
2674 if (!emitDestructuringOps(&target
->as
<ListNode
>(), flav
)) {
2677 // emitDestructuringOps leaves the assigned (to-be-destructured) value on
2678 // top of the stack.
2681 case ParseNodeKind::Name
: {
2682 auto name
= target
->as
<NameNode
>().name();
2683 NameLocation loc
= lookupName(name
);
2684 NameOpEmitter::Kind kind
;
2686 case DestructuringFlavor::Declaration
:
2687 kind
= NameOpEmitter::Kind::Initialize
;
2690 case DestructuringFlavor::Assignment
:
2691 kind
= NameOpEmitter::Kind::SimpleAssignment
;
2695 NameOpEmitter
noe(this, name
, loc
, kind
);
2696 if (!noe
.prepareForRhs()) {
2700 if (noe
.emittedBindOp()) {
2701 // This is like ordinary assignment, but with one difference.
2703 // In `a = b`, we first determine a binding for `a` (using
2704 // JSOp::BindName or JSOp::BindGName), then we evaluate `b`, then
2705 // a JSOp::SetName instruction.
2707 // In `[a] = [b]`, per spec, `b` is evaluated first, then we
2708 // determine a binding for `a`. Then we need to do assignment--
2709 // but the operands are on the stack in the wrong order for
2710 // JSOp::SetProp, so we have to add a JSOp::Swap.
2712 // In the cases where we are emitting a name op, emit a swap
2714 if (!emit1(JSOp::Swap
)) {
2719 // In cases of emitting a frame slot or environment slot,
2720 // nothing needs be done.
2722 if (!noe
.emitAssignment()) {
2730 case ParseNodeKind::DotExpr
: {
2731 // The reference is already pushed by emitDestructuringLHSRef.
2732 // [stack] # if Super
2733 // [stack] THIS SUPERBASE VAL
2734 // [stack] # otherwise
2736 PropertyAccess
* prop
= &target
->as
<PropertyAccess
>();
2737 bool isSuper
= prop
->isSuper();
2738 PropOpEmitter
poe(this, PropOpEmitter::Kind::SimpleAssignment
,
2739 isSuper
? PropOpEmitter::ObjKind::Super
2740 : PropOpEmitter::ObjKind::Other
);
2741 if (!poe
.skipObjAndRhs()) {
2745 if (!poe
.emitAssignment(prop
->key().atom())) {
2751 case ParseNodeKind::ElemExpr
: {
2752 // The reference is already pushed by emitDestructuringLHSRef.
2753 // [stack] # if Super
2754 // [stack] THIS KEY SUPERBASE VAL
2755 // [stack] # otherwise
2756 // [stack] OBJ KEY VAL
2757 PropertyByValue
* elem
= &target
->as
<PropertyByValue
>();
2758 bool isSuper
= elem
->isSuper();
2759 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
2760 ElemOpEmitter
eoe(this, ElemOpEmitter::Kind::SimpleAssignment
,
2761 isSuper
? ElemOpEmitter::ObjKind::Super
2762 : ElemOpEmitter::ObjKind::Other
);
2763 if (!eoe
.skipObjAndKeyAndRhs()) {
2766 if (!eoe
.emitAssignment()) {
2773 case ParseNodeKind::PrivateMemberExpr
: {
2774 // The reference is already pushed by emitDestructuringLHSRef.
2775 // [stack] OBJ NAME VAL
2776 PrivateMemberAccess
* privateExpr
= &target
->as
<PrivateMemberAccess
>();
2777 PrivateOpEmitter
xoe(this, PrivateOpEmitter::Kind::SimpleAssignment
,
2778 privateExpr
->privateName().name());
2779 if (!xoe
.skipReference()) {
2782 if (!xoe
.emitAssignment()) {
2789 case ParseNodeKind::CallExpr
:
2790 MOZ_ASSERT_UNREACHABLE(
2791 "Parser::reportIfNotValidSimpleAssignmentTarget "
2792 "rejects function calls as assignment "
2793 "targets in destructuring assignments");
2797 MOZ_CRASH("emitSetOrInitializeDestructuring: bad lhs kind");
2800 // Pop the assigned value.
2801 if (!emit1(JSOp::Pop
)) {
2809 JSOp
BytecodeEmitter::getIterCallOp(JSOp callOp
,
2810 SelfHostedIter selfHostedIter
) {
2811 if (emitterMode
== BytecodeEmitter::SelfHosting
) {
2812 MOZ_ASSERT(selfHostedIter
!= SelfHostedIter::Deny
);
2816 return JSOp::CallContent
;
2817 case JSOp::CallIter
:
2818 return JSOp::CallContentIter
;
2820 MOZ_CRASH("Unknown iterator call op");
2827 bool BytecodeEmitter::emitIteratorNext(
2828 const Maybe
<uint32_t>& callSourceCoordOffset
,
2829 IteratorKind iterKind
/* = IteratorKind::Sync */,
2830 SelfHostedIter selfHostedIter
/* = SelfHostedIter::Deny */) {
2831 MOZ_ASSERT(selfHostedIter
!= SelfHostedIter::Deny
||
2832 emitterMode
!= BytecodeEmitter::SelfHosting
,
2833 ".next() iteration is prohibited in self-hosted code because it"
2834 "can run user-modifiable iteration code");
2836 // [stack] ... NEXT ITER
2837 MOZ_ASSERT(bytecodeSection().stackDepth() >= 2);
2839 if (!emitCall(getIterCallOp(JSOp::Call
, selfHostedIter
), 0,
2840 callSourceCoordOffset
)) {
2841 // [stack] ... RESULT
2845 if (iterKind
== IteratorKind::Async
) {
2846 if (!emitAwaitInInnermostScope()) {
2847 // [stack] ... RESULT
2852 if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext
)) {
2853 // [stack] ... RESULT
2859 bool BytecodeEmitter::emitIteratorCloseInScope(
2860 EmitterScope
& currentScope
,
2861 IteratorKind iterKind
/* = IteratorKind::Sync */,
2862 CompletionKind completionKind
/* = CompletionKind::Normal */,
2863 SelfHostedIter selfHostedIter
/* = SelfHostedIter::Deny */) {
2864 MOZ_ASSERT(selfHostedIter
!= SelfHostedIter::Deny
||
2865 emitterMode
!= BytecodeEmitter::SelfHosting
,
2866 ".close() on iterators is prohibited in self-hosted code because "
2867 "it can run user-modifiable iteration code");
2869 if (iterKind
== IteratorKind::Sync
) {
2870 return emit2(JSOp::CloseIter
, uint8_t(completionKind
));
2873 // Generate inline logic corresponding to IteratorClose (ES2021 7.4.6) and
2874 // AsyncIteratorClose (ES2021 7.4.7). Steps numbers apply to both operations.
2876 // Callers need to ensure that the iterator object is at the top of the
2879 // For non-Throw completions, we emit the equivalent of:
2881 // var returnMethod = GetMethod(iterator, "return");
2882 // if (returnMethod !== undefined) {
2883 // var innerResult = [Await] Call(returnMethod, iterator);
2884 // CheckIsObj(innerResult);
2887 // Whereas for Throw completions, we emit:
2890 // var returnMethod = GetMethod(iterator, "return");
2891 // if (returnMethod !== undefined) {
2892 // [Await] Call(returnMethod, iterator);
2896 Maybe
<TryEmitter
> tryCatch
;
2898 if (completionKind
== CompletionKind::Throw
) {
2899 tryCatch
.emplace(this, TryEmitter::Kind::TryCatch
,
2900 TryEmitter::ControlKind::NonSyntactic
);
2902 if (!tryCatch
->emitTry()) {
2908 if (!emit1(JSOp::Dup
)) {
2909 // [stack] ... ITER ITER
2913 // Steps 1-2 are assertions, step 3 is implicit.
2917 // Get the "return" method.
2918 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::return_())) {
2919 // [stack] ... ITER RET
2925 // Do nothing if "return" is undefined or null.
2926 InternalIfEmitter
ifReturnMethodIsDefined(this);
2927 if (!emit1(JSOp::IsNullOrUndefined
)) {
2928 // [stack] ... ITER RET NULL-OR-UNDEF
2932 if (!ifReturnMethodIsDefined
.emitThenElse(
2933 IfEmitter::ConditionKind::Negative
)) {
2934 // [stack] ... ITER RET
2940 // Call the "return" method.
2941 if (!emit1(JSOp::Swap
)) {
2942 // [stack] ... RET ITER
2946 if (!emitCall(getIterCallOp(JSOp::Call
, selfHostedIter
), 0)) {
2947 // [stack] ... RESULT
2951 // 7.4.7 AsyncIteratorClose, step 5.d.
2952 if (iterKind
== IteratorKind::Async
) {
2953 if (completionKind
!= CompletionKind::Throw
) {
2954 // Await clobbers rval, so save the current rval.
2955 if (!emit1(JSOp::GetRval
)) {
2956 // [stack] ... RESULT RVAL
2959 if (!emit1(JSOp::Swap
)) {
2960 // [stack] ... RVAL RESULT
2965 if (!emitAwaitInScope(currentScope
)) {
2966 // [stack] ... RVAL? RESULT
2970 if (completionKind
!= CompletionKind::Throw
) {
2971 if (!emit1(JSOp::Swap
)) {
2972 // [stack] ... RESULT RVAL
2975 if (!emit1(JSOp::SetRval
)) {
2976 // [stack] ... RESULT
2982 // Step 6 (Handled in caller).
2985 if (completionKind
!= CompletionKind::Throw
) {
2986 // Check that the "return" result is an object.
2987 if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn
)) {
2988 // [stack] ... RESULT
2993 if (!ifReturnMethodIsDefined
.emitElse()) {
2994 // [stack] ... ITER RET
2998 if (!emit1(JSOp::Pop
)) {
3003 if (!ifReturnMethodIsDefined
.emitEnd()) {
3007 if (completionKind
== CompletionKind::Throw
) {
3008 if (!tryCatch
->emitCatch()) {
3009 // [stack] ... ITER EXC
3013 // Just ignore the exception thrown by call and await.
3014 if (!emit1(JSOp::Pop
)) {
3019 if (!tryCatch
->emitEnd()) {
3025 // Step 9 (Handled in caller).
3027 return emit1(JSOp::Pop
);
3031 template <typename InnerEmitter
>
3032 bool BytecodeEmitter::wrapWithDestructuringTryNote(int32_t iterDepth
,
3033 InnerEmitter emitter
) {
3034 MOZ_ASSERT(bytecodeSection().stackDepth() >= iterDepth
);
3036 // Pad a nop at the beginning of the bytecode covered by the trynote so
3037 // that when unwinding environments, we may unwind to the scope
3038 // corresponding to the pc *before* the start, in case the first bytecode
3039 // emitted by |emitter| is the start of an inner scope. See comment above
3040 // UnwindEnvironmentToTryPc.
3041 if (!emit1(JSOp::TryDestructuring
)) {
3045 BytecodeOffset start
= bytecodeSection().offset();
3046 if (!emitter(this)) {
3049 BytecodeOffset end
= bytecodeSection().offset();
3051 return addTryNote(TryNoteKind::Destructuring
, iterDepth
, start
, end
);
3056 bool BytecodeEmitter::emitDefault(ParseNode
* defaultExpr
, ParseNode
* pattern
) {
3059 DefaultEmitter
de(this);
3060 if (!de
.prepareForDefault()) {
3064 if (!emitInitializer(defaultExpr
, pattern
)) {
3065 // [stack] DEFAULTVALUE
3068 if (!de
.emitEnd()) {
3069 // [stack] VALUE/DEFAULTVALUE
3075 bool BytecodeEmitter::emitAnonymousFunctionWithName(
3076 ParseNode
* node
, TaggedParserAtomIndex name
) {
3077 MOZ_ASSERT(node
->isDirectRHSAnonFunction());
3079 if (node
->is
<FunctionNode
>()) {
3080 // Function doesn't have 'name' property at this point.
3081 // Set function's name at compile time.
3082 if (!setFunName(node
->as
<FunctionNode
>().funbox(), name
)) {
3086 return emitTree(node
);
3089 MOZ_ASSERT(node
->is
<ClassNode
>());
3091 return emitClass(&node
->as
<ClassNode
>(), ClassNameKind::InferredName
, name
);
3094 bool BytecodeEmitter::emitAnonymousFunctionWithComputedName(
3095 ParseNode
* node
, FunctionPrefixKind prefixKind
) {
3096 MOZ_ASSERT(node
->isDirectRHSAnonFunction());
3098 if (node
->is
<FunctionNode
>()) {
3099 if (!emitTree(node
)) {
3103 if (!emitDupAt(1)) {
3104 // [stack] NAME FUN NAME
3107 if (!emit2(JSOp::SetFunName
, uint8_t(prefixKind
))) {
3114 MOZ_ASSERT(node
->is
<ClassNode
>());
3115 MOZ_ASSERT(prefixKind
== FunctionPrefixKind::None
);
3117 return emitClass(&node
->as
<ClassNode
>(), ClassNameKind::ComputedName
);
3120 bool BytecodeEmitter::setFunName(FunctionBox
* funbox
,
3121 TaggedParserAtomIndex name
) {
3122 // The inferred name may already be set if this function is an interpreted
3123 // lazy function and we OOM'ed after we set the inferred name the first
3125 if (funbox
->hasInferredName()) {
3126 MOZ_ASSERT(!funbox
->emitBytecode
);
3127 MOZ_ASSERT(funbox
->displayAtom() == name
);
3132 funbox
->setInferredName(name
);
3136 bool BytecodeEmitter::emitInitializer(ParseNode
* initializer
,
3137 ParseNode
* pattern
) {
3138 if (initializer
->isDirectRHSAnonFunction()) {
3139 MOZ_ASSERT(!pattern
->isInParens());
3140 auto name
= pattern
->as
<NameNode
>().name();
3141 if (!emitAnonymousFunctionWithName(initializer
, name
)) {
3145 if (!emitTree(initializer
)) {
3153 bool BytecodeEmitter::emitDestructuringOpsArray(ListNode
* pattern
,
3154 DestructuringFlavor flav
) {
3155 MOZ_ASSERT(getSelfHostedIterFor(pattern
) == SelfHostedIter::Deny
,
3156 "array destructuring is prohibited in self-hosted code because it"
3157 "can run user-modifiable iteration code");
3158 MOZ_ASSERT(pattern
->isKind(ParseNodeKind::ArrayExpr
));
3159 MOZ_ASSERT(bytecodeSection().stackDepth() != 0);
3161 // Here's pseudo code for |let [a, b, , c=y, ...d] = x;|
3163 // Lines that are annotated "covered by trynote" mean that upon throwing
3164 // an exception, IteratorClose is called on iter only if done is false.
3168 // let iter, next, lref, result, done, value; // stack values
3170 // // NOTE: the fast path for this example is not applicable, because of
3171 // // the spread and the assignment |c=y|, but it is documented here for a
3172 // // simpler example, |let [a,b] = x;|
3174 // // if (IsOptimizableArray(x)) {
3177 // // goto end: // (skip everything below)
3180 // iter = x[Symbol.iterator]();
3181 // next = iter.next;
3183 // // ==== emitted by loop for a ====
3184 // lref = GetReference(a); // covered by trynote
3186 // result = Call(next, iter);
3187 // done = result.done;
3190 // value = undefined;
3192 // value = result.value;
3194 // SetOrInitialize(lref, value); // covered by trynote
3196 // // ==== emitted by loop for b ====
3197 // lref = GetReference(b); // covered by trynote
3200 // value = undefined;
3202 // result = Call(next, iter);
3203 // done = result.done;
3205 // value = undefined;
3207 // value = result.value;
3210 // SetOrInitialize(lref, value); // covered by trynote
3212 // // ==== emitted by loop for elision ====
3214 // value = undefined;
3216 // result = Call(next, iter);
3217 // done = result.done;
3219 // value = undefined;
3221 // value = result.value;
3224 // // ==== emitted by loop for c ====
3225 // lref = GetReference(c); // covered by trynote
3228 // value = undefined;
3230 // result = Call(next, iter);
3231 // done = result.done;
3233 // value = undefined;
3235 // value = result.value;
3238 // if (value === undefined)
3239 // value = y; // covered by trynote
3241 // SetOrInitialize(lref, value); // covered by trynote
3243 // // ==== emitted by loop for d ====
3244 // lref = GetReference(d); // covered by trynote
3249 // value = [...iter];
3251 // SetOrInitialize(lref, value); // covered by trynote
3253 // // === emitted after loop ===
3255 // IteratorClose(iter);
3259 bool isEligibleForArrayOptimizations
= true;
3260 for (ParseNode
* member
: pattern
->contents()) {
3261 switch (member
->getKind()) {
3262 case ParseNodeKind::Elision
:
3264 case ParseNodeKind::Name
: {
3265 auto name
= member
->as
<NameNode
>().name();
3266 NameLocation loc
= lookupName(name
);
3267 if (loc
.kind() != NameLocation::Kind::ArgumentSlot
&&
3268 loc
.kind() != NameLocation::Kind::FrameSlot
&&
3269 loc
.kind() != NameLocation::Kind::EnvironmentCoordinate
) {
3270 isEligibleForArrayOptimizations
= false;
3275 // Unfortunately we can't handle any recursive destructuring,
3276 // because we can't guarantee that the recursed-into parts
3277 // won't run code which invalidates our constraints. We also
3278 // cannot handle ParseNodeKind::AssignExpr for similar reasons.
3279 isEligibleForArrayOptimizations
= false;
3282 if (!isEligibleForArrayOptimizations
) {
3287 // Use an iterator to destructure the RHS, instead of index lookup. We
3288 // must leave the *original* value on the stack.
3289 if (!emit1(JSOp::Dup
)) {
3290 // [stack] ... OBJ OBJ
3294 Maybe
<InternalIfEmitter
> ifArrayOptimizable
;
3296 if (isEligibleForArrayOptimizations
) {
3297 ifArrayOptimizable
.emplace(
3298 this, BranchEmitterBase::LexicalKind::MayContainLexicalAccessInBranch
);
3300 if (!emit1(JSOp::Dup
)) {
3305 if (!emit1(JSOp::OptimizeGetIterator
)) {
3306 // [stack] OBJ OBJ IS_OPTIMIZABLE
3310 if (!ifArrayOptimizable
->emitThenElse()) {
3315 if (!emitAtomOp(JSOp::GetProp
,
3316 TaggedParserAtomIndex::WellKnown::length())) {
3317 // [stack] OBJ LENGTH
3321 if (!emit1(JSOp::Swap
)) {
3322 // [stack] LENGTH OBJ
3327 for (ParseNode
* member
: pattern
->contents()) {
3328 if (member
->isKind(ParseNodeKind::Elision
)) {
3333 if (!emit1(JSOp::Dup
)) {
3334 // [stack] LENGTH OBJ OBJ
3338 if (!emitNumberOp(idx
)) {
3339 // [stack] LENGTH OBJ OBJ IDX
3343 if (!emit1(JSOp::Dup
)) {
3344 // [stack] LENGTH OBJ OBJ IDX IDX
3348 if (!emitDupAt(4)) {
3349 // [stack] LENGTH OBJ OBJ IDX IDX LENGTH
3353 if (!emit1(JSOp::Lt
)) {
3354 // [stack] LENGTH OBJ OBJ IDX IS_IN_DENSE_BOUNDS
3358 InternalIfEmitter
isInDenseBounds(this);
3359 if (!isInDenseBounds
.emitThenElse()) {
3360 // [stack] LENGTH OBJ OBJ IDX
3364 if (!emit1(JSOp::GetElem
)) {
3365 // [stack] LENGTH OBJ VALUE
3369 if (!isInDenseBounds
.emitElse()) {
3370 // [stack] LENGTH OBJ OBJ IDX
3375 // [stack] LENGTH OBJ
3379 if (!emit1(JSOp::Undefined
)) {
3380 // [stack] LENGTH OBJ UNDEFINED
3384 if (!isInDenseBounds
.emitEnd()) {
3385 // [stack] LENGTH OBJ VALUE|UNDEFINED
3389 if (!emitSetOrInitializeDestructuring(member
, flav
)) {
3390 // [stack] LENGTH OBJ
3397 if (!emit1(JSOp::Swap
)) {
3398 // [stack] OBJ LENGTH
3402 if (!emit1(JSOp::Pop
)) {
3407 if (!ifArrayOptimizable
->emitElse()) {
3413 if (!emitIterator(SelfHostedIter::Deny
)) {
3414 // [stack] ... OBJ NEXT ITER
3418 // For an empty pattern [], call IteratorClose unconditionally. Nothing
3419 // else needs to be done.
3420 if (!pattern
->head()) {
3421 if (!emit1(JSOp::Swap
)) {
3422 // [stack] ... OBJ ITER NEXT
3425 if (!emit1(JSOp::Pop
)) {
3426 // [stack] ... OBJ ITER
3430 if (!emitIteratorCloseInInnermostScope()) {
3435 if (ifArrayOptimizable
.isSome()) {
3436 if (!ifArrayOptimizable
->emitEnd()) {
3445 // Push an initial FALSE value for DONE.
3446 if (!emit1(JSOp::False
)) {
3447 // [stack] ... OBJ NEXT ITER FALSE
3451 // TryNoteKind::Destructuring expects the iterator and the done value
3452 // to be the second to top and the top of the stack, respectively.
3453 // IteratorClose is called upon exception only if done is false.
3454 int32_t tryNoteDepth
= bytecodeSection().stackDepth();
3456 for (ParseNode
* member
: pattern
->contents()) {
3457 bool isFirst
= member
== pattern
->head();
3458 DebugOnly
<bool> hasNext
= !!member
->pn_next
;
3460 ParseNode
* subpattern
;
3461 if (member
->isKind(ParseNodeKind::Spread
)) {
3462 subpattern
= member
->as
<UnaryNode
>().kid();
3464 MOZ_ASSERT(!subpattern
->isKind(ParseNodeKind::AssignExpr
));
3466 subpattern
= member
;
3469 ParseNode
* lhsPattern
= subpattern
;
3470 ParseNode
* pndefault
= nullptr;
3471 if (subpattern
->isKind(ParseNodeKind::AssignExpr
)) {
3472 lhsPattern
= subpattern
->as
<AssignmentNode
>().left();
3473 pndefault
= subpattern
->as
<AssignmentNode
>().right();
3476 // Number of stack slots emitted for the LHS reference.
3479 // Spec requires LHS reference to be evaluated first.
3480 bool isElision
= lhsPattern
->isKind(ParseNodeKind::Elision
);
3482 auto emitLHSRef
= [lhsPattern
, &emitted
](BytecodeEmitter
* bce
) {
3483 return bce
->emitDestructuringLHSRef(lhsPattern
, &emitted
);
3484 // [stack] ... OBJ NEXT ITER DONE LREF*
3486 if (!wrapWithDestructuringTryNote(tryNoteDepth
, emitLHSRef
)) {
3491 // Pick the DONE value to the top of the stack.
3493 if (!emitPickN(emitted
)) {
3494 // [stack] ... OBJ NEXT ITER LREF* DONE
3500 // If this element is the first, DONE is always FALSE, so pop it.
3502 // Non-first elements should emit if-else depending on the
3503 // member pattern, below.
3504 if (!emit1(JSOp::Pop
)) {
3505 // [stack] ... OBJ NEXT ITER LREF*
3510 if (member
->isKind(ParseNodeKind::Spread
)) {
3511 InternalIfEmitter
ifThenElse(this);
3513 // If spread is not the first element of the pattern,
3514 // iterator can already be completed.
3515 // [stack] ... OBJ NEXT ITER LREF* DONE
3517 if (!ifThenElse
.emitThenElse()) {
3518 // [stack] ... OBJ NEXT ITER LREF*
3522 if (!emitUint32Operand(JSOp::NewArray
, 0)) {
3523 // [stack] ... OBJ NEXT ITER LREF* ARRAY
3526 if (!ifThenElse
.emitElse()) {
3527 // [stack] ... OBJ NEXT ITER LREF*
3532 // If iterator is not completed, create a new array with the rest
3534 if (!emitDupAt(emitted
+ 1, 2)) {
3535 // [stack] ... OBJ NEXT ITER LREF* NEXT ITER
3538 if (!emitUint32Operand(JSOp::NewArray
, 0)) {
3539 // [stack] ... OBJ NEXT ITER LREF* NEXT ITER ARRAY
3542 if (!emitNumberOp(0)) {
3543 // [stack] ... OBJ NEXT ITER LREF* NEXT ITER ARRAY INDEX
3546 if (!emitSpread(SelfHostedIter::Deny
)) {
3547 // [stack] ... OBJ NEXT ITER LREF* ARRAY INDEX
3550 if (!emit1(JSOp::Pop
)) {
3551 // [stack] ... OBJ NEXT ITER LREF* ARRAY
3556 if (!ifThenElse
.emitEnd()) {
3559 MOZ_ASSERT(ifThenElse
.pushed() == 1);
3562 // At this point the iterator is done. Unpick a TRUE value for DONE above
3564 if (!emit1(JSOp::True
)) {
3565 // [stack] ... OBJ NEXT ITER LREF* ARRAY TRUE
3568 if (!emitUnpickN(emitted
+ 1)) {
3569 // [stack] ... OBJ NEXT ITER TRUE LREF* ARRAY
3573 auto emitAssignment
= [lhsPattern
, flav
](BytecodeEmitter
* bce
) {
3574 return bce
->emitSetOrInitializeDestructuring(lhsPattern
, flav
);
3575 // [stack] ... OBJ NEXT ITER TRUE
3577 if (!wrapWithDestructuringTryNote(tryNoteDepth
, emitAssignment
)) {
3581 MOZ_ASSERT(!hasNext
);
3585 InternalIfEmitter
ifAlreadyDone(this);
3587 // [stack] ... OBJ NEXT ITER LREF* DONE
3589 if (!ifAlreadyDone
.emitThenElse()) {
3590 // [stack] ... OBJ NEXT ITER LREF*
3594 if (!emit1(JSOp::Undefined
)) {
3595 // [stack] ... OBJ NEXT ITER LREF* UNDEF
3598 if (!emit1(JSOp::NopDestructuring
)) {
3599 // [stack] ... OBJ NEXT ITER LREF* UNDEF
3603 // The iterator is done. Unpick a TRUE value for DONE above ITER.
3604 if (!emit1(JSOp::True
)) {
3605 // [stack] ... OBJ NEXT ITER LREF* UNDEF TRUE
3608 if (!emitUnpickN(emitted
+ 1)) {
3609 // [stack] ... OBJ NEXT ITER TRUE LREF* UNDEF
3613 if (!ifAlreadyDone
.emitElse()) {
3614 // [stack] ... OBJ NEXT ITER LREF*
3619 if (!emitDupAt(emitted
+ 1, 2)) {
3620 // [stack] ... OBJ NEXT ITER LREF* NEXT
3623 if (!emitIteratorNext(Some(pattern
->pn_pos
.begin
))) {
3624 // [stack] ... OBJ NEXT ITER LREF* RESULT
3627 if (!emit1(JSOp::Dup
)) {
3628 // [stack] ... OBJ NEXT ITER LREF* RESULT RESULT
3631 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::done())) {
3632 // [stack] ... OBJ NEXT ITER LREF* RESULT DONE
3636 if (!emit1(JSOp::Dup
)) {
3637 // [stack] ... OBJ NEXT ITER LREF* RESULT DONE DONE
3640 if (!emitUnpickN(emitted
+ 2)) {
3641 // [stack] ... OBJ NEXT ITER DONE LREF* RESULT DONE
3645 InternalIfEmitter
ifDone(this);
3646 if (!ifDone
.emitThenElse()) {
3647 // [stack] ... OBJ NEXT ITER DONE LREF* RESULT
3651 if (!emit1(JSOp::Pop
)) {
3652 // [stack] ... OBJ NEXT ITER DONE LREF*
3655 if (!emit1(JSOp::Undefined
)) {
3656 // [stack] ... OBJ NEXT ITER DONE LREF* UNDEF
3659 if (!emit1(JSOp::NopDestructuring
)) {
3660 // [stack] ... OBJ NEXT ITER DONE LREF* UNDEF
3664 if (!ifDone
.emitElse()) {
3665 // [stack] ... OBJ NEXT ITER DONE LREF* RESULT
3669 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::value())) {
3670 // [stack] ... OBJ NEXT ITER DONE LREF* VALUE
3674 if (!ifDone
.emitEnd()) {
3677 MOZ_ASSERT(ifDone
.pushed() == 0);
3680 if (!ifAlreadyDone
.emitEnd()) {
3683 MOZ_ASSERT(ifAlreadyDone
.pushed() == 2);
3687 auto emitDefault
= [pndefault
, lhsPattern
](BytecodeEmitter
* bce
) {
3688 return bce
->emitDefault(pndefault
, lhsPattern
);
3689 // [stack] ... OBJ NEXT ITER DONE LREF* VALUE
3692 if (!wrapWithDestructuringTryNote(tryNoteDepth
, emitDefault
)) {
3698 auto emitAssignment
= [lhsPattern
, flav
](BytecodeEmitter
* bce
) {
3699 return bce
->emitSetOrInitializeDestructuring(lhsPattern
, flav
);
3700 // [stack] ... OBJ NEXT ITER DONE
3703 if (!wrapWithDestructuringTryNote(tryNoteDepth
, emitAssignment
)) {
3707 if (!emit1(JSOp::Pop
)) {
3708 // [stack] ... OBJ NEXT ITER DONE
3714 // The last DONE value is on top of the stack. If not DONE, call
3716 // [stack] ... OBJ NEXT ITER DONE
3718 InternalIfEmitter
ifDone(this);
3719 if (!ifDone
.emitThenElse()) {
3720 // [stack] ... OBJ NEXT ITER
3727 if (!ifDone
.emitElse()) {
3728 // [stack] ... OBJ NEXT ITER
3731 if (!emit1(JSOp::Swap
)) {
3732 // [stack] ... OBJ ITER NEXT
3735 if (!emit1(JSOp::Pop
)) {
3736 // [stack] ... OBJ ITER
3739 if (!emitIteratorCloseInInnermostScope()) {
3743 if (!ifDone
.emitEnd()) {
3747 if (ifArrayOptimizable
.isSome()) {
3748 if (!ifArrayOptimizable
->emitEnd()) {
3757 bool BytecodeEmitter::emitComputedPropertyName(UnaryNode
* computedPropName
) {
3758 MOZ_ASSERT(computedPropName
->isKind(ParseNodeKind::ComputedName
));
3759 return emitTree(computedPropName
->kid()) && emit1(JSOp::ToPropertyKey
);
3762 bool BytecodeEmitter::emitDestructuringOpsObject(ListNode
* pattern
,
3763 DestructuringFlavor flav
) {
3764 MOZ_ASSERT(pattern
->isKind(ParseNodeKind::ObjectExpr
));
3767 MOZ_ASSERT(bytecodeSection().stackDepth() > 0);
3769 if (!emit1(JSOp::CheckObjCoercible
)) {
3774 bool needsRestPropertyExcludedSet
=
3775 pattern
->count() > 1 && pattern
->last()->isKind(ParseNodeKind::Spread
);
3776 if (needsRestPropertyExcludedSet
) {
3777 if (!emitDestructuringObjRestExclusionSet(pattern
)) {
3778 // [stack] ... RHS SET
3782 if (!emit1(JSOp::Swap
)) {
3783 // [stack] ... SET RHS
3788 for (ParseNode
* member
: pattern
->contents()) {
3789 ParseNode
* subpattern
;
3790 if (member
->isKind(ParseNodeKind::MutateProto
) ||
3791 member
->isKind(ParseNodeKind::Spread
)) {
3792 subpattern
= member
->as
<UnaryNode
>().kid();
3794 MOZ_ASSERT_IF(member
->isKind(ParseNodeKind::Spread
),
3795 !subpattern
->isKind(ParseNodeKind::AssignExpr
));
3797 MOZ_ASSERT(member
->isKind(ParseNodeKind::PropertyDefinition
) ||
3798 member
->isKind(ParseNodeKind::Shorthand
));
3799 subpattern
= member
->as
<BinaryNode
>().right();
3802 ParseNode
* lhs
= subpattern
;
3803 ParseNode
* pndefault
= nullptr;
3804 if (subpattern
->isKind(ParseNodeKind::AssignExpr
)) {
3805 lhs
= subpattern
->as
<AssignmentNode
>().left();
3806 pndefault
= subpattern
->as
<AssignmentNode
>().right();
3809 // Number of stack slots emitted for the LHS reference.
3812 // Spec requires LHS reference to be evaluated first.
3813 if (!emitDestructuringLHSRef(lhs
, &emitted
)) {
3814 // [stack] ... SET? RHS LREF*
3818 // Duplicate the value being destructured to use as a reference base.
3819 if (!emitDupAt(emitted
)) {
3820 // [stack] ... SET? RHS LREF* RHS
3824 if (member
->isKind(ParseNodeKind::Spread
)) {
3825 if (!updateSourceCoordNotes(member
->pn_pos
.begin
)) {
3829 if (!emit1(JSOp::NewInit
)) {
3830 // [stack] ... SET? RHS LREF* RHS TARGET
3833 if (!emit1(JSOp::Dup
)) {
3834 // [stack] ... SET? RHS LREF* RHS TARGET TARGET
3837 if (!emit2(JSOp::Pick
, 2)) {
3838 // [stack] ... SET? RHS LREF* TARGET TARGET RHS
3842 if (needsRestPropertyExcludedSet
) {
3843 if (!emit2(JSOp::Pick
, emitted
+ 4)) {
3844 // [stack] ... RHS LREF* TARGET TARGET RHS SET
3849 CopyOption option
= needsRestPropertyExcludedSet
? CopyOption::Filtered
3850 : CopyOption::Unfiltered
;
3851 if (!emitCopyDataProperties(option
)) {
3852 // [stack] ... RHS LREF* TARGET
3856 // Destructure TARGET per this member's lhs.
3857 if (!emitSetOrInitializeDestructuring(lhs
, flav
)) {
3862 MOZ_ASSERT(member
== pattern
->last(), "Rest property is always last");
3866 // Now push the property value currently being matched, which is the value
3867 // of the current property name "label" on the left of a colon in the object
3869 if (member
->isKind(ParseNodeKind::MutateProto
)) {
3870 if (!emitAtomOp(JSOp::GetProp
,
3871 TaggedParserAtomIndex::WellKnown::proto_())) {
3872 // [stack] ... SET? RHS LREF* PROP
3876 MOZ_ASSERT(member
->isKind(ParseNodeKind::PropertyDefinition
) ||
3877 member
->isKind(ParseNodeKind::Shorthand
));
3879 ParseNode
* key
= member
->as
<BinaryNode
>().left();
3880 if (key
->isKind(ParseNodeKind::ObjectPropertyName
) ||
3881 key
->isKind(ParseNodeKind::StringExpr
)) {
3882 if (!emitAtomOp(JSOp::GetProp
, key
->as
<NameNode
>().atom())) {
3883 // [stack] ... SET? RHS LREF* PROP
3887 if (key
->isKind(ParseNodeKind::NumberExpr
)) {
3888 if (!emitNumberOp(key
->as
<NumericLiteral
>().value())) {
3889 // [stack]... SET? RHS LREF* RHS KEY
3893 // Otherwise this is a computed property name. BigInt keys are parsed
3894 // as (synthetic) computed property names, too.
3895 MOZ_ASSERT(key
->isKind(ParseNodeKind::ComputedName
));
3897 if (!emitComputedPropertyName(&key
->as
<UnaryNode
>())) {
3898 // [stack] ... SET? RHS LREF* RHS KEY
3902 // Add the computed property key to the exclusion set.
3903 if (needsRestPropertyExcludedSet
) {
3904 if (!emitDupAt(emitted
+ 3)) {
3905 // [stack] ... SET RHS LREF* RHS KEY SET
3908 if (!emitDupAt(1)) {
3909 // [stack] ... SET RHS LREF* RHS KEY SET KEY
3912 if (!emit1(JSOp::Undefined
)) {
3913 // [stack] ... SET RHS LREF* RHS KEY SET KEY UNDEFINED
3916 if (!emit1(JSOp::InitElem
)) {
3917 // [stack] ... SET RHS LREF* RHS KEY SET
3920 if (!emit1(JSOp::Pop
)) {
3921 // [stack] ... SET RHS LREF* RHS KEY
3927 // Get the property value.
3928 if (!emitElemOpBase(JSOp::GetElem
)) {
3929 // [stack] ... SET? RHS LREF* PROP
3936 if (!emitDefault(pndefault
, lhs
)) {
3937 // [stack] ... SET? RHS LREF* VALUE
3942 // Destructure PROP per this member's lhs.
3943 if (!emitSetOrInitializeDestructuring(lhs
, flav
)) {
3944 // [stack] ... SET? RHS
3952 static bool IsDestructuringRestExclusionSetObjLiteralCompatible(
3953 ListNode
* pattern
) {
3954 uint32_t propCount
= 0;
3955 for (ParseNode
* member
: pattern
->contents()) {
3956 if (member
->isKind(ParseNodeKind::Spread
)) {
3957 MOZ_ASSERT(!member
->pn_next
, "unexpected trailing element after spread");
3963 if (member
->isKind(ParseNodeKind::MutateProto
)) {
3967 ParseNode
* key
= member
->as
<BinaryNode
>().left();
3968 if (key
->isKind(ParseNodeKind::ObjectPropertyName
) ||
3969 key
->isKind(ParseNodeKind::StringExpr
)) {
3973 // Number and BigInt keys aren't yet supported. Computed property names need
3974 // to be added dynamically.
3975 MOZ_ASSERT(key
->isKind(ParseNodeKind::NumberExpr
) ||
3976 key
->isKind(ParseNodeKind::BigIntExpr
) ||
3977 key
->isKind(ParseNodeKind::ComputedName
));
3981 if (propCount
> SharedPropMap::MaxPropsForNonDictionary
) {
3982 // JSOp::NewObject cannot accept dictionary-mode objects.
3989 bool BytecodeEmitter::emitDestructuringObjRestExclusionSet(ListNode
* pattern
) {
3990 MOZ_ASSERT(pattern
->isKind(ParseNodeKind::ObjectExpr
));
3991 MOZ_ASSERT(pattern
->last()->isKind(ParseNodeKind::Spread
));
3993 // See if we can use ObjLiteral to construct the exclusion set object.
3994 if (IsDestructuringRestExclusionSetObjLiteralCompatible(pattern
)) {
3995 if (!emitDestructuringRestExclusionSetObjLiteral(pattern
)) {
4000 // Take the slow but sure way and start off with a blank object.
4001 if (!emit1(JSOp::NewInit
)) {
4007 for (ParseNode
* member
: pattern
->contents()) {
4008 if (member
->isKind(ParseNodeKind::Spread
)) {
4009 MOZ_ASSERT(!member
->pn_next
, "unexpected trailing element after spread");
4013 TaggedParserAtomIndex pnatom
;
4014 if (member
->isKind(ParseNodeKind::MutateProto
)) {
4015 pnatom
= TaggedParserAtomIndex::WellKnown::proto_();
4017 ParseNode
* key
= member
->as
<BinaryNode
>().left();
4018 if (key
->isKind(ParseNodeKind::ObjectPropertyName
) ||
4019 key
->isKind(ParseNodeKind::StringExpr
)) {
4020 pnatom
= key
->as
<NameNode
>().atom();
4021 } else if (key
->isKind(ParseNodeKind::NumberExpr
)) {
4022 if (!emitNumberOp(key
->as
<NumericLiteral
>().value())) {
4026 // Otherwise this is a computed property name which needs to be added
4027 // dynamically. BigInt keys are parsed as (synthetic) computed property
4029 MOZ_ASSERT(key
->isKind(ParseNodeKind::ComputedName
));
4034 // Initialize elements with |undefined|.
4035 if (!emit1(JSOp::Undefined
)) {
4040 if (!emit1(JSOp::InitElem
)) {
4044 if (!emitAtomOp(JSOp::InitProp
, pnatom
)) {
4053 bool BytecodeEmitter::emitDestructuringOps(ListNode
* pattern
,
4054 DestructuringFlavor flav
) {
4055 if (pattern
->isKind(ParseNodeKind::ArrayExpr
)) {
4056 return emitDestructuringOpsArray(pattern
, flav
);
4058 return emitDestructuringOpsObject(pattern
, flav
);
4061 bool BytecodeEmitter::emitTemplateString(ListNode
* templateString
) {
4062 bool pushedString
= false;
4064 for (ParseNode
* item
: templateString
->contents()) {
4065 bool isString
= (item
->getKind() == ParseNodeKind::StringExpr
||
4066 item
->getKind() == ParseNodeKind::TemplateStringExpr
);
4068 // Skip empty strings. These are very common: a template string like
4069 // `${a}${b}` has three empty strings and without this optimization
4070 // we'd emit four JSOp::Add operations instead of just one.
4071 if (isString
&& item
->as
<NameNode
>().atom() ==
4072 TaggedParserAtomIndex::WellKnown::empty()) {
4077 // We update source notes before emitting the expression
4078 if (!updateSourceCoordNotes(item
->pn_pos
.begin
)) {
4083 if (!emitTree(item
)) {
4088 // We need to convert the expression to a string
4089 if (!emit1(JSOp::ToString
)) {
4095 // We've pushed two strings onto the stack. Add them together, leaving
4097 if (!emit1(JSOp::Add
)) {
4101 pushedString
= true;
4105 if (!pushedString
) {
4106 // All strings were empty, this can happen for something like `${""}`.
4107 // Just push an empty string.
4108 if (!emitStringOp(JSOp::String
,
4109 TaggedParserAtomIndex::WellKnown::empty())) {
4117 bool BytecodeEmitter::emitDeclarationList(ListNode
* declList
) {
4118 for (ParseNode
* decl
: declList
->contents()) {
4120 ParseNode
* initializer
;
4121 if (decl
->isKind(ParseNodeKind::Name
)) {
4123 initializer
= nullptr;
4125 AssignmentNode
* assignNode
= &decl
->as
<AssignmentNode
>();
4126 pattern
= assignNode
->left();
4127 initializer
= assignNode
->right();
4130 if (pattern
->isKind(ParseNodeKind::Name
)) {
4131 // initializer can be null here.
4132 if (!emitSingleDeclaration(declList
, &pattern
->as
<NameNode
>(),
4137 MOZ_ASSERT(pattern
->isKind(ParseNodeKind::ArrayExpr
) ||
4138 pattern
->isKind(ParseNodeKind::ObjectExpr
));
4139 MOZ_ASSERT(initializer
!= nullptr);
4141 if (!updateSourceCoordNotes(initializer
->pn_pos
.begin
)) {
4144 if (!markStepBreakpoint()) {
4147 if (!emitTree(initializer
)) {
4151 if (!emitDestructuringOps(&pattern
->as
<ListNode
>(),
4152 DestructuringFlavor::Declaration
)) {
4156 if (!emit1(JSOp::Pop
)) {
4164 bool BytecodeEmitter::emitSingleDeclaration(ListNode
* declList
, NameNode
* decl
,
4165 ParseNode
* initializer
) {
4166 MOZ_ASSERT(decl
->isKind(ParseNodeKind::Name
));
4168 // Nothing to do for initializer-less 'var' declarations, as there's no TDZ.
4169 if (!initializer
&& declList
->isKind(ParseNodeKind::VarStmt
)) {
4173 auto nameAtom
= decl
->name();
4174 NameOpEmitter
noe(this, nameAtom
, NameOpEmitter::Kind::Initialize
);
4175 if (!noe
.prepareForRhs()) {
4180 // Lexical declarations are initialized to undefined without an
4182 MOZ_ASSERT(declList
->isKind(ParseNodeKind::LetDecl
),
4183 "var declarations without initializers handled above, "
4184 "and const declarations must have initializers");
4185 if (!emit1(JSOp::Undefined
)) {
4186 // [stack] ENV? UNDEF
4190 MOZ_ASSERT(initializer
);
4192 if (!updateSourceCoordNotes(initializer
->pn_pos
.begin
)) {
4195 if (!markStepBreakpoint()) {
4198 if (!emitInitializer(initializer
, decl
)) {
4203 if (!noe
.emitAssignment()) {
4207 if (!emit1(JSOp::Pop
)) {
4215 bool BytecodeEmitter::emitAssignmentRhs(
4216 ParseNode
* rhs
, TaggedParserAtomIndex anonFunctionName
) {
4217 if (rhs
->isDirectRHSAnonFunction()) {
4218 if (anonFunctionName
) {
4219 return emitAnonymousFunctionWithName(rhs
, anonFunctionName
);
4221 return emitAnonymousFunctionWithComputedName(rhs
, FunctionPrefixKind::None
);
4223 return emitTree(rhs
);
4226 // The RHS value to assign is already on the stack, i.e., the next enumeration
4227 // value in a for-in or for-of loop. Offset is the location in the stack of the
4228 // already-emitted rhs. If we emitted a JSOp::BindName or JSOp::BindGName, then
4229 // the scope is on the top of the stack and we need to dig one deeper to get
4230 // the right RHS value.
4231 bool BytecodeEmitter::emitAssignmentRhs(uint8_t offset
) {
4233 return emitPickN(offset
- 1);
4239 static inline JSOp
CompoundAssignmentParseNodeKindToJSOp(ParseNodeKind pnk
) {
4241 case ParseNodeKind::InitExpr
:
4243 case ParseNodeKind::AssignExpr
:
4245 case ParseNodeKind::AddAssignExpr
:
4247 case ParseNodeKind::SubAssignExpr
:
4249 case ParseNodeKind::BitOrAssignExpr
:
4251 case ParseNodeKind::BitXorAssignExpr
:
4252 return JSOp::BitXor
;
4253 case ParseNodeKind::BitAndAssignExpr
:
4254 return JSOp::BitAnd
;
4255 case ParseNodeKind::LshAssignExpr
:
4257 case ParseNodeKind::RshAssignExpr
:
4259 case ParseNodeKind::UrshAssignExpr
:
4261 case ParseNodeKind::MulAssignExpr
:
4263 case ParseNodeKind::DivAssignExpr
:
4265 case ParseNodeKind::ModAssignExpr
:
4267 case ParseNodeKind::PowAssignExpr
:
4269 case ParseNodeKind::CoalesceAssignExpr
:
4270 case ParseNodeKind::OrAssignExpr
:
4271 case ParseNodeKind::AndAssignExpr
:
4272 // Short-circuit assignment operators are handled elsewhere.
4275 MOZ_CRASH("unexpected compound assignment op");
4279 bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind
, ParseNode
* lhs
,
4281 JSOp compoundOp
= CompoundAssignmentParseNodeKindToJSOp(kind
);
4282 bool isCompound
= compoundOp
!= JSOp::Nop
;
4283 bool isInit
= kind
== ParseNodeKind::InitExpr
;
4285 // We estimate the number of properties this could create
4286 // if used as constructor merely by counting this.foo = assignment
4287 // or init expressions;
4289 // This currently doesn't handle this[x] = foo;
4290 if (isInit
|| kind
== ParseNodeKind::AssignExpr
) {
4291 if (lhs
->isKind(ParseNodeKind::DotExpr
)) {
4292 if (lhs
->as
<PropertyAccess
>().expression().isKind(
4293 ParseNodeKind::ThisExpr
)) {
4294 propertyAdditionEstimate
++;
4299 MOZ_ASSERT_IF(isInit
, lhs
->isKind(ParseNodeKind::DotExpr
) ||
4300 lhs
->isKind(ParseNodeKind::ElemExpr
) ||
4301 lhs
->isKind(ParseNodeKind::PrivateMemberExpr
));
4303 // |name| is used within NameOpEmitter, so its lifetime must surpass |noe|.
4304 TaggedParserAtomIndex name
;
4306 Maybe
<NameOpEmitter
> noe
;
4307 Maybe
<PropOpEmitter
> poe
;
4308 Maybe
<ElemOpEmitter
> eoe
;
4309 Maybe
<PrivateOpEmitter
> xoe
;
4311 // Deal with non-name assignments.
4314 // Purpose of anonFunctionName:
4316 // In normal name assignments (`f = function(){}`), an anonymous function gets
4317 // an inferred name based on the left-hand side name node.
4319 // In normal property assignments (`obj.x = function(){}`), the anonymous
4320 // function does not have a computed name, and rhs->isDirectRHSAnonFunction()
4321 // will be false (and anonFunctionName will not be used). However, in field
4322 // initializers (`class C { x = function(){} }`), field initialization is
4323 // implemented via a property or elem assignment (where we are now), and
4324 // rhs->isDirectRHSAnonFunction() is set - so we'll assign the name of the
4326 TaggedParserAtomIndex anonFunctionName
;
4328 switch (lhs
->getKind()) {
4329 case ParseNodeKind::Name
: {
4330 name
= lhs
->as
<NameNode
>().name();
4331 anonFunctionName
= name
;
4332 noe
.emplace(this, name
,
4333 isCompound
? NameOpEmitter::Kind::CompoundAssignment
4334 : NameOpEmitter::Kind::SimpleAssignment
);
4337 case ParseNodeKind::DotExpr
: {
4338 PropertyAccess
* prop
= &lhs
->as
<PropertyAccess
>();
4339 bool isSuper
= prop
->isSuper();
4341 isCompound
? PropOpEmitter::Kind::CompoundAssignment
4342 : isInit
? PropOpEmitter::Kind::PropInit
4343 : PropOpEmitter::Kind::SimpleAssignment
,
4344 isSuper
? PropOpEmitter::ObjKind::Super
4345 : PropOpEmitter::ObjKind::Other
);
4346 if (!poe
->prepareForObj()) {
4349 anonFunctionName
= prop
->name();
4351 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
4352 if (!emitGetThisForSuperBase(base
)) {
4353 // [stack] THIS SUPERBASE
4356 // SUPERBASE is pushed onto THIS later in poe->emitGet below.
4359 if (!emitTree(&prop
->expression())) {
4367 case ParseNodeKind::ElemExpr
: {
4368 PropertyByValue
* elem
= &lhs
->as
<PropertyByValue
>();
4369 bool isSuper
= elem
->isSuper();
4370 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
4372 isCompound
? ElemOpEmitter::Kind::CompoundAssignment
4373 : isInit
? ElemOpEmitter::Kind::PropInit
4374 : ElemOpEmitter::Kind::SimpleAssignment
,
4375 isSuper
? ElemOpEmitter::ObjKind::Super
4376 : ElemOpEmitter::ObjKind::Other
);
4377 if (!emitElemObjAndKey(elem
, isSuper
, *eoe
)) {
4378 // [stack] # if Super
4380 // [stack] # otherwise
4385 // SUPERBASE is pushed onto KEY in eoe->emitGet below.
4392 case ParseNodeKind::PrivateMemberExpr
: {
4393 PrivateMemberAccess
* privateExpr
= &lhs
->as
<PrivateMemberAccess
>();
4395 isCompound
? PrivateOpEmitter::Kind::CompoundAssignment
4396 : isInit
? PrivateOpEmitter::Kind::PropInit
4397 : PrivateOpEmitter::Kind::SimpleAssignment
,
4398 privateExpr
->privateName().name());
4399 if (!emitTree(&privateExpr
->expression())) {
4403 if (!xoe
->emitReference()) {
4407 offset
+= xoe
->numReferenceSlots();
4410 case ParseNodeKind::ArrayExpr
:
4411 case ParseNodeKind::ObjectExpr
:
4413 case ParseNodeKind::CallExpr
:
4414 if (!emitTree(lhs
)) {
4418 // Assignment to function calls is forbidden, but we have to make the
4419 // call first. Now we can throw.
4420 if (!emit2(JSOp::ThrowMsg
, uint8_t(ThrowMsgKind::AssignToCall
))) {
4424 // Rebalance the stack to placate stack-depth assertions.
4425 if (!emit1(JSOp::Pop
)) {
4435 switch (lhs
->getKind()) {
4436 case ParseNodeKind::DotExpr
: {
4437 PropertyAccess
* prop
= &lhs
->as
<PropertyAccess
>();
4438 if (!poe
->emitGet(prop
->key().atom())) {
4439 // [stack] # if Super
4440 // [stack] THIS SUPERBASE PROP
4441 // [stack] # otherwise
4447 case ParseNodeKind::ElemExpr
: {
4448 if (!eoe
->emitGet()) {
4449 // [stack] KEY THIS OBJ ELEM
4454 case ParseNodeKind::PrivateMemberExpr
: {
4455 if (!xoe
->emitGet()) {
4456 // [stack] OBJ KEY VALUE
4461 case ParseNodeKind::CallExpr
:
4462 // We just emitted a JSOp::ThrowMsg and popped the call's return
4463 // value. Push a random value to make sure the stack depth is
4465 if (!emit1(JSOp::Null
)) {
4474 switch (lhs
->getKind()) {
4475 case ParseNodeKind::Name
:
4476 if (!noe
->prepareForRhs()) {
4477 // [stack] ENV? VAL?
4480 offset
+= noe
->emittedBindOp();
4482 case ParseNodeKind::DotExpr
:
4483 if (!poe
->prepareForRhs()) {
4484 // [stack] # if Simple Assignment with Super
4485 // [stack] THIS SUPERBASE
4486 // [stack] # if Simple Assignment with other
4488 // [stack] # if Compound Assignment with Super
4489 // [stack] THIS SUPERBASE PROP
4490 // [stack] # if Compound Assignment with other
4495 case ParseNodeKind::ElemExpr
:
4496 if (!eoe
->prepareForRhs()) {
4497 // [stack] # if Simple Assignment with Super
4498 // [stack] THIS KEY SUPERBASE
4499 // [stack] # if Simple Assignment with other
4501 // [stack] # if Compound Assignment with Super
4502 // [stack] THIS KEY SUPERBASE ELEM
4503 // [stack] # if Compound Assignment with other
4504 // [stack] OBJ KEY ELEM
4508 case ParseNodeKind::PrivateMemberExpr
:
4509 // no stack adjustment needed
4516 if (!emitAssignmentRhs(rhs
, anonFunctionName
)) {
4517 // [stack] ... VAL? RHS
4521 // Assumption: Things with pre-emitted RHS values never need to be named.
4522 if (!emitAssignmentRhs(offset
)) {
4523 // [stack] ... VAL? RHS
4528 /* If += etc., emit the binary operator with a hint for the decompiler. */
4530 if (!emit1(compoundOp
)) {
4534 if (!emit1(JSOp::NopIsAssignOp
)) {
4540 /* Finally, emit the specialized assignment bytecode. */
4541 switch (lhs
->getKind()) {
4542 case ParseNodeKind::Name
: {
4543 if (!noe
->emitAssignment()) {
4549 case ParseNodeKind::DotExpr
: {
4550 PropertyAccess
* prop
= &lhs
->as
<PropertyAccess
>();
4551 if (!poe
->emitAssignment(prop
->key().atom())) {
4557 case ParseNodeKind::CallExpr
:
4558 // We threw above, so nothing to do here.
4560 case ParseNodeKind::ElemExpr
: {
4561 if (!eoe
->emitAssignment()) {
4567 case ParseNodeKind::PrivateMemberExpr
:
4568 if (!xoe
->emitAssignment()) {
4573 case ParseNodeKind::ArrayExpr
:
4574 case ParseNodeKind::ObjectExpr
:
4575 if (!emitDestructuringOps(&lhs
->as
<ListNode
>(),
4576 DestructuringFlavor::Assignment
)) {
4586 bool BytecodeEmitter::emitShortCircuitAssignment(AssignmentNode
* node
) {
4587 TDZCheckCache
tdzCache(this);
4590 switch (node
->getKind()) {
4591 case ParseNodeKind::CoalesceAssignExpr
:
4592 op
= JSOp::Coalesce
;
4594 case ParseNodeKind::OrAssignExpr
:
4597 case ParseNodeKind::AndAssignExpr
:
4601 MOZ_CRASH("Unexpected ParseNodeKind");
4604 ParseNode
* lhs
= node
->left();
4605 ParseNode
* rhs
= node
->right();
4607 // |name| is used within NameOpEmitter, so its lifetime must surpass |noe|.
4608 TaggedParserAtomIndex name
;
4610 // Select the appropriate emitter based on the left-hand side.
4611 Maybe
<NameOpEmitter
> noe
;
4612 Maybe
<PropOpEmitter
> poe
;
4613 Maybe
<ElemOpEmitter
> eoe
;
4614 Maybe
<PrivateOpEmitter
> xoe
;
4616 int32_t depth
= bytecodeSection().stackDepth();
4618 // Number of values pushed onto the stack in addition to the lhs value.
4621 // Evaluate the left-hand side expression and compute any stack values needed
4622 // for the assignment.
4623 switch (lhs
->getKind()) {
4624 case ParseNodeKind::Name
: {
4625 name
= lhs
->as
<NameNode
>().name();
4626 noe
.emplace(this, name
, NameOpEmitter::Kind::CompoundAssignment
);
4628 if (!noe
->prepareForRhs()) {
4633 numPushed
= noe
->emittedBindOp();
4637 case ParseNodeKind::DotExpr
: {
4638 PropertyAccess
* prop
= &lhs
->as
<PropertyAccess
>();
4639 bool isSuper
= prop
->isSuper();
4641 poe
.emplace(this, PropOpEmitter::Kind::CompoundAssignment
,
4642 isSuper
? PropOpEmitter::ObjKind::Super
4643 : PropOpEmitter::ObjKind::Other
);
4645 if (!poe
->prepareForObj()) {
4650 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
4651 if (!emitGetThisForSuperBase(base
)) {
4652 // [stack] THIS SUPERBASE
4656 if (!emitTree(&prop
->expression())) {
4662 if (!poe
->emitGet(prop
->key().atom())) {
4663 // [stack] # if Super
4664 // [stack] THIS SUPERBASE LHS
4665 // [stack] # otherwise
4670 if (!poe
->prepareForRhs()) {
4671 // [stack] # if Super
4672 // [stack] THIS SUPERBASE LHS
4673 // [stack] # otherwise
4678 numPushed
= 1 + isSuper
;
4682 case ParseNodeKind::ElemExpr
: {
4683 PropertyByValue
* elem
= &lhs
->as
<PropertyByValue
>();
4684 bool isSuper
= elem
->isSuper();
4685 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
4686 eoe
.emplace(this, ElemOpEmitter::Kind::CompoundAssignment
,
4687 isSuper
? ElemOpEmitter::ObjKind::Super
4688 : ElemOpEmitter::ObjKind::Other
);
4690 if (!emitElemObjAndKey(elem
, isSuper
, *eoe
)) {
4691 // [stack] # if Super
4693 // [stack] # otherwise
4698 if (!eoe
->emitGet()) {
4699 // [stack] # if Super
4700 // [stack] THIS KEY SUPERBASE LHS
4701 // [stack] # otherwise
4702 // [stack] OBJ KEY LHS
4706 if (!eoe
->prepareForRhs()) {
4707 // [stack] # if Super
4708 // [stack] THIS KEY SUPERBASE LHS
4709 // [stack] # otherwise
4710 // [stack] OBJ KEY LHS
4714 numPushed
= 2 + isSuper
;
4718 case ParseNodeKind::PrivateMemberExpr
: {
4719 PrivateMemberAccess
* privateExpr
= &lhs
->as
<PrivateMemberAccess
>();
4720 xoe
.emplace(this, PrivateOpEmitter::Kind::CompoundAssignment
,
4721 privateExpr
->privateName().name());
4722 if (!emitTree(&privateExpr
->expression())) {
4726 if (!xoe
->emitReference()) {
4730 if (!xoe
->emitGet()) {
4731 // [stack] OBJ NAME LHS
4734 numPushed
= xoe
->numReferenceSlots();
4742 MOZ_ASSERT(bytecodeSection().stackDepth() == depth
+ numPushed
+ 1);
4744 // Test for the short-circuit condition.
4746 if (!emitJump(op
, &jump
)) {
4751 // The short-circuit condition wasn't fulfilled, pop the left-hand side value
4752 // which was kept on the stack.
4753 if (!emit1(JSOp::Pop
)) {
4758 if (!emitAssignmentRhs(rhs
, name
)) {
4763 // Perform the actual assignment.
4764 switch (lhs
->getKind()) {
4765 case ParseNodeKind::Name
: {
4766 if (!noe
->emitAssignment()) {
4773 case ParseNodeKind::DotExpr
: {
4774 PropertyAccess
* prop
= &lhs
->as
<PropertyAccess
>();
4776 if (!poe
->emitAssignment(prop
->key().atom())) {
4783 case ParseNodeKind::ElemExpr
: {
4784 if (!eoe
->emitAssignment()) {
4791 case ParseNodeKind::PrivateMemberExpr
:
4792 if (!xoe
->emitAssignment()) {
4802 MOZ_ASSERT(bytecodeSection().stackDepth() == depth
+ 1);
4804 // Join with the short-circuit jump and pop anything left on the stack.
4805 if (numPushed
> 0) {
4806 JumpList jumpAroundPop
;
4807 if (!emitJump(JSOp::Goto
, &jumpAroundPop
)) {
4812 if (!emitJumpTargetAndPatch(jump
)) {
4817 // Reconstruct the stack depth after the jump.
4818 bytecodeSection().setStackDepth(depth
+ 1 + numPushed
);
4820 // Move the left-hand side value to the bottom and pop the rest.
4821 if (!emitUnpickN(numPushed
)) {
4825 if (!emitPopN(numPushed
)) {
4830 if (!emitJumpTargetAndPatch(jumpAroundPop
)) {
4831 // [stack] LHS | RHS
4835 if (!emitJumpTargetAndPatch(jump
)) {
4836 // [stack] LHS | RHS
4841 MOZ_ASSERT(bytecodeSection().stackDepth() == depth
+ 1);
4846 bool BytecodeEmitter::emitCallSiteObjectArray(ObjLiteralWriter
& writer
,
4847 ListNode
* cookedOrRaw
,
4848 ParseNode
* head
, uint32_t count
) {
4849 DebugOnly
<size_t> idx
= 0;
4850 for (ParseNode
* pn
: cookedOrRaw
->contentsFrom(head
)) {
4851 MOZ_ASSERT(pn
->isKind(ParseNodeKind::TemplateStringExpr
) ||
4852 pn
->isKind(ParseNodeKind::RawUndefinedExpr
));
4854 if (!emitObjLiteralValue(writer
, pn
)) {
4859 MOZ_ASSERT(idx
== count
);
4864 bool BytecodeEmitter::emitCallSiteObject(CallSiteNode
* callSiteObj
) {
4865 constexpr JSOp op
= JSOp::CallSiteObj
;
4867 // The first element of a call-site node is the raw-values list. Skip over it.
4868 ListNode
* raw
= callSiteObj
->rawNodes();
4869 MOZ_ASSERT(raw
->isKind(ParseNodeKind::ArrayExpr
));
4870 ParseNode
* head
= callSiteObj
->head()->pn_next
;
4872 uint32_t count
= callSiteObj
->count() - 1;
4873 MOZ_ASSERT(count
== raw
->count());
4875 ObjLiteralWriter writer
;
4876 writer
.beginCallSiteObj(op
);
4877 writer
.beginDenseArrayElements();
4879 // Write elements of the two arrays: the 'cooked' values followed by the
4881 MOZ_RELEASE_ASSERT(count
< UINT32_MAX
/ 2,
4882 "Number of elements for both arrays must fit in uint32_t");
4883 if (!emitCallSiteObjectArray(writer
, callSiteObj
, head
, count
)) {
4886 if (!emitCallSiteObjectArray(writer
, raw
, raw
->head(), count
)) {
4890 GCThingIndex cookedIndex
;
4891 if (!addObjLiteralData(writer
, &cookedIndex
)) {
4895 MOZ_ASSERT(sc
->hasCallSiteObj());
4897 return emitInternedObjectOp(cookedIndex
, op
);
4900 bool BytecodeEmitter::emitCatch(BinaryNode
* catchClause
) {
4901 // We must be nested under a try-finally statement.
4902 MOZ_ASSERT(innermostNestableControl
->is
<TryFinallyControl
>());
4904 ParseNode
* param
= catchClause
->left();
4906 // Catch parameter was omitted; just discard the exception.
4907 if (!emit1(JSOp::Pop
)) {
4911 switch (param
->getKind()) {
4912 case ParseNodeKind::ArrayExpr
:
4913 case ParseNodeKind::ObjectExpr
:
4914 if (!emitDestructuringOps(¶m
->as
<ListNode
>(),
4915 DestructuringFlavor::Declaration
)) {
4918 if (!emit1(JSOp::Pop
)) {
4923 case ParseNodeKind::Name
:
4924 if (!emitLexicalInitialization(¶m
->as
<NameNode
>())) {
4927 if (!emit1(JSOp::Pop
)) {
4937 /* Emit the catch body. */
4938 return emitTree(catchClause
->right());
4941 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See the
4942 // comment on EmitSwitch.
4943 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitTry(TryNode
* tryNode
) {
4944 LexicalScopeNode
* catchScope
= tryNode
->catchScope();
4945 ParseNode
* finallyNode
= tryNode
->finallyBlock();
4947 TryEmitter::Kind kind
;
4950 kind
= TryEmitter::Kind::TryCatchFinally
;
4952 kind
= TryEmitter::Kind::TryCatch
;
4955 MOZ_ASSERT(finallyNode
);
4956 kind
= TryEmitter::Kind::TryFinally
;
4958 TryEmitter
tryCatch(this, kind
, TryEmitter::ControlKind::Syntactic
);
4960 if (!tryCatch
.emitTry()) {
4964 if (!emitTree(tryNode
->body())) {
4968 // If this try has a catch block, emit it.
4970 // The emitted code for a catch block looks like:
4972 // [pushlexicalenv] only if any local aliased
4974 // setlocal 0; pop assign or possibly destructure exception
4975 // < catch block contents >
4977 // [poplexicalenv] only if any local aliased
4978 // if there is a finally block:
4980 // [jump target for returning from finally]
4981 // goto <after finally>
4982 if (!tryCatch
.emitCatch()) {
4986 // Emit the lexical scope and catch body.
4987 if (!emitTree(catchScope
)) {
4992 // Emit the finally handler, if there is one.
4994 if (!tryCatch
.emitFinally(Some(finallyNode
->pn_pos
.begin
))) {
4998 if (!emitTree(finallyNode
)) {
5003 if (!tryCatch
.emitEnd()) {
5010 [[nodiscard
]] bool BytecodeEmitter::emitJumpToFinally(JumpList
* jump
,
5012 // Push the continuation index.
5013 if (!emitNumberOp(idx
)) {
5018 if (!emit1(JSOp::False
)) {
5022 // Jump to the finally block.
5023 if (!emitJumpNoFallthrough(JSOp::Goto
, jump
)) {
5030 bool BytecodeEmitter::emitIf(TernaryNode
* ifNode
) {
5031 IfEmitter
ifThenElse(this);
5033 if (!ifThenElse
.emitIf(Some(ifNode
->kid1()->pn_pos
.begin
))) {
5038 ParseNode
* testNode
= ifNode
->kid1();
5039 auto conditionKind
= IfEmitter::ConditionKind::Positive
;
5040 if (testNode
->isKind(ParseNodeKind::NotExpr
)) {
5041 testNode
= testNode
->as
<UnaryNode
>().kid();
5042 conditionKind
= IfEmitter::ConditionKind::Negative
;
5045 if (!markStepBreakpoint()) {
5049 // Emit code for the condition before pushing stmtInfo.
5050 // NOTE: NotExpr of testNode may be unwrapped, and in that case the negation
5051 // is handled by conditionKind.
5052 if (!emitTree(testNode
)) {
5056 ParseNode
* elseNode
= ifNode
->kid3();
5058 if (!ifThenElse
.emitThenElse(conditionKind
)) {
5062 if (!ifThenElse
.emitThen(conditionKind
)) {
5067 /* Emit code for the then part. */
5068 if (!emitTree(ifNode
->kid2())) {
5073 if (elseNode
->isKind(ParseNodeKind::IfStmt
)) {
5074 ifNode
= &elseNode
->as
<TernaryNode
>();
5076 if (!ifThenElse
.emitElseIf(Some(ifNode
->kid1()->pn_pos
.begin
))) {
5083 if (!ifThenElse
.emitElse()) {
5087 /* Emit code for the else part. */
5088 if (!emitTree(elseNode
)) {
5093 if (!ifThenElse
.emitEnd()) {
5100 bool BytecodeEmitter::emitHoistedFunctionsInList(ListNode
* stmtList
) {
5101 MOZ_ASSERT(stmtList
->hasTopLevelFunctionDeclarations());
5103 // We can call this multiple times for sloppy eval scopes.
5104 if (stmtList
->emittedTopLevelFunctionDeclarations()) {
5108 stmtList
->setEmittedTopLevelFunctionDeclarations();
5110 for (ParseNode
* stmt
: stmtList
->contents()) {
5111 ParseNode
* maybeFun
= stmt
;
5113 if (!sc
->strict()) {
5114 while (maybeFun
->isKind(ParseNodeKind::LabelStmt
)) {
5115 maybeFun
= maybeFun
->as
<LabeledStatement
>().statement();
5119 if (maybeFun
->is
<FunctionNode
>() &&
5120 maybeFun
->as
<FunctionNode
>().functionIsHoisted()) {
5121 if (!emitTree(maybeFun
)) {
5130 bool BytecodeEmitter::emitLexicalScopeBody(
5131 ParseNode
* body
, EmitLineNumberNote emitLineNote
/* = EMIT_LINENOTE */) {
5132 if (body
->isKind(ParseNodeKind::StatementList
) &&
5133 body
->as
<ListNode
>().hasTopLevelFunctionDeclarations()) {
5134 // This block contains function statements whose definitions are
5135 // hoisted to the top of the block. Emit these as a separate pass
5136 // before the rest of the block.
5137 if (!emitHoistedFunctionsInList(&body
->as
<ListNode
>())) {
5142 // Line notes were updated by emitLexicalScope or emitScript.
5143 return emitTree(body
, ValueUsage::WantValue
, emitLineNote
);
5146 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
5147 // the comment on emitSwitch.
5148 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitLexicalScope(
5149 LexicalScopeNode
* lexicalScope
) {
5150 LexicalScopeEmitter
lse(this);
5152 ParseNode
* body
= lexicalScope
->scopeBody();
5153 if (lexicalScope
->isEmptyScope()) {
5154 if (!lse
.emitEmptyScope()) {
5158 if (!emitLexicalScopeBody(body
)) {
5162 if (!lse
.emitEnd()) {
5169 // We are about to emit some bytecode for what the spec calls "declaration
5170 // instantiation". Assign these instructions to the opening `{` of the
5171 // block. (Using the location of each declaration we're instantiating is
5172 // too weird when stepping in the debugger.)
5173 if (!ParseNodeRequiresSpecialLineNumberNotes(body
)) {
5174 if (!updateSourceCoordNotes(lexicalScope
->pn_pos
.begin
)) {
5180 if (body
->isKind(ParseNodeKind::Catch
)) {
5181 BinaryNode
* catchNode
= &body
->as
<BinaryNode
>();
5183 (!catchNode
->left() || catchNode
->left()->isKind(ParseNodeKind::Name
))
5184 ? ScopeKind::SimpleCatch
5187 kind
= lexicalScope
->kind();
5190 if (!lse
.emitScope(kind
, lexicalScope
->scopeBindings())) {
5194 if (body
->isKind(ParseNodeKind::ForStmt
)) {
5195 // for loops need to emit JSOp::FreshenLexicalEnv/JSOp::RecreateLexicalEnv
5196 // if there are lexical declarations in the head. Signal this by passing a
5197 // non-nullptr lexical scope.
5198 if (!emitFor(&body
->as
<ForNode
>(), &lse
.emitterScope())) {
5202 if (!emitLexicalScopeBody(body
, SUPPRESS_LINENOTE
)) {
5207 if (!lse
.emitEnd()) {
5213 bool BytecodeEmitter::emitWith(BinaryNode
* withNode
) {
5214 // Ensure that the column of the 'with' is set properly.
5215 if (!updateSourceCoordNotes(withNode
->left()->pn_pos
.begin
)) {
5219 if (!markStepBreakpoint()) {
5223 if (!emitTree(withNode
->left())) {
5227 EmitterScope
emitterScope(this);
5228 if (!emitterScope
.enterWith(this)) {
5232 if (!emitTree(withNode
->right())) {
5236 return emitterScope
.leave(this);
5239 bool BytecodeEmitter::emitCopyDataProperties(CopyOption option
) {
5240 DebugOnly
<int32_t> depth
= bytecodeSection().stackDepth();
5243 if (option
== CopyOption::Filtered
) {
5244 MOZ_ASSERT(depth
> 2);
5245 // [stack] TARGET SOURCE SET
5248 if (!emitAtomOp(JSOp::GetIntrinsic
,
5249 TaggedParserAtomIndex::WellKnown::CopyDataProperties())) {
5250 // [stack] TARGET SOURCE SET COPYDATAPROPERTIES
5254 MOZ_ASSERT(depth
> 1);
5255 // [stack] TARGET SOURCE
5260 TaggedParserAtomIndex::WellKnown::CopyDataPropertiesUnfiltered())) {
5261 // [stack] TARGET SOURCE COPYDATAPROPERTIES
5266 if (!emit1(JSOp::Undefined
)) {
5267 // [stack] TARGET SOURCE SET? COPYDATAPROPERTIES
5271 if (!emit2(JSOp::Pick
, argc
+ 1)) {
5272 // [stack] SOURCE SET? COPYDATAPROPERTIES UNDEFINED
5276 if (!emit2(JSOp::Pick
, argc
+ 1)) {
5277 // [stack] SET? COPYDATAPROPERTIES UNDEFINED TARGET
5281 if (option
== CopyOption::Filtered
) {
5282 if (!emit2(JSOp::Pick
, argc
+ 1)) {
5283 // [stack] COPYDATAPROPERTIES UNDEFINED TARGET SOURCE SET
5287 // Callee is always self-hosted instrinsic, and cannot be content function.
5288 if (!emitCall(JSOp::CallIgnoresRv
, argc
)) {
5293 if (!emit1(JSOp::Pop
)) {
5298 MOZ_ASSERT(depth
- int(argc
) == bytecodeSection().stackDepth());
5302 bool BytecodeEmitter::emitBigIntOp(BigIntLiteral
* bigint
) {
5304 if (!perScriptData().gcThingList().append(bigint
, &index
)) {
5307 return emitGCIndexOp(JSOp::BigInt
, index
);
5310 bool BytecodeEmitter::emitIterable(ParseNode
* value
,
5311 SelfHostedIter selfHostedIter
,
5312 IteratorKind iterKind
) {
5313 MOZ_ASSERT(getSelfHostedIterFor(value
) == selfHostedIter
);
5315 if (!emitTree(value
)) {
5320 switch (selfHostedIter
) {
5321 case SelfHostedIter::Deny
:
5322 case SelfHostedIter::AllowContent
:
5326 case SelfHostedIter::AllowContentWith
: {
5327 // This is the following case:
5329 // for (const nextValue of allowContentIterWith(items, usingIterator)) {
5331 // `items` is emitted by `emitTree(value)` above, and the result is on the
5332 // stack as ITERABLE.
5333 // `usingIterator` is the value of `items[Symbol.iterator]`, that's
5334 // already retrieved.
5335 ListNode
* argsList
= value
->as
<CallNode
>().args();
5336 MOZ_ASSERT_IF(iterKind
== IteratorKind::Sync
, argsList
->count() == 2);
5337 MOZ_ASSERT_IF(iterKind
== IteratorKind::Async
, argsList
->count() == 3);
5339 if (!emitTree(argsList
->head()->pn_next
)) {
5340 // [stack] ITERABLE ITERFN
5344 // Async iterator has two possible iterators: An async iterator and a sync
5346 if (iterKind
== IteratorKind::Async
) {
5347 if (!emitTree(argsList
->head()->pn_next
->pn_next
)) {
5348 // [stack] ITERABLE ASYNC_ITERFN SYNC_ITERFN
5353 // [stack] ITERABLE ASYNC_ITERFN? SYNC_ITERFN
5357 case SelfHostedIter::AllowContentWithNext
: {
5358 // This is the following case:
5360 // for (const nextValue of allowContentIterWithNext(iterator, next)) {
5362 // `iterator` is emitted by `emitTree(value)` above, and the result is on
5363 // the stack as ITER.
5364 // `next` is the value of `iterator.next`, that's already retrieved.
5365 ListNode
* argsList
= value
->as
<CallNode
>().args();
5366 MOZ_ASSERT(argsList
->count() == 2);
5368 if (!emitTree(argsList
->head()->pn_next
)) {
5369 // [stack] ITER NEXT
5373 if (!emit1(JSOp::Swap
)) {
5374 // [stack] NEXT ITER
5378 // [stack] NEXT ITER
5383 MOZ_CRASH("invalid self-hosted iteration kind");
5386 bool BytecodeEmitter::emitIterator(SelfHostedIter selfHostedIter
) {
5387 MOZ_ASSERT(selfHostedIter
!= SelfHostedIter::Deny
||
5388 emitterMode
!= BytecodeEmitter::SelfHosting
,
5389 "[Symbol.iterator]() call is prohibited in self-hosted code "
5390 "because it can run user-modifiable iteration code");
5392 if (selfHostedIter
== SelfHostedIter::AllowContentWithNext
) {
5393 // [stack] NEXT ITER
5395 // Nothing to do, stack already contains the iterator and its `next` method.
5399 if (selfHostedIter
!= SelfHostedIter::AllowContentWith
) {
5402 // Convert iterable to iterator.
5403 if (!emit1(JSOp::Dup
)) {
5407 if (!emit2(JSOp::Symbol
, uint8_t(JS::SymbolCode::iterator
))) {
5408 // [stack] OBJ OBJ @@ITERATOR
5411 if (!emitElemOpBase(JSOp::GetElem
)) {
5412 // [stack] OBJ ITERFN
5417 if (!emit1(JSOp::Swap
)) {
5418 // [stack] ITERFN OBJ
5421 if (!emitCall(getIterCallOp(JSOp::CallIter
, selfHostedIter
), 0)) {
5425 if (!emitCheckIsObj(CheckIsObjectKind::GetIterator
)) {
5429 if (!emit1(JSOp::Dup
)) {
5430 // [stack] ITER ITER
5433 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::next())) {
5434 // [stack] ITER NEXT
5437 if (!emit1(JSOp::Swap
)) {
5438 // [stack] NEXT ITER
5444 bool BytecodeEmitter::emitAsyncIterator(SelfHostedIter selfHostedIter
) {
5445 MOZ_ASSERT(selfHostedIter
!= SelfHostedIter::AllowContentWithNext
);
5446 MOZ_ASSERT(selfHostedIter
!= SelfHostedIter::Deny
||
5447 emitterMode
!= BytecodeEmitter::SelfHosting
,
5448 "[Symbol.asyncIterator]() call is prohibited in self-hosted code "
5449 "because it can run user-modifiable iteration code");
5451 if (selfHostedIter
!= SelfHostedIter::AllowContentWith
) {
5454 // Convert iterable to iterator.
5455 if (!emit1(JSOp::Dup
)) {
5459 if (!emit2(JSOp::Symbol
, uint8_t(JS::SymbolCode::asyncIterator
))) {
5460 // [stack] OBJ OBJ @@ASYNCITERATOR
5463 if (!emitElemOpBase(JSOp::GetElem
)) {
5464 // [stack] OBJ ASYNC_ITERFN
5468 // [stack] OBJ ASYNC_ITERFN SYNC_ITERFN
5470 if (!emitElemOpBase(JSOp::Swap
)) {
5471 // [stack] OBJ SYNC_ITERFN ASYNC_ITERFN
5476 InternalIfEmitter
ifAsyncIterIsUndefined(this);
5477 if (!emit1(JSOp::IsNullOrUndefined
)) {
5478 // [stack] OBJ SYNC_ITERFN? ASYNC_ITERFN NULL-OR-UNDEF
5481 if (!ifAsyncIterIsUndefined
.emitThenElse()) {
5482 // [stack] OBJ SYNC_ITERFN? ASYNC_ITERFN
5486 if (!emit1(JSOp::Pop
)) {
5487 // [stack] OBJ SYNC_ITERFN?
5491 if (selfHostedIter
!= SelfHostedIter::AllowContentWith
) {
5492 if (!emit1(JSOp::Dup
)) {
5496 if (!emit2(JSOp::Symbol
, uint8_t(JS::SymbolCode::iterator
))) {
5497 // [stack] OBJ OBJ @@ITERATOR
5500 if (!emitElemOpBase(JSOp::GetElem
)) {
5501 // [stack] OBJ SYNC_ITERFN
5505 // [stack] OBJ SYNC_ITERFN
5508 if (!emit1(JSOp::Swap
)) {
5509 // [stack] SYNC_ITERFN OBJ
5512 if (!emitCall(getIterCallOp(JSOp::CallIter
, selfHostedIter
), 0)) {
5516 if (!emitCheckIsObj(CheckIsObjectKind::GetIterator
)) {
5521 if (!emit1(JSOp::Dup
)) {
5522 // [stack] ITER ITER
5525 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::next())) {
5526 // [stack] ITER SYNCNEXT
5530 if (!emit1(JSOp::ToAsyncIter
)) {
5535 if (!ifAsyncIterIsUndefined
.emitElse()) {
5536 // [stack] OBJ SYNC_ITERFN? ASYNC_ITERFN
5540 if (selfHostedIter
== SelfHostedIter::AllowContentWith
) {
5541 if (!emit1(JSOp::Swap
)) {
5542 // [stack] OBJ ASYNC_ITERFN SYNC_ITERFN
5545 if (!emit1(JSOp::Pop
)) {
5546 // [stack] OBJ ASYNC_ITERFN
5551 if (!emit1(JSOp::Swap
)) {
5552 // [stack] ASYNC_ITERFN OBJ
5555 if (!emitCall(getIterCallOp(JSOp::CallIter
, selfHostedIter
), 0)) {
5559 if (!emitCheckIsObj(CheckIsObjectKind::GetAsyncIterator
)) {
5564 if (!ifAsyncIterIsUndefined
.emitEnd()) {
5569 if (!emit1(JSOp::Dup
)) {
5570 // [stack] ITER ITER
5573 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::next())) {
5574 // [stack] ITER NEXT
5577 if (!emit1(JSOp::Swap
)) {
5578 // [stack] NEXT ITER
5585 bool BytecodeEmitter::emitSpread(SelfHostedIter selfHostedIter
) {
5586 // [stack] NEXT ITER ARR I
5587 return emitSpread(selfHostedIter
, 2, JSOp::InitElemInc
);
5588 // [stack] ARR FINAL_INDEX
5591 bool BytecodeEmitter::emitSpread(SelfHostedIter selfHostedIter
,
5592 int spreadeeStackItems
, JSOp storeElementOp
) {
5593 LoopControl
loopInfo(this, StatementKind::Spread
);
5594 // In the [stack] annotations, (spreadee) can be "ARR I" (when spreading
5595 // into an array or into call parameters, or "TUPLE" (when spreading into a
5598 if (!loopInfo
.emitLoopHead(this, Nothing())) {
5599 // [stack] NEXT ITER (spreadee)
5605 auto loopDepth
= bytecodeSection().stackDepth();
5608 // Spread operations can't contain |continue|, so don't bother setting loop
5609 // and enclosing "update" offsets, as we do with for-loops.
5611 if (!emitDupAt(spreadeeStackItems
+ 1, 2)) {
5612 // [stack] NEXT ITER (spreadee) NEXT ITER
5615 if (!emitIteratorNext(Nothing(), IteratorKind::Sync
, selfHostedIter
)) {
5616 // [stack] NEXT ITER (spreadee) RESULT
5619 if (!emit1(JSOp::Dup
)) {
5620 // [stack] NEXT ITER (spreadee) RESULT RESULT
5623 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::done())) {
5624 // [stack] NEXT ITER (spreadee) RESULT DONE
5627 if (!emitJump(JSOp::JumpIfTrue
, &loopInfo
.breaks
)) {
5628 // [stack] NEXT ITER (spreadee) RESULT
5632 // Emit code to assign result.value to the iteration variable.
5633 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::value())) {
5634 // [stack] NEXT ITER (spreadee) VALUE
5637 if (!emit1(storeElementOp
)) {
5638 // [stack] NEXT ITER (spreadee)
5642 if (!loopInfo
.emitLoopEnd(this, JSOp::Goto
, TryNoteKind::ForOf
)) {
5643 // [stack] NEXT ITER (spreadee)
5647 MOZ_ASSERT(bytecodeSection().stackDepth() == loopDepth
);
5650 // When we leave the loop body and jump to this point, the result value is
5651 // still on the stack. Account for that by updating the stack depth
5653 bytecodeSection().setStackDepth(bytecodeSection().stackDepth() + 1);
5655 // No continues should occur in spreads.
5656 MOZ_ASSERT(!loopInfo
.continues
.offset
.valid());
5658 if (!emit2(JSOp::Pick
, spreadeeStackItems
+ 2)) {
5659 // [stack] ITER (spreadee) RESULT NEXT
5662 if (!emit2(JSOp::Pick
, spreadeeStackItems
+ 2)) {
5663 // [stack] (spreadee) RESULT NEXT ITER
5668 // [stack] (spreadee)
5671 bool BytecodeEmitter::emitInitializeForInOrOfTarget(TernaryNode
* forHead
) {
5672 MOZ_ASSERT(forHead
->isKind(ParseNodeKind::ForIn
) ||
5673 forHead
->isKind(ParseNodeKind::ForOf
));
5675 MOZ_ASSERT(bytecodeSection().stackDepth() >= 1,
5676 "must have a per-iteration value for initializing");
5678 ParseNode
* target
= forHead
->kid1();
5679 MOZ_ASSERT(!forHead
->kid2());
5681 // If the for-in/of loop didn't have a variable declaration, per-loop
5682 // initialization is just assigning the iteration value to a target
5684 if (!target
->is
<DeclarationListNode
>()) {
5685 return emitAssignmentOrInit(ParseNodeKind::AssignExpr
, target
, nullptr);
5686 // [stack] ... ITERVAL
5689 // Otherwise, per-loop initialization is (possibly) declaration
5690 // initialization. If the declaration is a lexical declaration, it must be
5691 // initialized. If the declaration is a variable declaration, an
5692 // assignment to that name (which does *not* necessarily assign to the
5693 // variable!) must be generated.
5695 auto* declarationList
= &target
->as
<DeclarationListNode
>();
5696 if (!updateSourceCoordNotes(declarationList
->pn_pos
.begin
)) {
5700 target
= declarationList
->singleBinding();
5702 NameNode
* nameNode
= nullptr;
5703 if (target
->isKind(ParseNodeKind::Name
)) {
5704 nameNode
= &target
->as
<NameNode
>();
5705 } else if (target
->isKind(ParseNodeKind::AssignExpr
)) {
5706 BinaryNode
* assignNode
= &target
->as
<BinaryNode
>();
5707 if (assignNode
->left()->is
<NameNode
>()) {
5708 nameNode
= &assignNode
->left()->as
<NameNode
>();
5713 auto nameAtom
= nameNode
->name();
5714 NameOpEmitter
noe(this, nameAtom
, NameOpEmitter::Kind::Initialize
);
5715 if (!noe
.prepareForRhs()) {
5718 if (noe
.emittedBindOp()) {
5719 // Per-iteration initialization in for-in/of loops computes the
5720 // iteration value *before* initializing. Thus the initializing
5721 // value may be buried under a bind-specific value on the stack.
5722 // Swap it to the top of the stack.
5723 MOZ_ASSERT(bytecodeSection().stackDepth() >= 2);
5724 if (!emit1(JSOp::Swap
)) {
5728 // In cases of emitting a frame slot or environment slot,
5729 // nothing needs be done.
5730 MOZ_ASSERT(bytecodeSection().stackDepth() >= 1);
5732 if (!noe
.emitAssignment()) {
5736 // The caller handles removing the iteration value from the stack.
5741 !target
->isKind(ParseNodeKind::AssignExpr
),
5742 "for-in/of loop destructuring declarations can't have initializers");
5744 MOZ_ASSERT(target
->isKind(ParseNodeKind::ArrayExpr
) ||
5745 target
->isKind(ParseNodeKind::ObjectExpr
));
5746 return emitDestructuringOps(&target
->as
<ListNode
>(),
5747 DestructuringFlavor::Declaration
);
5750 bool BytecodeEmitter::emitForOf(ForNode
* forOfLoop
,
5751 const EmitterScope
* headLexicalEmitterScope
) {
5752 MOZ_ASSERT(forOfLoop
->isKind(ParseNodeKind::ForStmt
));
5754 TernaryNode
* forOfHead
= forOfLoop
->head();
5755 MOZ_ASSERT(forOfHead
->isKind(ParseNodeKind::ForOf
));
5757 unsigned iflags
= forOfLoop
->iflags();
5758 IteratorKind iterKind
=
5759 (iflags
& JSITER_FORAWAITOF
) ? IteratorKind::Async
: IteratorKind::Sync
;
5760 MOZ_ASSERT_IF(iterKind
== IteratorKind::Async
, sc
->isSuspendableContext());
5761 MOZ_ASSERT_IF(iterKind
== IteratorKind::Async
,
5762 sc
->asSuspendableContext()->isAsync());
5764 ParseNode
* forHeadExpr
= forOfHead
->kid3();
5766 // Certain builtins (e.g. Array.from) are implemented in self-hosting
5768 auto selfHostedIter
= getSelfHostedIterFor(forHeadExpr
);
5769 ForOfEmitter
forOf(this, headLexicalEmitterScope
, selfHostedIter
, iterKind
);
5771 if (!forOf
.emitIterated()) {
5776 if (!updateSourceCoordNotes(forHeadExpr
->pn_pos
.begin
)) {
5779 if (!markStepBreakpoint()) {
5782 if (!emitIterable(forHeadExpr
, selfHostedIter
, iterKind
)) {
5787 if (headLexicalEmitterScope
) {
5788 DebugOnly
<ParseNode
*> forOfTarget
= forOfHead
->kid1();
5789 MOZ_ASSERT(forOfTarget
->isKind(ParseNodeKind::LetDecl
) ||
5790 forOfTarget
->isKind(ParseNodeKind::ConstDecl
));
5793 if (!forOf
.emitInitialize(forOfHead
->pn_pos
.begin
)) {
5794 // [stack] NEXT ITER VALUE
5798 if (!emitInitializeForInOrOfTarget(forOfHead
)) {
5799 // [stack] NEXT ITER VALUE
5803 if (!forOf
.emitBody()) {
5804 // [stack] NEXT ITER UNDEF
5808 // Perform the loop body.
5809 ParseNode
* forBody
= forOfLoop
->body();
5810 if (!emitTree(forBody
)) {
5811 // [stack] NEXT ITER UNDEF
5815 if (!forOf
.emitEnd(forHeadExpr
->pn_pos
.begin
)) {
5823 bool BytecodeEmitter::emitForIn(ForNode
* forInLoop
,
5824 const EmitterScope
* headLexicalEmitterScope
) {
5825 TernaryNode
* forInHead
= forInLoop
->head();
5826 MOZ_ASSERT(forInHead
->isKind(ParseNodeKind::ForIn
));
5828 ForInEmitter
forIn(this, headLexicalEmitterScope
);
5830 // Annex B: Evaluate the var-initializer expression if present.
5831 // |for (var i = initializer in expr) { ... }|
5832 ParseNode
* forInTarget
= forInHead
->kid1();
5833 if (forInTarget
->is
<DeclarationListNode
>()) {
5834 auto* declarationList
= &forInTarget
->as
<DeclarationListNode
>();
5836 ParseNode
* decl
= declarationList
->singleBinding();
5837 if (decl
->isKind(ParseNodeKind::AssignExpr
)) {
5838 BinaryNode
* assignNode
= &decl
->as
<BinaryNode
>();
5839 if (assignNode
->left()->is
<NameNode
>()) {
5840 NameNode
* nameNode
= &assignNode
->left()->as
<NameNode
>();
5841 ParseNode
* initializer
= assignNode
->right();
5843 forInTarget
->isKind(ParseNodeKind::VarStmt
),
5844 "for-in initializers are only permitted for |var| declarations");
5846 if (!updateSourceCoordNotes(decl
->pn_pos
.begin
)) {
5850 auto nameAtom
= nameNode
->name();
5851 NameOpEmitter
noe(this, nameAtom
, NameOpEmitter::Kind::Initialize
);
5852 if (!noe
.prepareForRhs()) {
5855 if (!emitInitializer(initializer
, nameNode
)) {
5858 if (!noe
.emitAssignment()) {
5862 // Pop the initializer.
5863 if (!emit1(JSOp::Pop
)) {
5870 if (!forIn
.emitIterated()) {
5875 // Evaluate the expression being iterated.
5876 ParseNode
* expr
= forInHead
->kid3();
5878 if (!updateSourceCoordNotes(expr
->pn_pos
.begin
)) {
5881 if (!markStepBreakpoint()) {
5884 if (!emitTree(expr
)) {
5889 MOZ_ASSERT(forInLoop
->iflags() == 0);
5891 MOZ_ASSERT_IF(headLexicalEmitterScope
,
5892 forInTarget
->isKind(ParseNodeKind::LetDecl
) ||
5893 forInTarget
->isKind(ParseNodeKind::ConstDecl
));
5895 if (!forIn
.emitInitialize()) {
5896 // [stack] ITER ITERVAL
5900 if (!emitInitializeForInOrOfTarget(forInHead
)) {
5901 // [stack] ITER ITERVAL
5905 if (!forIn
.emitBody()) {
5906 // [stack] ITER ITERVAL
5910 // Perform the loop body.
5911 ParseNode
* forBody
= forInLoop
->body();
5912 if (!emitTree(forBody
)) {
5913 // [stack] ITER ITERVAL
5917 if (!forIn
.emitEnd(forInHead
->pn_pos
.begin
)) {
5925 /* C-style `for (init; cond; update) ...` loop. */
5926 bool BytecodeEmitter::emitCStyleFor(
5927 ForNode
* forNode
, const EmitterScope
* headLexicalEmitterScope
) {
5928 TernaryNode
* forHead
= forNode
->head();
5929 ParseNode
* forBody
= forNode
->body();
5930 ParseNode
* init
= forHead
->kid1();
5931 ParseNode
* cond
= forHead
->kid2();
5932 ParseNode
* update
= forHead
->kid3();
5933 bool isLet
= init
&& init
->isKind(ParseNodeKind::LetDecl
);
5935 CForEmitter
cfor(this, isLet
? headLexicalEmitterScope
: nullptr);
5937 if (!cfor
.emitInit(init
? Some(init
->pn_pos
.begin
) : Nothing())) {
5942 // If the head of this for-loop declared any lexical variables, the parser
5943 // wrapped this ParseNodeKind::For node in a ParseNodeKind::LexicalScope
5944 // representing the implicit scope of those variables. By the time we get
5945 // here, we have already entered that scope. So far, so good.
5947 // Emit the `init` clause, whether it's an expression or a variable
5948 // declaration. (The loop variables were hoisted into an enclosing
5949 // scope, but we still need to emit code for the initializers.)
5950 if (init
->is
<DeclarationListNode
>()) {
5951 MOZ_ASSERT(!init
->as
<DeclarationListNode
>().empty());
5953 if (!emitTree(init
)) {
5958 if (!updateSourceCoordNotes(init
->pn_pos
.begin
)) {
5961 if (!markStepBreakpoint()) {
5965 // 'init' is an expression, not a declaration. emitTree left its
5966 // value on the stack.
5967 if (!emitTree(init
, ValueUsage::IgnoreValue
)) {
5971 if (!emit1(JSOp::Pop
)) {
5978 if (!cfor
.emitCond(cond
? Some(cond
->pn_pos
.begin
) : Nothing())) {
5984 if (!updateSourceCoordNotes(cond
->pn_pos
.begin
)) {
5987 if (!markStepBreakpoint()) {
5990 if (!emitTree(cond
)) {
5996 if (!cfor
.emitBody(cond
? CForEmitter::Cond::Present
5997 : CForEmitter::Cond::Missing
)) {
6002 if (!emitTree(forBody
)) {
6007 if (!cfor
.emitUpdate(
6008 update
? CForEmitter::Update::Present
: CForEmitter::Update::Missing
,
6009 update
? Some(update
->pn_pos
.begin
) : Nothing())) {
6014 // Check for update code to do before the condition (if any).
6016 if (!updateSourceCoordNotes(update
->pn_pos
.begin
)) {
6019 if (!markStepBreakpoint()) {
6022 if (!emitTree(update
, ValueUsage::IgnoreValue
)) {
6028 if (!cfor
.emitEnd(forNode
->pn_pos
.begin
)) {
6036 bool BytecodeEmitter::emitFor(ForNode
* forNode
,
6037 const EmitterScope
* headLexicalEmitterScope
) {
6038 if (forNode
->head()->isKind(ParseNodeKind::ForHead
)) {
6039 return emitCStyleFor(forNode
, headLexicalEmitterScope
);
6042 if (!updateLineNumberNotes(forNode
->pn_pos
.begin
)) {
6046 if (forNode
->head()->isKind(ParseNodeKind::ForIn
)) {
6047 return emitForIn(forNode
, headLexicalEmitterScope
);
6050 MOZ_ASSERT(forNode
->head()->isKind(ParseNodeKind::ForOf
));
6051 return emitForOf(forNode
, headLexicalEmitterScope
);
6054 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitFunction(
6055 FunctionNode
* funNode
, bool needsProto
/* = false */) {
6056 FunctionBox
* funbox
= funNode
->funbox();
6060 FunctionEmitter
fe(this, funbox
, funNode
->syntaxKind(),
6061 funNode
->functionIsHoisted()
6062 ? FunctionEmitter::IsHoisted::Yes
6063 : FunctionEmitter::IsHoisted::No
);
6065 // |wasEmittedByEnclosingScript| flag is set to true once the function has
6066 // been emitted. Function definitions that need hoisting to the top of the
6067 // function will be seen by emitFunction in two places.
6068 if (funbox
->wasEmittedByEnclosingScript()) {
6069 if (!fe
.emitAgain()) {
6073 MOZ_ASSERT(funNode
->functionIsHoisted());
6074 } else if (funbox
->isInterpreted()) {
6075 if (!funbox
->emitBytecode
) {
6076 return fe
.emitLazy();
6080 if (!fe
.prepareForNonLazy()) {
6085 BytecodeEmitter
bce2(this, funbox
);
6086 if (!bce2
.init(funNode
->pn_pos
)) {
6090 /* We measured the max scope depth when we parsed the function. */
6091 if (!bce2
.emitFunctionScript(funNode
)) {
6095 if (!fe
.emitNonLazyEnd()) {
6100 if (!fe
.emitAsmJSModule()) {
6106 // Track the last emitted top-level self-hosted function, so that intrinsics
6107 // can adjust attributes at parse time.
6109 // NOTE: We also disallow lambda functions in the top-level body. This is done
6110 // to simplify handling of the self-hosted stencil. Within normal function
6111 // declarations there are no such restrictions.
6112 if (emitterMode
== EmitterMode::SelfHosting
) {
6113 if (sc
->isTopLevelContext()) {
6114 MOZ_ASSERT(!funbox
->isLambda());
6115 MOZ_ASSERT(funbox
->explicitName());
6116 prevSelfHostedTopLevelFunction
= funbox
;
6123 bool BytecodeEmitter::emitDo(BinaryNode
* doNode
) {
6124 ParseNode
* bodyNode
= doNode
->left();
6126 DoWhileEmitter
doWhile(this);
6127 if (!doWhile
.emitBody(doNode
->pn_pos
.begin
, getOffsetForLoop(bodyNode
))) {
6131 if (!emitTree(bodyNode
)) {
6135 if (!doWhile
.emitCond()) {
6139 ParseNode
* condNode
= doNode
->right();
6140 if (!updateSourceCoordNotes(condNode
->pn_pos
.begin
)) {
6143 if (!markStepBreakpoint()) {
6146 if (!emitTree(condNode
)) {
6150 if (!doWhile
.emitEnd()) {
6157 bool BytecodeEmitter::emitWhile(BinaryNode
* whileNode
) {
6158 ParseNode
* bodyNode
= whileNode
->right();
6160 WhileEmitter
wh(this);
6162 ParseNode
* condNode
= whileNode
->left();
6163 if (!wh
.emitCond(whileNode
->pn_pos
.begin
, getOffsetForLoop(condNode
),
6164 whileNode
->pn_pos
.end
)) {
6168 if (!updateSourceCoordNotes(condNode
->pn_pos
.begin
)) {
6171 if (!markStepBreakpoint()) {
6174 if (!emitTree(condNode
)) {
6178 if (!wh
.emitBody()) {
6181 if (!emitTree(bodyNode
)) {
6185 if (!wh
.emitEnd()) {
6192 bool BytecodeEmitter::emitBreak(TaggedParserAtomIndex label
) {
6193 BreakableControl
* target
;
6195 // Any statement with the matching label may be the break target.
6196 auto hasSameLabel
= [label
](LabelControl
* labelControl
) {
6197 return labelControl
->label() == label
;
6199 target
= findInnermostNestableControl
<LabelControl
>(hasSameLabel
);
6201 auto isNotLabel
= [](BreakableControl
* control
) {
6202 return !control
->is
<LabelControl
>();
6204 target
= findInnermostNestableControl
<BreakableControl
>(isNotLabel
);
6207 return emitGoto(target
, GotoKind::Break
);
6210 bool BytecodeEmitter::emitContinue(TaggedParserAtomIndex label
) {
6211 LoopControl
* target
= nullptr;
6213 // Find the loop statement enclosed by the matching label.
6214 NestableControl
* control
= innermostNestableControl
;
6215 while (!control
->is
<LabelControl
>() ||
6216 control
->as
<LabelControl
>().label() != label
) {
6217 if (control
->is
<LoopControl
>()) {
6218 target
= &control
->as
<LoopControl
>();
6220 control
= control
->enclosing();
6223 target
= findInnermostNestableControl
<LoopControl
>();
6225 return emitGoto(target
, GotoKind::Continue
);
6228 bool BytecodeEmitter::emitGetFunctionThis(NameNode
* thisName
) {
6229 MOZ_ASSERT(sc
->hasFunctionThisBinding());
6230 MOZ_ASSERT(thisName
->isName(TaggedParserAtomIndex::WellKnown::dot_this_()));
6232 if (!updateLineNumberNotes(thisName
->pn_pos
.begin
)) {
6236 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
6240 if (sc
->needsThisTDZChecks()) {
6241 if (!emit1(JSOp::CheckThis
)) {
6250 bool BytecodeEmitter::emitGetThisForSuperBase(UnaryNode
* superBase
) {
6251 MOZ_ASSERT(superBase
->isKind(ParseNodeKind::SuperBase
));
6252 NameNode
* nameNode
= &superBase
->kid()->as
<NameNode
>();
6253 return emitGetFunctionThis(nameNode
);
6257 bool BytecodeEmitter::emitThisLiteral(ThisLiteral
* pn
) {
6258 if (ParseNode
* kid
= pn
->kid()) {
6259 NameNode
* thisName
= &kid
->as
<NameNode
>();
6260 return emitGetFunctionThis(thisName
);
6264 if (sc
->thisBinding() == ThisBinding::Module
) {
6265 return emit1(JSOp::Undefined
);
6269 MOZ_ASSERT(sc
->thisBinding() == ThisBinding::Global
);
6271 MOZ_ASSERT(outermostScope().hasNonSyntacticScopeOnChain() ==
6272 sc
->hasNonSyntacticScope());
6273 if (sc
->hasNonSyntacticScope()) {
6274 return emit1(JSOp::NonSyntacticGlobalThis
);
6278 return emit1(JSOp::GlobalThis
);
6282 bool BytecodeEmitter::emitCheckDerivedClassConstructorReturn() {
6284 lookupName(TaggedParserAtomIndex::WellKnown::dot_this_()).hasKnownSlot());
6285 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
6288 if (!emit1(JSOp::CheckReturn
)) {
6291 if (!emit1(JSOp::SetRval
)) {
6297 bool BytecodeEmitter::emitNewTarget() {
6298 MOZ_ASSERT(sc
->allowNewTarget());
6300 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_newTarget_())) {
6301 // [stack] NEW.TARGET
6307 bool BytecodeEmitter::emitNewTarget(NewTargetNode
* pn
) {
6308 MOZ_ASSERT(pn
->newTargetName()->isName(
6309 TaggedParserAtomIndex::WellKnown::dot_newTarget_()));
6311 return emitNewTarget();
6314 bool BytecodeEmitter::emitNewTarget(CallNode
* pn
) {
6315 MOZ_ASSERT(pn
->callOp() == JSOp::SuperCall
||
6316 pn
->callOp() == JSOp::SpreadSuperCall
);
6318 // The parser is responsible for marking the "new.target" binding as being
6319 // implicitly used in super() calls.
6320 return emitNewTarget();
6323 bool BytecodeEmitter::emitReturn(UnaryNode
* returnNode
) {
6324 if (!updateSourceCoordNotes(returnNode
->pn_pos
.begin
)) {
6328 if (!markStepBreakpoint()) {
6332 /* Push a return value */
6333 if (ParseNode
* expr
= returnNode
->kid()) {
6334 if (!emitTree(expr
)) {
6338 if (sc
->asSuspendableContext()->isAsync() &&
6339 sc
->asSuspendableContext()->isGenerator()) {
6340 if (!emitAwaitInInnermostScope()) {
6345 /* No explicit return value provided */
6346 if (!emit1(JSOp::Undefined
)) {
6351 // We know functionBodyEndPos is set because "return" is only
6352 // valid in a function, and so we've passed through
6353 // emitFunctionScript.
6354 if (!updateSourceCoordNotes(*functionBodyEndPos
)) {
6359 * The return value is currently on the stack. We would like to
6360 * generate JSOp::Return, but if we have work to do before returning,
6361 * we will instead generate JSOp::SetRval / JSOp::RetRval.
6363 * We don't know whether we will need fixup code until after calling
6364 * prepareForNonLocalJumpToOutermost, so we start by generating
6365 * JSOp::SetRval, then mutate it to JSOp::Return in finishReturn if it
6368 BytecodeOffset setRvalOffset
= bytecodeSection().offset();
6369 if (!emit1(JSOp::SetRval
)) {
6373 NonLocalExitControl
nle(this, NonLocalExitKind::Return
);
6374 return nle
.emitReturn(setRvalOffset
);
6377 bool BytecodeEmitter::finishReturn(BytecodeOffset setRvalOffset
) {
6378 // The return value is currently in rval. Depending on the current function,
6379 // we may have to do additional work before returning:
6380 // - Derived class constructors must check if the return value is an object.
6381 // - Generators and async functions must do a final yield.
6382 // - Non-async generators must return the value as an iterator result:
6383 // { value: <rval>, done: true }
6384 // - Non-generator async functions must resolve the function's result promise
6387 // If we have not generated any code since the SetRval that stored the return
6388 // value, we can also optimize the bytecode by rewriting that SetRval as a
6389 // JSOp::Return. See |emitReturn| above.
6391 bool isDerivedClassConstructor
=
6392 sc
->isFunctionBox() && sc
->asFunctionBox()->isDerivedClassConstructor();
6393 bool needsFinalYield
=
6394 sc
->isFunctionBox() && sc
->asFunctionBox()->needsFinalYield();
6395 bool isSimpleReturn
=
6396 setRvalOffset
.valid() &&
6397 setRvalOffset
+ BytecodeOffsetDiff(JSOpLength_SetRval
) ==
6398 bytecodeSection().offset();
6400 if (isDerivedClassConstructor
) {
6401 MOZ_ASSERT(!needsFinalYield
);
6402 if (!emitJump(JSOp::Goto
, &endOfDerivedClassConstructorBody
)) {
6408 if (needsFinalYield
) {
6409 if (!emitJump(JSOp::Goto
, &finalYields
)) {
6415 if (isSimpleReturn
) {
6416 MOZ_ASSERT(JSOp(bytecodeSection().code()[setRvalOffset
.value()]) ==
6418 bytecodeSection().code()[setRvalOffset
.value()] = jsbytecode(JSOp::Return
);
6422 // Nothing special needs to be done.
6423 return emitReturnRval();
6426 bool BytecodeEmitter::emitGetDotGeneratorInScope(EmitterScope
& currentScope
) {
6427 if (!sc
->isFunction() && sc
->isModuleContext() &&
6428 sc
->asModuleContext()->isAsync()) {
6429 NameLocation loc
= *locationOfNameBoundInScopeType
<ModuleScope
>(
6430 TaggedParserAtomIndex::WellKnown::dot_generator_(), ¤tScope
);
6431 return emitGetNameAtLocation(
6432 TaggedParserAtomIndex::WellKnown::dot_generator_(), loc
);
6434 NameLocation loc
= *locationOfNameBoundInScopeType
<FunctionScope
>(
6435 TaggedParserAtomIndex::WellKnown::dot_generator_(), ¤tScope
);
6436 return emitGetNameAtLocation(
6437 TaggedParserAtomIndex::WellKnown::dot_generator_(), loc
);
6440 bool BytecodeEmitter::emitInitialYield(UnaryNode
* yieldNode
) {
6441 if (!emitTree(yieldNode
->kid())) {
6445 if (!emitYieldOp(JSOp::InitialYield
)) {
6446 // [stack] RVAL GENERATOR RESUMEKIND
6449 if (!emit1(JSOp::CheckResumeKind
)) {
6453 if (!emit1(JSOp::Pop
)) {
6461 bool BytecodeEmitter::emitYield(UnaryNode
* yieldNode
) {
6462 MOZ_ASSERT(sc
->isFunctionBox());
6463 MOZ_ASSERT(sc
->asFunctionBox()->isGenerator());
6464 MOZ_ASSERT(yieldNode
->isKind(ParseNodeKind::YieldExpr
));
6466 bool needsIteratorResult
= sc
->asFunctionBox()->needsIteratorResult();
6467 if (needsIteratorResult
) {
6468 if (!emitPrepareIteratorResult()) {
6473 if (ParseNode
* expr
= yieldNode
->kid()) {
6474 if (!emitTree(expr
)) {
6475 // [stack] ITEROBJ? VAL
6479 if (!emit1(JSOp::Undefined
)) {
6480 // [stack] ITEROBJ? UNDEFINED
6485 if (sc
->asSuspendableContext()->isAsync()) {
6486 MOZ_ASSERT(!needsIteratorResult
);
6487 if (!emitAwaitInInnermostScope()) {
6493 if (needsIteratorResult
) {
6494 if (!emitFinishIteratorResult(false)) {
6500 if (!emitGetDotGeneratorInInnermostScope()) {
6501 // [stack] # if needsIteratorResult
6502 // [stack] ITEROBJ .GENERATOR
6504 // [stack] RESULT .GENERATOR
6508 if (!emitYieldOp(JSOp::Yield
)) {
6509 // [stack] YIELDRESULT GENERATOR RESUMEKIND
6513 if (!emit1(JSOp::CheckResumeKind
)) {
6514 // [stack] YIELDRESULT
6521 bool BytecodeEmitter::emitAwaitInInnermostScope(UnaryNode
* awaitNode
) {
6522 MOZ_ASSERT(sc
->isSuspendableContext());
6523 MOZ_ASSERT(awaitNode
->isKind(ParseNodeKind::AwaitExpr
));
6525 if (!emitTree(awaitNode
->kid())) {
6528 return emitAwaitInInnermostScope();
6531 bool BytecodeEmitter::emitAwaitInScope(EmitterScope
& currentScope
) {
6532 if (!emit1(JSOp::CanSkipAwait
)) {
6533 // [stack] VALUE CANSKIP
6537 if (!emit1(JSOp::MaybeExtractAwaitValue
)) {
6538 // [stack] VALUE_OR_RESOLVED CANSKIP
6542 InternalIfEmitter
ifCanSkip(this);
6543 if (!ifCanSkip
.emitThen(IfEmitter::ConditionKind::Negative
)) {
6544 // [stack] VALUE_OR_RESOLVED
6548 if (sc
->asSuspendableContext()->needsPromiseResult()) {
6549 if (!emitGetDotGeneratorInScope(currentScope
)) {
6550 // [stack] VALUE GENERATOR
6553 if (!emit1(JSOp::AsyncAwait
)) {
6559 if (!emitGetDotGeneratorInScope(currentScope
)) {
6560 // [stack] VALUE|PROMISE GENERATOR
6563 if (!emitYieldOp(JSOp::Await
)) {
6564 // [stack] RESOLVED GENERATOR RESUMEKIND
6567 if (!emit1(JSOp::CheckResumeKind
)) {
6572 if (!ifCanSkip
.emitEnd()) {
6576 MOZ_ASSERT(ifCanSkip
.popped() == 0);
6581 // ES2019 draft rev 49b781ec80117b60f73327ef3054703a3111e40c
6582 // 14.4.14 Runtime Semantics: Evaluation
6583 // YieldExpression : yield* AssignmentExpression
6584 bool BytecodeEmitter::emitYieldStar(ParseNode
* iter
) {
6585 MOZ_ASSERT(getSelfHostedIterFor(iter
) == SelfHostedIter::Deny
,
6586 "yield* is prohibited in self-hosted code because it can run "
6587 "user-modifiable iteration code");
6589 MOZ_ASSERT(sc
->isSuspendableContext());
6590 MOZ_ASSERT(sc
->asSuspendableContext()->isGenerator());
6593 IteratorKind iterKind
= sc
->asSuspendableContext()->isAsync()
6594 ? IteratorKind::Async
6595 : IteratorKind::Sync
;
6596 bool needsIteratorResult
= sc
->asSuspendableContext()->needsIteratorResult();
6599 if (!emitTree(iter
)) {
6603 if (iterKind
== IteratorKind::Async
) {
6604 if (!emitAsyncIterator(SelfHostedIter::Deny
)) {
6605 // [stack] NEXT ITER
6609 if (!emitIterator(SelfHostedIter::Deny
)) {
6610 // [stack] NEXT ITER
6616 // Start with NormalCompletion(undefined).
6617 if (!emit1(JSOp::Undefined
)) {
6618 // [stack] NEXT ITER RECEIVED
6621 if (!emitPushResumeKind(GeneratorResumeKind::Next
)) {
6622 // [stack] NEXT ITER RECEIVED RESUMEKIND
6626 const int32_t startDepth
= bytecodeSection().stackDepth();
6627 MOZ_ASSERT(startDepth
>= 4);
6629 // Step 7 is a loop.
6630 LoopControl
loopInfo(this, StatementKind::YieldStar
);
6631 if (!loopInfo
.emitLoopHead(this, Nothing())) {
6632 // [stack] NEXT ITER RECEIVED RESUMEKIND
6636 // Step 7.a. Check for Normal completion.
6637 if (!emit1(JSOp::Dup
)) {
6638 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND
6641 if (!emitPushResumeKind(GeneratorResumeKind::Next
)) {
6642 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND NORMAL
6645 if (!emit1(JSOp::StrictEq
)) {
6646 // [stack] NEXT ITER RECEIVED RESUMEKIND IS_NORMAL
6650 InternalIfEmitter
ifKind(this);
6651 if (!ifKind
.emitThenElse()) {
6652 // [stack] NEXT ITER RECEIVED RESUMEKIND
6656 if (!emit1(JSOp::Pop
)) {
6657 // [stack] NEXT ITER RECEIVED
6662 // result = iter.next(received)
6663 if (!emit2(JSOp::Unpick
, 2)) {
6664 // [stack] RECEIVED NEXT ITER
6667 if (!emit1(JSOp::Dup2
)) {
6668 // [stack] RECEIVED NEXT ITER NEXT ITER
6671 if (!emit2(JSOp::Pick
, 4)) {
6672 // [stack] NEXT ITER NEXT ITER RECEIVED
6675 if (!emitCall(JSOp::Call
, 1, iter
)) {
6676 // [stack] NEXT ITER RESULT
6681 if (iterKind
== IteratorKind::Async
) {
6682 if (!emitAwaitInInnermostScope()) {
6683 // [stack] NEXT ITER RESULT
6689 if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext
)) {
6690 // [stack] NEXT ITER RESULT
6694 // Bytecode for steps 7.a.iv-vii is emitted after the ifKind if-else because
6695 // it's shared with other branches.
6698 // Step 7.b. Check for Throw completion.
6699 if (!ifKind
.emitElseIf(Nothing())) {
6700 // [stack] NEXT ITER RECEIVED RESUMEKIND
6703 if (!emit1(JSOp::Dup
)) {
6704 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND
6707 if (!emitPushResumeKind(GeneratorResumeKind::Throw
)) {
6708 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND THROW
6711 if (!emit1(JSOp::StrictEq
)) {
6712 // [stack] NEXT ITER RECEIVED RESUMEKIND IS_THROW
6715 if (!ifKind
.emitThenElse()) {
6716 // [stack] NEXT ITER RECEIVED RESUMEKIND
6720 if (!emit1(JSOp::Pop
)) {
6721 // [stack] NEXT ITER RECEIVED
6725 if (!emitDupAt(1)) {
6726 // [stack] NEXT ITER RECEIVED ITER
6729 if (!emit1(JSOp::Dup
)) {
6730 // [stack] NEXT ITER RECEIVED ITER ITER
6733 if (!emitAtomOp(JSOp::GetProp
,
6734 TaggedParserAtomIndex::WellKnown::throw_())) {
6735 // [stack] NEXT ITER RECEIVED ITER THROW
6740 InternalIfEmitter
ifThrowMethodIsNotDefined(this);
6741 if (!emit1(JSOp::IsNullOrUndefined
)) {
6742 // [stack] NEXT ITER RECEIVED ITER THROW NULL-OR-UNDEF
6746 if (!ifThrowMethodIsNotDefined
.emitThenElse(
6747 IfEmitter::ConditionKind::Negative
)) {
6748 // [stack] NEXT ITER RECEIVED ITER THROW
6753 // RESULT = ITER.throw(EXCEPTION)
6754 if (!emit1(JSOp::Swap
)) {
6755 // [stack] NEXT ITER RECEIVED THROW ITER
6758 if (!emit2(JSOp::Pick
, 2)) {
6759 // [stack] NEXT ITER THROW ITER RECEIVED
6762 if (!emitCall(JSOp::Call
, 1, iter
)) {
6763 // [stack] NEXT ITER RESULT
6768 if (iterKind
== IteratorKind::Async
) {
6769 if (!emitAwaitInInnermostScope()) {
6770 // [stack] NEXT ITER RESULT
6776 if (!emitCheckIsObj(CheckIsObjectKind::IteratorThrow
)) {
6777 // [stack] NEXT ITER RESULT
6781 // Bytecode for steps 7.b.ii.5-8 is emitted after the ifKind if-else because
6782 // it's shared with other branches.
6785 if (!ifThrowMethodIsNotDefined
.emitElse()) {
6786 // [stack] NEXT ITER RECEIVED ITER THROW
6789 if (!emit1(JSOp::Pop
)) {
6790 // [stack] NEXT ITER RECEIVED ITER
6794 // Steps 7.b.iii.1-4.
6796 // If the iterator does not have a "throw" method, it calls IteratorClose
6797 // and then throws a TypeError.
6798 if (!emitIteratorCloseInInnermostScope(iterKind
, CompletionKind::Normal
)) {
6799 // [stack] NEXT ITER RECEIVED ITER
6802 // Steps 7.b.iii.5-6.
6803 if (!emit2(JSOp::ThrowMsg
, uint8_t(ThrowMsgKind::IteratorNoThrow
))) {
6804 // [stack] NEXT ITER RECEIVED ITER
6809 if (!ifThrowMethodIsNotDefined
.emitEnd()) {
6814 // Step 7.c. It must be a Return completion.
6815 if (!ifKind
.emitElse()) {
6816 // [stack] NEXT ITER RECEIVED RESUMEKIND
6820 if (!emit1(JSOp::Pop
)) {
6821 // [stack] NEXT ITER RECEIVED
6827 // Call iterator.return() for receiving a "forced return" completion from
6832 // Get the "return" method.
6833 if (!emitDupAt(1)) {
6834 // [stack] NEXT ITER RECEIVED ITER
6837 if (!emit1(JSOp::Dup
)) {
6838 // [stack] NEXT ITER RECEIVED ITER ITER
6841 if (!emitAtomOp(JSOp::GetProp
,
6842 TaggedParserAtomIndex::WellKnown::return_())) {
6843 // [stack] NEXT ITER RECEIVED ITER RET
6849 // Do nothing if "return" is undefined or null.
6850 InternalIfEmitter
ifReturnMethodIsDefined(this);
6851 if (!emit1(JSOp::IsNullOrUndefined
)) {
6852 // [stack] NEXT ITER RECEIVED ITER RET NULL-OR-UNDEF
6858 // Call "return" with the argument passed to Generator.prototype.return.
6859 if (!ifReturnMethodIsDefined
.emitThenElse(
6860 IfEmitter::ConditionKind::Negative
)) {
6861 // [stack] NEXT ITER RECEIVED ITER RET
6864 if (!emit1(JSOp::Swap
)) {
6865 // [stack] NEXT ITER RECEIVED RET ITER
6868 if (!emit2(JSOp::Pick
, 2)) {
6869 // [stack] NEXT ITER RET ITER RECEIVED
6872 if (needsIteratorResult
) {
6873 if (!emitAtomOp(JSOp::GetProp
,
6874 TaggedParserAtomIndex::WellKnown::value())) {
6875 // [stack] NEXT ITER RET ITER VAL
6879 if (!emitCall(JSOp::Call
, 1)) {
6880 // [stack] NEXT ITER RESULT
6885 if (iterKind
== IteratorKind::Async
) {
6886 if (!emitAwaitInInnermostScope()) {
6887 // [stack] NEXT ITER RESULT
6893 if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn
)) {
6894 // [stack] NEXT ITER RESULT
6898 // Check if the returned object from iterator.return() is done. If not,
6899 // continue yielding.
6901 // Steps 7.c.vii-viii.
6902 InternalIfEmitter
ifReturnDone(this);
6903 if (!emit1(JSOp::Dup
)) {
6904 // [stack] NEXT ITER RESULT RESULT
6907 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::done())) {
6908 // [stack] NEXT ITER RESULT DONE
6911 if (!ifReturnDone
.emitThenElse()) {
6912 // [stack] NEXT ITER RESULT
6917 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::value())) {
6918 // [stack] NEXT ITER VALUE
6921 if (needsIteratorResult
) {
6922 if (!emitPrepareIteratorResult()) {
6923 // [stack] NEXT ITER VALUE RESULT
6926 if (!emit1(JSOp::Swap
)) {
6927 // [stack] NEXT ITER RESULT VALUE
6930 if (!emitFinishIteratorResult(true)) {
6931 // [stack] NEXT ITER RESULT
6936 if (!ifReturnDone
.emitElse()) {
6937 // [stack] NEXT ITER RESULT
6941 // Jump to continue label for steps 7.c.ix-x.
6942 if (!emitJump(JSOp::Goto
, &loopInfo
.continues
)) {
6943 // [stack] NEXT ITER RESULT
6947 if (!ifReturnDone
.emitEnd()) {
6948 // [stack] NEXT ITER RESULT
6953 if (!ifReturnMethodIsDefined
.emitElse()) {
6954 // [stack] NEXT ITER RECEIVED ITER RET
6958 // [stack] NEXT ITER RECEIVED
6961 if (iterKind
== IteratorKind::Async
) {
6963 if (!emitAwaitInInnermostScope()) {
6964 // [stack] NEXT ITER RECEIVED
6968 if (!ifReturnMethodIsDefined
.emitEnd()) {
6969 // [stack] NEXT ITER RECEIVED
6973 // Perform a "forced generator return".
6977 if (!emitGetDotGeneratorInInnermostScope()) {
6978 // [stack] NEXT ITER RESULT GENOBJ
6981 if (!emitPushResumeKind(GeneratorResumeKind::Return
)) {
6982 // [stack] NEXT ITER RESULT GENOBJ RESUMEKIND
6985 if (!emit1(JSOp::CheckResumeKind
)) {
6986 // [stack] NEXT ITER RESULT GENOBJ RESUMEKIND
6991 if (!ifKind
.emitEnd()) {
6992 // [stack] NEXT ITER RESULT
6996 // Shared tail for Normal/Throw completions.
6999 // Steps 7.b.ii.5-6.
7001 // [stack] NEXT ITER RESULT
7003 // if (result.done) break;
7004 if (!emit1(JSOp::Dup
)) {
7005 // [stack] NEXT ITER RESULT RESULT
7008 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::done())) {
7009 // [stack] NEXT ITER RESULT DONE
7012 if (!emitJump(JSOp::JumpIfTrue
, &loopInfo
.breaks
)) {
7013 // [stack] NEXT ITER RESULT
7017 // Steps 7.a.vi-vii.
7018 // Steps 7.b.ii.7-8.
7020 if (!loopInfo
.emitContinueTarget(this)) {
7021 // [stack] NEXT ITER RESULT
7024 if (iterKind
== IteratorKind::Async
) {
7025 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::value())) {
7026 // [stack] NEXT ITER RESULT
7030 if (!emitGetDotGeneratorInInnermostScope()) {
7031 // [stack] NEXT ITER RESULT GENOBJ
7034 if (!emitYieldOp(JSOp::Yield
)) {
7035 // [stack] NEXT ITER RVAL GENOBJ RESUMEKIND
7038 if (!emit1(JSOp::Swap
)) {
7039 // [stack] NEXT ITER RVAL RESUMEKIND GENOBJ
7042 if (!emit1(JSOp::Pop
)) {
7043 // [stack] NEXT ITER RVAL RESUMEKIND
7046 if (!loopInfo
.emitLoopEnd(this, JSOp::Goto
, TryNoteKind::Loop
)) {
7047 // [stack] NEXT ITER RVAL RESUMEKIND
7051 // Jumps to this point have 3 (instead of 4) values on the stack.
7052 MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth
);
7053 bytecodeSection().setStackDepth(startDepth
- 1);
7055 // [stack] NEXT ITER RESULT
7061 if (!emit2(JSOp::Unpick
, 2)) {
7062 // [stack] RESULT NEXT ITER
7069 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::value())) {
7074 MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth
- 3);
7079 bool BytecodeEmitter::emitStatementList(ListNode
* stmtList
) {
7080 for (ParseNode
* stmt
: stmtList
->contents()) {
7081 if (!emitTree(stmt
)) {
7088 bool BytecodeEmitter::emitExpressionStatement(UnaryNode
* exprStmt
) {
7089 MOZ_ASSERT(exprStmt
->isKind(ParseNodeKind::ExpressionStmt
));
7092 * Top-level or called-from-a-native JS_Execute/EvaluateScript,
7093 * debugger, and eval frames may need the value of the ultimate
7094 * expression statement as the script's result, despite the fact
7095 * that it appears useless to the compiler.
7097 * API users may also set the ReadOnlyCompileOptions::noScriptRval option when
7098 * calling JS_Compile* to suppress JSOp::SetRval.
7100 bool wantval
= false;
7101 bool useful
= false;
7102 if (sc
->isTopLevelContext()) {
7103 useful
= wantval
= !sc
->noScriptRval();
7106 /* Don't eliminate expressions with side effects. */
7107 ParseNode
* expr
= exprStmt
->kid();
7109 if (!checkSideEffects(expr
, &useful
)) {
7114 * Don't eliminate apparently useless expressions if they are labeled
7115 * expression statements. The startOffset() test catches the case
7116 * where we are nesting in emitTree for a labeled compound statement.
7118 if (innermostNestableControl
&&
7119 innermostNestableControl
->is
<LabelControl
>() &&
7120 innermostNestableControl
->as
<LabelControl
>().startOffset() >=
7121 bytecodeSection().offset()) {
7127 ValueUsage valueUsage
=
7128 wantval
? ValueUsage::WantValue
: ValueUsage::IgnoreValue
;
7129 ExpressionStatementEmitter
ese(this, valueUsage
);
7130 if (!ese
.prepareForExpr(exprStmt
->pn_pos
.begin
)) {
7133 if (!markStepBreakpoint()) {
7136 if (!emitTree(expr
, valueUsage
)) {
7139 if (!ese
.emitEnd()) {
7147 bool BytecodeEmitter::emitDeleteName(UnaryNode
* deleteNode
) {
7148 MOZ_ASSERT(deleteNode
->isKind(ParseNodeKind::DeleteNameExpr
));
7150 NameNode
* nameExpr
= &deleteNode
->kid()->as
<NameNode
>();
7151 MOZ_ASSERT(nameExpr
->isKind(ParseNodeKind::Name
));
7153 return emitAtomOp(JSOp::DelName
, nameExpr
->atom());
7156 bool BytecodeEmitter::emitDeleteProperty(UnaryNode
* deleteNode
) {
7157 MOZ_ASSERT(deleteNode
->isKind(ParseNodeKind::DeletePropExpr
));
7159 PropertyAccess
* propExpr
= &deleteNode
->kid()->as
<PropertyAccess
>();
7160 PropOpEmitter
poe(this, PropOpEmitter::Kind::Delete
,
7161 propExpr
->as
<PropertyAccess
>().isSuper()
7162 ? PropOpEmitter::ObjKind::Super
7163 : PropOpEmitter::ObjKind::Other
);
7164 if (propExpr
->isSuper()) {
7165 // The expression |delete super.foo;| has to evaluate |super.foo|,
7166 // which could throw if |this| hasn't yet been set by a |super(...)|
7167 // call or the super-base is not an object, before throwing a
7168 // ReferenceError for attempting to delete a super-reference.
7169 UnaryNode
* base
= &propExpr
->expression().as
<UnaryNode
>();
7170 if (!emitGetThisForSuperBase(base
)) {
7175 if (!poe
.prepareForObj()) {
7178 if (!emitPropLHS(propExpr
)) {
7184 if (!poe
.emitDelete(propExpr
->key().atom())) {
7185 // [stack] # if Super
7187 // [stack] # otherwise
7188 // [stack] SUCCEEDED
7195 bool BytecodeEmitter::emitDeleteElement(UnaryNode
* deleteNode
) {
7196 MOZ_ASSERT(deleteNode
->isKind(ParseNodeKind::DeleteElemExpr
));
7198 PropertyByValue
* elemExpr
= &deleteNode
->kid()->as
<PropertyByValue
>();
7199 bool isSuper
= elemExpr
->isSuper();
7200 DebugOnly
<bool> isPrivate
=
7201 elemExpr
->key().isKind(ParseNodeKind::PrivateName
);
7202 MOZ_ASSERT(!isPrivate
);
7204 this, ElemOpEmitter::Kind::Delete
,
7205 isSuper
? ElemOpEmitter::ObjKind::Super
: ElemOpEmitter::ObjKind::Other
);
7207 // The expression |delete super[foo];| has to evaluate |super[foo]|,
7208 // which could throw if |this| hasn't yet been set by a |super(...)|
7209 // call, or trigger side-effects when evaluating ToPropertyKey(foo),
7210 // or also throw when the super-base is not an object, before throwing
7211 // a ReferenceError for attempting to delete a super-reference.
7212 if (!eoe
.prepareForObj()) {
7217 UnaryNode
* base
= &elemExpr
->expression().as
<UnaryNode
>();
7218 if (!emitGetThisForSuperBase(base
)) {
7222 if (!eoe
.prepareForKey()) {
7226 if (!emitTree(&elemExpr
->key())) {
7231 if (!emitElemObjAndKey(elemExpr
, false, eoe
)) {
7236 if (!eoe
.emitDelete()) {
7237 // [stack] # if Super
7239 // [stack] # otherwise
7240 // [stack] SUCCEEDED
7247 bool BytecodeEmitter::emitDeleteExpression(UnaryNode
* deleteNode
) {
7248 MOZ_ASSERT(deleteNode
->isKind(ParseNodeKind::DeleteExpr
));
7250 ParseNode
* expression
= deleteNode
->kid();
7252 // If useless, just emit JSOp::True; otherwise convert |delete <expr>| to
7253 // effectively |<expr>, true|.
7254 bool useful
= false;
7255 if (!checkSideEffects(expression
, &useful
)) {
7260 if (!emitTree(expression
)) {
7263 if (!emit1(JSOp::Pop
)) {
7268 return emit1(JSOp::True
);
7271 bool BytecodeEmitter::emitDeleteOptionalChain(UnaryNode
* deleteNode
) {
7272 MOZ_ASSERT(deleteNode
->isKind(ParseNodeKind::DeleteOptionalChainExpr
));
7274 OptionalEmitter
oe(this, bytecodeSection().stackDepth());
7276 ParseNode
* kid
= deleteNode
->kid();
7277 switch (kid
->getKind()) {
7278 case ParseNodeKind::ElemExpr
:
7279 case ParseNodeKind::OptionalElemExpr
: {
7280 auto* elemExpr
= &kid
->as
<PropertyByValueBase
>();
7281 if (!emitDeleteElementInOptChain(elemExpr
, oe
)) {
7282 // [stack] # If shortcircuit
7283 // [stack] UNDEFINED-OR-NULL
7284 // [stack] # otherwise
7285 // [stack] SUCCEEDED
7291 case ParseNodeKind::DotExpr
:
7292 case ParseNodeKind::OptionalDotExpr
: {
7293 auto* propExpr
= &kid
->as
<PropertyAccessBase
>();
7294 if (!emitDeletePropertyInOptChain(propExpr
, oe
)) {
7295 // [stack] # If shortcircuit
7296 // [stack] UNDEFINED-OR-NULL
7297 // [stack] # otherwise
7298 // [stack] SUCCEEDED
7304 MOZ_ASSERT_UNREACHABLE("Unrecognized optional delete ParseNodeKind");
7307 if (!oe
.emitOptionalJumpTarget(JSOp::True
)) {
7308 // [stack] # If shortcircuit
7310 // [stack] # otherwise
7311 // [stack] SUCCEEDED
7318 bool BytecodeEmitter::emitDeletePropertyInOptChain(PropertyAccessBase
* propExpr
,
7319 OptionalEmitter
& oe
) {
7320 MOZ_ASSERT_IF(propExpr
->is
<PropertyAccess
>(),
7321 !propExpr
->as
<PropertyAccess
>().isSuper());
7322 PropOpEmitter
poe(this, PropOpEmitter::Kind::Delete
,
7323 PropOpEmitter::ObjKind::Other
);
7325 if (!poe
.prepareForObj()) {
7329 if (!emitOptionalTree(&propExpr
->expression(), oe
)) {
7333 if (propExpr
->isKind(ParseNodeKind::OptionalDotExpr
)) {
7334 if (!oe
.emitJumpShortCircuit()) {
7335 // [stack] # if Jump
7336 // [stack] UNDEFINED-OR-NULL
7337 // [stack] # otherwise
7343 if (!poe
.emitDelete(propExpr
->key().atom())) {
7344 // [stack] SUCCEEDED
7351 bool BytecodeEmitter::emitDeleteElementInOptChain(PropertyByValueBase
* elemExpr
,
7352 OptionalEmitter
& oe
) {
7353 MOZ_ASSERT_IF(elemExpr
->is
<PropertyByValue
>(),
7354 !elemExpr
->as
<PropertyByValue
>().isSuper());
7355 ElemOpEmitter
eoe(this, ElemOpEmitter::Kind::Delete
,
7356 ElemOpEmitter::ObjKind::Other
);
7358 if (!eoe
.prepareForObj()) {
7363 if (!emitOptionalTree(&elemExpr
->expression(), oe
)) {
7368 if (elemExpr
->isKind(ParseNodeKind::OptionalElemExpr
)) {
7369 if (!oe
.emitJumpShortCircuit()) {
7370 // [stack] # if Jump
7371 // [stack] UNDEFINED-OR-NULL
7372 // [stack] # otherwise
7378 if (!eoe
.prepareForKey()) {
7383 if (!emitTree(&elemExpr
->key())) {
7388 if (!eoe
.emitDelete()) {
7389 // [stack] SUCCEEDED
7396 bool BytecodeEmitter::emitDebugCheckSelfHosted() {
7400 if (!emit1(JSOp::DebugCheckSelfHosted
)) {
7409 bool BytecodeEmitter::emitSelfHostedCallFunction(CallNode
* callNode
, JSOp op
) {
7410 // Special-casing of callFunction to emit bytecode that directly
7411 // invokes the callee with the correct |this| object and arguments.
7412 // callFunction(fun, thisArg, arg0, arg1) thus becomes:
7413 // - emit lookup for fun
7414 // - emit lookup for thisArg
7415 // - emit lookups for arg0, arg1
7417 // argc is set to the amount of actually emitted args and the
7418 // emitting of args below is disabled by setting emitArgs to false.
7419 NameNode
* calleeNode
= &callNode
->callee()->as
<NameNode
>();
7420 ListNode
* argsList
= callNode
->args();
7422 MOZ_ASSERT(argsList
->count() >= 2);
7424 MOZ_ASSERT(callNode
->callOp() == JSOp::Call
);
7427 calleeNode
->name() ==
7428 TaggedParserAtomIndex::WellKnown::constructContentFunction();
7429 ParseNode
* funNode
= argsList
->head();
7431 if (!emitTree(funNode
)) {
7437 MOZ_ASSERT(op
== JSOp::Call
|| op
== JSOp::CallContent
||
7438 op
== JSOp::NewContent
);
7439 if (op
== JSOp::Call
) {
7440 if (!emitDebugCheckSelfHosted()) {
7447 ParseNode
* thisOrNewTarget
= funNode
->pn_next
;
7449 // Save off the new.target value, but here emit a proper |this| for a
7450 // constructing call.
7451 if (!emit1(JSOp::IsConstructing
)) {
7452 // [stack] CALLEE IS_CONSTRUCTING
7456 // It's |this|, emit it.
7457 if (!emitTree(thisOrNewTarget
)) {
7458 // [stack] CALLEE THIS
7463 for (ParseNode
* argpn
: argsList
->contentsFrom(thisOrNewTarget
->pn_next
)) {
7464 if (!emitTree(argpn
)) {
7465 // [stack] CALLEE ... ARGS...
7471 if (!emitTree(thisOrNewTarget
)) {
7472 // [stack] CALLEE IS_CONSTRUCTING ARGS... NEW.TARGET
7477 uint32_t argc
= argsList
->count() - 2;
7478 if (!emitCall(op
, argc
)) {
7486 bool BytecodeEmitter::emitSelfHostedResumeGenerator(CallNode
* callNode
) {
7487 ListNode
* argsList
= callNode
->args();
7489 // Syntax: resumeGenerator(gen, value, 'next'|'throw'|'return')
7490 MOZ_ASSERT(argsList
->count() == 3);
7492 ParseNode
* genNode
= argsList
->head();
7493 if (!emitTree(genNode
)) {
7494 // [stack] GENERATOR
7498 ParseNode
* valNode
= genNode
->pn_next
;
7499 if (!emitTree(valNode
)) {
7500 // [stack] GENERATOR VALUE
7504 ParseNode
* kindNode
= valNode
->pn_next
;
7505 MOZ_ASSERT(kindNode
->isKind(ParseNodeKind::StringExpr
));
7506 GeneratorResumeKind kind
=
7507 ParserAtomToResumeKind(kindNode
->as
<NameNode
>().atom());
7508 MOZ_ASSERT(!kindNode
->pn_next
);
7510 if (!emitPushResumeKind(kind
)) {
7511 // [stack] GENERATOR VALUE RESUMEKIND
7515 if (!emit1(JSOp::Resume
)) {
7523 bool BytecodeEmitter::emitSelfHostedForceInterpreter() {
7524 // JSScript::hasForceInterpreterOp() relies on JSOp::ForceInterpreter being
7525 // the first bytecode op in the script.
7526 MOZ_ASSERT(bytecodeSection().code().empty());
7528 if (!emit1(JSOp::ForceInterpreter
)) {
7531 if (!emit1(JSOp::Undefined
)) {
7538 bool BytecodeEmitter::emitSelfHostedAllowContentIter(CallNode
* callNode
) {
7539 ListNode
* argsList
= callNode
->args();
7541 MOZ_ASSERT(argsList
->count() == 1);
7543 // We're just here as a sentinel. Pass the value through directly.
7544 return emitTree(argsList
->head());
7547 bool BytecodeEmitter::emitSelfHostedAllowContentIterWith(CallNode
* callNode
) {
7548 ListNode
* argsList
= callNode
->args();
7550 MOZ_ASSERT(argsList
->count() == 2 || argsList
->count() == 3);
7552 // We're just here as a sentinel. Pass the value through directly.
7553 return emitTree(argsList
->head());
7556 bool BytecodeEmitter::emitSelfHostedAllowContentIterWithNext(
7557 CallNode
* callNode
) {
7558 ListNode
* argsList
= callNode
->args();
7560 MOZ_ASSERT(argsList
->count() == 2);
7562 // We're just here as a sentinel. Pass the value through directly.
7563 return emitTree(argsList
->head());
7566 bool BytecodeEmitter::emitSelfHostedDefineDataProperty(CallNode
* callNode
) {
7567 ListNode
* argsList
= callNode
->args();
7569 // Only optimize when 3 arguments are passed.
7570 MOZ_ASSERT(argsList
->count() == 3);
7572 ParseNode
* objNode
= argsList
->head();
7573 if (!emitTree(objNode
)) {
7577 ParseNode
* idNode
= objNode
->pn_next
;
7578 if (!emitTree(idNode
)) {
7582 ParseNode
* valNode
= idNode
->pn_next
;
7583 if (!emitTree(valNode
)) {
7587 // This will leave the object on the stack instead of pushing |undefined|,
7588 // but that's fine because the self-hosted code doesn't use the return
7590 return emit1(JSOp::InitElem
);
7593 bool BytecodeEmitter::emitSelfHostedHasOwn(CallNode
* callNode
) {
7594 ListNode
* argsList
= callNode
->args();
7596 MOZ_ASSERT(argsList
->count() == 2);
7598 ParseNode
* idNode
= argsList
->head();
7599 if (!emitTree(idNode
)) {
7603 ParseNode
* objNode
= idNode
->pn_next
;
7604 if (!emitTree(objNode
)) {
7608 return emit1(JSOp::HasOwn
);
7611 bool BytecodeEmitter::emitSelfHostedGetPropertySuper(CallNode
* callNode
) {
7612 ListNode
* argsList
= callNode
->args();
7614 MOZ_ASSERT(argsList
->count() == 3);
7616 ParseNode
* objNode
= argsList
->head();
7617 ParseNode
* idNode
= objNode
->pn_next
;
7618 ParseNode
* receiverNode
= idNode
->pn_next
;
7620 if (!emitTree(receiverNode
)) {
7624 if (!emitTree(idNode
)) {
7628 if (!emitTree(objNode
)) {
7632 return emitElemOpBase(JSOp::GetElemSuper
);
7635 bool BytecodeEmitter::emitSelfHostedToNumeric(CallNode
* callNode
) {
7636 ListNode
* argsList
= callNode
->args();
7638 MOZ_ASSERT(argsList
->count() == 1);
7640 ParseNode
* argNode
= argsList
->head();
7642 if (!emitTree(argNode
)) {
7646 return emit1(JSOp::ToNumeric
);
7649 bool BytecodeEmitter::emitSelfHostedToString(CallNode
* callNode
) {
7650 ListNode
* argsList
= callNode
->args();
7652 MOZ_ASSERT(argsList
->count() == 1);
7654 ParseNode
* argNode
= argsList
->head();
7656 if (!emitTree(argNode
)) {
7660 return emit1(JSOp::ToString
);
7663 bool BytecodeEmitter::emitSelfHostedIsNullOrUndefined(CallNode
* callNode
) {
7664 ListNode
* argsList
= callNode
->args();
7666 MOZ_ASSERT(argsList
->count() == 1);
7668 ParseNode
* argNode
= argsList
->head();
7670 if (!emitTree(argNode
)) {
7674 if (!emit1(JSOp::IsNullOrUndefined
)) {
7675 // [stack] ARG IS_NULL_OR_UNDEF
7678 if (!emit1(JSOp::Swap
)) {
7679 // [stack] IS_NULL_OR_UNDEF ARG
7682 if (!emit1(JSOp::Pop
)) {
7683 // [stack] IS_NULL_OR_UNDEF
7689 bool BytecodeEmitter::emitSelfHostedIteratorClose(CallNode
* callNode
) {
7690 ListNode
* argsList
= callNode
->args();
7691 MOZ_ASSERT(argsList
->count() == 1);
7693 ParseNode
* argNode
= argsList
->head();
7694 if (!emitTree(argNode
)) {
7699 if (!emit2(JSOp::CloseIter
, uint8_t(CompletionKind::Normal
))) {
7704 // This is still a call node, so we must generate a stack value.
7705 if (!emit1(JSOp::Undefined
)) {
7713 bool BytecodeEmitter::emitSelfHostedGetBuiltinConstructorOrPrototype(
7714 CallNode
* callNode
, bool isConstructor
) {
7715 ListNode
* argsList
= callNode
->args();
7717 MOZ_ASSERT(argsList
->count() == 1);
7719 ParseNode
* argNode
= argsList
->head();
7721 if (!argNode
->isKind(ParseNodeKind::StringExpr
)) {
7722 reportError(callNode
, JSMSG_UNEXPECTED_TYPE
, "built-in name",
7723 "not a string constant");
7727 auto name
= argNode
->as
<NameNode
>().atom();
7729 BuiltinObjectKind kind
;
7730 if (isConstructor
) {
7731 kind
= BuiltinConstructorForName(name
);
7733 kind
= BuiltinPrototypeForName(name
);
7736 if (kind
== BuiltinObjectKind::None
) {
7737 reportError(callNode
, JSMSG_UNEXPECTED_TYPE
, "built-in name",
7738 "not a valid built-in");
7742 return emitBuiltinObject(kind
);
7745 bool BytecodeEmitter::emitSelfHostedGetBuiltinConstructor(CallNode
* callNode
) {
7746 return emitSelfHostedGetBuiltinConstructorOrPrototype(
7747 callNode
, /* isConstructor = */ true);
7750 bool BytecodeEmitter::emitSelfHostedGetBuiltinPrototype(CallNode
* callNode
) {
7751 return emitSelfHostedGetBuiltinConstructorOrPrototype(
7752 callNode
, /* isConstructor = */ false);
7755 JS::SymbolCode
ParserAtomToSymbolCode(TaggedParserAtomIndex atom
) {
7756 // NOTE: This is a linear search, but the set of entries is quite small and
7757 // this is only used for initial self-hosted parse.
7758 #define MATCH_WELL_KNOWN_SYMBOL(NAME) \
7759 if (atom == TaggedParserAtomIndex::WellKnown::NAME()) { \
7760 return JS::SymbolCode::NAME; \
7762 JS_FOR_EACH_WELL_KNOWN_SYMBOL(MATCH_WELL_KNOWN_SYMBOL
)
7763 #undef MATCH_WELL_KNOWN_SYMBOL
7765 return JS::SymbolCode::Limit
;
7768 bool BytecodeEmitter::emitSelfHostedGetBuiltinSymbol(CallNode
* callNode
) {
7769 ListNode
* argsList
= callNode
->args();
7771 MOZ_ASSERT(argsList
->count() == 1);
7773 ParseNode
* argNode
= argsList
->head();
7775 if (!argNode
->isKind(ParseNodeKind::StringExpr
)) {
7776 reportError(callNode
, JSMSG_UNEXPECTED_TYPE
, "built-in name",
7777 "not a string constant");
7781 auto name
= argNode
->as
<NameNode
>().atom();
7783 JS::SymbolCode code
= ParserAtomToSymbolCode(name
);
7784 if (code
== JS::SymbolCode::Limit
) {
7785 reportError(callNode
, JSMSG_UNEXPECTED_TYPE
, "built-in name",
7786 "not a valid built-in");
7790 return emit2(JSOp::Symbol
, uint8_t(code
));
7793 bool BytecodeEmitter::emitSelfHostedArgumentsLength(CallNode
* callNode
) {
7794 MOZ_ASSERT(!sc
->asFunctionBox()->needsArgsObj());
7795 sc
->asFunctionBox()->setUsesArgumentsIntrinsics();
7797 MOZ_ASSERT(callNode
->args()->count() == 0);
7799 return emit1(JSOp::ArgumentsLength
);
7802 bool BytecodeEmitter::emitSelfHostedGetArgument(CallNode
* callNode
) {
7803 MOZ_ASSERT(!sc
->asFunctionBox()->needsArgsObj());
7804 sc
->asFunctionBox()->setUsesArgumentsIntrinsics();
7806 ListNode
* argsList
= callNode
->args();
7807 MOZ_ASSERT(argsList
->count() == 1);
7809 ParseNode
* argNode
= argsList
->head();
7810 if (!emitTree(argNode
)) {
7814 return emit1(JSOp::GetActualArg
);
7818 void BytecodeEmitter::assertSelfHostedExpectedTopLevel(ParseNode
* node
) {
7819 // The function argument is expected to be a simple binding/function name.
7820 // Eg. `function foo() { }; SpecialIntrinsic(foo)`
7821 MOZ_ASSERT(node
->isKind(ParseNodeKind::Name
),
7822 "argument must be a function name");
7823 TaggedParserAtomIndex targetName
= node
->as
<NameNode
>().name();
7825 // The special intrinsics must follow the target functions definition. A
7826 // simple assert is fine here since any hoisted function will cause a non-null
7827 // value to be set here.
7828 MOZ_ASSERT(prevSelfHostedTopLevelFunction
);
7830 // The target function must match the most recently defined top-level
7831 // self-hosted function.
7832 MOZ_ASSERT(prevSelfHostedTopLevelFunction
->explicitName() == targetName
,
7833 "selfhost decorator must immediately follow target function");
7837 bool BytecodeEmitter::emitSelfHostedSetIsInlinableLargeFunction(
7838 CallNode
* callNode
) {
7840 ListNode
* argsList
= callNode
->args();
7842 MOZ_ASSERT(argsList
->count() == 1);
7844 assertSelfHostedExpectedTopLevel(argsList
->head());
7847 MOZ_ASSERT(prevSelfHostedTopLevelFunction
->isInitialCompilation
);
7848 prevSelfHostedTopLevelFunction
->setIsInlinableLargeFunction();
7850 // This is still a call node, so we must generate a stack value.
7851 return emit1(JSOp::Undefined
);
7854 bool BytecodeEmitter::emitSelfHostedSetCanonicalName(CallNode
* callNode
) {
7855 ListNode
* argsList
= callNode
->args();
7857 MOZ_ASSERT(argsList
->count() == 2);
7860 assertSelfHostedExpectedTopLevel(argsList
->head());
7863 ParseNode
* nameNode
= argsList
->last();
7864 MOZ_ASSERT(nameNode
->isKind(ParseNodeKind::StringExpr
));
7865 TaggedParserAtomIndex specName
= nameNode
->as
<NameNode
>().atom();
7866 // Canonical name must be atomized.
7867 compilationState
.parserAtoms
.markUsedByStencil(specName
,
7868 ParserAtom::Atomize::Yes
);
7870 // Store the canonical name for instantiation.
7871 prevSelfHostedTopLevelFunction
->functionStencil().setSelfHostedCanonicalName(
7874 return emit1(JSOp::Undefined
);
7878 void BytecodeEmitter::assertSelfHostedUnsafeGetReservedSlot(
7879 ListNode
* argsList
) {
7880 MOZ_ASSERT(argsList
->count() == 2);
7882 ParseNode
* objNode
= argsList
->head();
7883 ParseNode
* slotNode
= objNode
->pn_next
;
7885 // Ensure that the slot argument is fixed, this is required by the JITs.
7886 MOZ_ASSERT(slotNode
->isKind(ParseNodeKind::NumberExpr
),
7887 "slot argument must be a constant");
7890 void BytecodeEmitter::assertSelfHostedUnsafeSetReservedSlot(
7891 ListNode
* argsList
) {
7892 MOZ_ASSERT(argsList
->count() == 3);
7894 ParseNode
* objNode
= argsList
->head();
7895 ParseNode
* slotNode
= objNode
->pn_next
;
7897 // Ensure that the slot argument is fixed, this is required by the JITs.
7898 MOZ_ASSERT(slotNode
->isKind(ParseNodeKind::NumberExpr
),
7899 "slot argument must be a constant");
7903 /* A version of emitCalleeAndThis for the optional cases:
7910 * See emitCallOrNew and emitOptionalCall for more context.
7912 bool BytecodeEmitter::emitOptionalCalleeAndThis(ParseNode
* callee
,
7914 CallOrNewEmitter
& cone
,
7915 OptionalEmitter
& oe
) {
7916 AutoCheckRecursionLimit
recursion(fc
);
7917 if (!recursion
.check(fc
)) {
7921 switch (ParseNodeKind kind
= callee
->getKind()) {
7922 case ParseNodeKind::Name
: {
7923 auto name
= callee
->as
<NameNode
>().name();
7924 if (!cone
.emitNameCallee(name
)) {
7925 // [stack] CALLEE THIS
7931 case ParseNodeKind::OptionalDotExpr
: {
7932 MOZ_ASSERT(emitterMode
!= BytecodeEmitter::SelfHosting
);
7933 OptionalPropertyAccess
* prop
= &callee
->as
<OptionalPropertyAccess
>();
7934 bool isSuper
= false;
7936 PropOpEmitter
& poe
= cone
.prepareForPropCallee(isSuper
);
7937 if (!emitOptionalDotExpression(prop
, poe
, isSuper
, oe
)) {
7938 // [stack] CALLEE THIS
7943 case ParseNodeKind::DotExpr
: {
7944 MOZ_ASSERT(emitterMode
!= BytecodeEmitter::SelfHosting
);
7945 PropertyAccess
* prop
= &callee
->as
<PropertyAccess
>();
7946 bool isSuper
= prop
->isSuper();
7948 PropOpEmitter
& poe
= cone
.prepareForPropCallee(isSuper
);
7949 if (!emitOptionalDotExpression(prop
, poe
, isSuper
, oe
)) {
7950 // [stack] CALLEE THIS
7956 case ParseNodeKind::OptionalElemExpr
: {
7957 OptionalPropertyByValue
* elem
= &callee
->as
<OptionalPropertyByValue
>();
7958 bool isSuper
= false;
7959 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
7960 ElemOpEmitter
& eoe
= cone
.prepareForElemCallee(isSuper
);
7961 if (!emitOptionalElemExpression(elem
, eoe
, isSuper
, oe
)) {
7962 // [stack] CALLEE THIS
7967 case ParseNodeKind::ElemExpr
: {
7968 PropertyByValue
* elem
= &callee
->as
<PropertyByValue
>();
7969 bool isSuper
= elem
->isSuper();
7970 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
7971 ElemOpEmitter
& eoe
= cone
.prepareForElemCallee(isSuper
);
7972 if (!emitOptionalElemExpression(elem
, eoe
, isSuper
, oe
)) {
7973 // [stack] CALLEE THIS
7979 case ParseNodeKind::PrivateMemberExpr
:
7980 case ParseNodeKind::OptionalPrivateMemberExpr
: {
7981 PrivateMemberAccessBase
* privateExpr
=
7982 &callee
->as
<PrivateMemberAccessBase
>();
7983 PrivateOpEmitter
& xoe
=
7984 cone
.prepareForPrivateCallee(privateExpr
->privateName().name());
7985 if (!emitOptionalPrivateExpression(privateExpr
, xoe
, oe
)) {
7986 // [stack] CALLEE THIS
7992 case ParseNodeKind::Function
:
7993 if (!cone
.prepareForFunctionCallee()) {
7996 if (!emitOptionalTree(callee
, oe
)) {
8002 case ParseNodeKind::OptionalChain
: {
8003 return emitCalleeAndThisForOptionalChain(&callee
->as
<UnaryNode
>(), call
,
8008 MOZ_RELEASE_ASSERT(kind
!= ParseNodeKind::SuperBase
);
8010 if (!cone
.prepareForOtherCallee()) {
8013 if (!emitOptionalTree(callee
, oe
)) {
8020 if (!cone
.emitThis()) {
8021 // [stack] CALLEE THIS
8028 bool BytecodeEmitter::emitCalleeAndThis(ParseNode
* callee
, CallNode
* call
,
8029 CallOrNewEmitter
& cone
) {
8030 MOZ_ASSERT(call
->callee() == callee
);
8032 switch (callee
->getKind()) {
8033 case ParseNodeKind::Name
: {
8034 auto name
= callee
->as
<NameNode
>().name();
8035 if (!cone
.emitNameCallee(name
)) {
8036 // [stack] CALLEE THIS?
8041 case ParseNodeKind::DotExpr
: {
8042 MOZ_ASSERT(emitterMode
!= BytecodeEmitter::SelfHosting
);
8043 PropertyAccess
* prop
= &callee
->as
<PropertyAccess
>();
8044 bool isSuper
= prop
->isSuper();
8046 PropOpEmitter
& poe
= cone
.prepareForPropCallee(isSuper
);
8047 if (!poe
.prepareForObj()) {
8051 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
8052 if (!emitGetThisForSuperBase(base
)) {
8057 if (!emitPropLHS(prop
)) {
8062 if (!poe
.emitGet(prop
->key().atom())) {
8063 // [stack] CALLEE THIS?
8069 case ParseNodeKind::ElemExpr
: {
8070 MOZ_ASSERT(emitterMode
!= BytecodeEmitter::SelfHosting
);
8071 PropertyByValue
* elem
= &callee
->as
<PropertyByValue
>();
8072 bool isSuper
= elem
->isSuper();
8073 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
8074 ElemOpEmitter
& eoe
= cone
.prepareForElemCallee(isSuper
);
8075 if (!emitElemObjAndKey(elem
, isSuper
, eoe
)) {
8076 // [stack] # if Super
8077 // [stack] THIS? THIS KEY
8078 // [stack] # otherwise
8079 // [stack] OBJ? OBJ KEY
8082 if (!eoe
.emitGet()) {
8083 // [stack] CALLEE THIS?
8089 case ParseNodeKind::PrivateMemberExpr
: {
8090 MOZ_ASSERT(emitterMode
!= BytecodeEmitter::SelfHosting
);
8091 PrivateMemberAccessBase
* privateExpr
=
8092 &callee
->as
<PrivateMemberAccessBase
>();
8093 PrivateOpEmitter
& xoe
=
8094 cone
.prepareForPrivateCallee(privateExpr
->privateName().name());
8095 if (!emitTree(&privateExpr
->expression())) {
8099 if (!xoe
.emitReference()) {
8103 if (!xoe
.emitGetForCallOrNew()) {
8104 // [stack] CALLEE THIS
8110 case ParseNodeKind::Function
:
8111 if (!cone
.prepareForFunctionCallee()) {
8114 if (!emitTree(callee
)) {
8119 case ParseNodeKind::SuperBase
:
8120 MOZ_ASSERT(call
->isKind(ParseNodeKind::SuperCallExpr
));
8121 MOZ_ASSERT(callee
->isKind(ParseNodeKind::SuperBase
));
8122 if (!cone
.emitSuperCallee()) {
8123 // [stack] CALLEE IsConstructing
8127 case ParseNodeKind::OptionalChain
: {
8128 return emitCalleeAndThisForOptionalChain(&callee
->as
<UnaryNode
>(), call
,
8132 if (!cone
.prepareForOtherCallee()) {
8135 if (!emitTree(callee
)) {
8141 if (!cone
.emitThis()) {
8142 // [stack] CALLEE THIS
8149 ParseNode
* BytecodeEmitter::getCoordNode(ParseNode
* callNode
,
8150 ParseNode
* calleeNode
, JSOp op
,
8151 ListNode
* argsList
) {
8152 ParseNode
* coordNode
= callNode
;
8153 if (op
== JSOp::Call
|| op
== JSOp::SpreadCall
) {
8154 // Default to using the location of the `(` itself.
8155 // obj[expr]() // expression
8156 // ^ // column coord
8157 coordNode
= argsList
;
8159 switch (calleeNode
->getKind()) {
8160 case ParseNodeKind::DotExpr
:
8161 // Use the position of a property access identifier.
8163 // obj().aprop() // expression
8164 // ^ // column coord
8166 // Note: Because of the constant folding logic in FoldElement,
8167 // this case also applies for constant string properties.
8169 // obj()['aprop']() // expression
8170 // ^ // column coord
8171 coordNode
= &calleeNode
->as
<PropertyAccess
>().key();
8173 case ParseNodeKind::Name
: {
8174 // Use the start of callee name unless it is at a separator
8177 // 2 + obj() // expression
8178 // ^ // column coord
8180 if (argsList
->empty() ||
8181 !bytecodeSection().atSeparator(calleeNode
->pn_pos
.begin
)) {
8182 // Use the start of callee names.
8183 coordNode
= calleeNode
;
8195 bool BytecodeEmitter::emitArguments(ListNode
* argsList
, bool isCall
,
8196 bool isSpread
, CallOrNewEmitter
& cone
) {
8197 uint32_t argc
= argsList
->count();
8198 if (argc
>= ARGC_LIMIT
) {
8199 reportError(argsList
,
8200 isCall
? JSMSG_TOO_MANY_FUN_ARGS
: JSMSG_TOO_MANY_CON_ARGS
);
8204 if (!cone
.prepareForNonSpreadArguments()) {
8205 // [stack] CALLEE THIS
8208 for (ParseNode
* arg
: argsList
->contents()) {
8209 if (!updateSourceCoordNotesIfNonLiteral(arg
)) {
8212 if (!emitTree(arg
)) {
8213 // [stack] CALLEE THIS ARG*
8217 } else if (cone
.wantSpreadOperand()) {
8218 auto* spreadNode
= &argsList
->head()->as
<UnaryNode
>();
8219 if (!updateSourceCoordNotesIfNonLiteral(spreadNode
->kid())) {
8222 if (!emitTree(spreadNode
->kid())) {
8223 // [stack] CALLEE THIS ARG0
8227 if (!cone
.emitSpreadArgumentsTest()) {
8228 // [stack] CALLEE THIS ARG0
8232 if (cone
.wantSpreadIteration()) {
8233 if (!emitSpreadIntoArray(spreadNode
)) {
8234 // [stack] CALLEE THIS ARR
8239 if (!cone
.emitSpreadArgumentsTestEnd()) {
8240 // [stack] CALLEE THIS ARR
8244 if (!cone
.prepareForSpreadArguments()) {
8245 // [stack] CALLEE THIS
8248 if (!emitArray(argsList
)) {
8249 // [stack] CALLEE THIS ARR
8257 bool BytecodeEmitter::emitOptionalCall(CallNode
* callNode
, OptionalEmitter
& oe
,
8258 ValueUsage valueUsage
) {
8260 * A modified version of emitCallOrNew that handles optional calls.
8262 * These include the following:
8268 * See CallOrNewEmitter for more context.
8270 ParseNode
* calleeNode
= callNode
->callee();
8271 ListNode
* argsList
= callNode
->args();
8272 bool isSpread
= IsSpreadOp(callNode
->callOp());
8273 JSOp op
= callNode
->callOp();
8274 uint32_t argc
= argsList
->count();
8275 bool isOptimizableSpread
= isSpread
&& argc
== 1;
8277 CallOrNewEmitter
cone(this, op
,
8279 ? CallOrNewEmitter::ArgumentsKind::SingleSpread
8280 : CallOrNewEmitter::ArgumentsKind::Other
,
8283 ParseNode
* coordNode
= getCoordNode(callNode
, calleeNode
, op
, argsList
);
8285 if (!emitOptionalCalleeAndThis(calleeNode
, callNode
, cone
, oe
)) {
8286 // [stack] CALLEE THIS
8290 if (callNode
->isKind(ParseNodeKind::OptionalCallExpr
)) {
8291 if (!oe
.emitJumpShortCircuitForCall()) {
8292 // [stack] CALLEE THIS
8297 if (!emitArguments(argsList
, /* isCall = */ true, isSpread
, cone
)) {
8298 // [stack] CALLEE THIS ARGS...
8302 if (!cone
.emitEnd(argc
, coordNode
->pn_pos
.begin
)) {
8310 bool BytecodeEmitter::emitCallOrNew(CallNode
* callNode
, ValueUsage valueUsage
) {
8312 * Emit callable invocation or operator new (constructor call) code.
8313 * First, emit code for the left operand to evaluate the callable or
8314 * constructable object expression.
8316 * Then (or in a call case that has no explicit reference-base
8317 * object) we emit JSOp::Undefined to produce the undefined |this|
8318 * value required for calls (which non-strict mode functions
8319 * will box into the global object).
8321 bool isCall
= callNode
->isKind(ParseNodeKind::CallExpr
) ||
8322 callNode
->isKind(ParseNodeKind::TaggedTemplateExpr
);
8323 ParseNode
* calleeNode
= callNode
->callee();
8324 ListNode
* argsList
= callNode
->args();
8325 JSOp op
= callNode
->callOp();
8327 if (calleeNode
->isKind(ParseNodeKind::Name
) &&
8328 emitterMode
== BytecodeEmitter::SelfHosting
&& op
== JSOp::Call
) {
8329 // Calls to "forceInterpreter", "callFunction",
8330 // "callContentFunction", or "resumeGenerator" in self-hosted
8331 // code generate inline bytecode.
8333 // NOTE: The list of special instruction names has to be kept in sync with
8334 // "js/src/builtin/.eslintrc.js".
8335 auto calleeName
= calleeNode
->as
<NameNode
>().name();
8336 if (calleeName
== TaggedParserAtomIndex::WellKnown::callFunction()) {
8337 return emitSelfHostedCallFunction(callNode
, JSOp::Call
);
8339 if (calleeName
== TaggedParserAtomIndex::WellKnown::callContentFunction()) {
8340 return emitSelfHostedCallFunction(callNode
, JSOp::CallContent
);
8343 TaggedParserAtomIndex::WellKnown::constructContentFunction()) {
8344 return emitSelfHostedCallFunction(callNode
, JSOp::NewContent
);
8346 if (calleeName
== TaggedParserAtomIndex::WellKnown::resumeGenerator()) {
8347 return emitSelfHostedResumeGenerator(callNode
);
8349 if (calleeName
== TaggedParserAtomIndex::WellKnown::forceInterpreter()) {
8350 return emitSelfHostedForceInterpreter();
8352 if (calleeName
== TaggedParserAtomIndex::WellKnown::allowContentIter()) {
8353 return emitSelfHostedAllowContentIter(callNode
);
8356 TaggedParserAtomIndex::WellKnown::allowContentIterWith()) {
8357 return emitSelfHostedAllowContentIterWith(callNode
);
8360 TaggedParserAtomIndex::WellKnown::allowContentIterWithNext()) {
8361 return emitSelfHostedAllowContentIterWithNext(callNode
);
8363 if (calleeName
== TaggedParserAtomIndex::WellKnown::DefineDataProperty() &&
8364 argsList
->count() == 3) {
8365 return emitSelfHostedDefineDataProperty(callNode
);
8367 if (calleeName
== TaggedParserAtomIndex::WellKnown::hasOwn()) {
8368 return emitSelfHostedHasOwn(callNode
);
8370 if (calleeName
== TaggedParserAtomIndex::WellKnown::getPropertySuper()) {
8371 return emitSelfHostedGetPropertySuper(callNode
);
8373 if (calleeName
== TaggedParserAtomIndex::WellKnown::ToNumeric()) {
8374 return emitSelfHostedToNumeric(callNode
);
8376 if (calleeName
== TaggedParserAtomIndex::WellKnown::ToString()) {
8377 return emitSelfHostedToString(callNode
);
8380 TaggedParserAtomIndex::WellKnown::GetBuiltinConstructor()) {
8381 return emitSelfHostedGetBuiltinConstructor(callNode
);
8383 if (calleeName
== TaggedParserAtomIndex::WellKnown::GetBuiltinPrototype()) {
8384 return emitSelfHostedGetBuiltinPrototype(callNode
);
8386 if (calleeName
== TaggedParserAtomIndex::WellKnown::GetBuiltinSymbol()) {
8387 return emitSelfHostedGetBuiltinSymbol(callNode
);
8389 if (calleeName
== TaggedParserAtomIndex::WellKnown::ArgumentsLength()) {
8390 return emitSelfHostedArgumentsLength(callNode
);
8392 if (calleeName
== TaggedParserAtomIndex::WellKnown::GetArgument()) {
8393 return emitSelfHostedGetArgument(callNode
);
8396 TaggedParserAtomIndex::WellKnown::SetIsInlinableLargeFunction()) {
8397 return emitSelfHostedSetIsInlinableLargeFunction(callNode
);
8399 if (calleeName
== TaggedParserAtomIndex::WellKnown::SetCanonicalName()) {
8400 return emitSelfHostedSetCanonicalName(callNode
);
8402 if (calleeName
== TaggedParserAtomIndex::WellKnown::IsNullOrUndefined()) {
8403 return emitSelfHostedIsNullOrUndefined(callNode
);
8405 if (calleeName
== TaggedParserAtomIndex::WellKnown::IteratorClose()) {
8406 return emitSelfHostedIteratorClose(callNode
);
8410 TaggedParserAtomIndex::WellKnown::UnsafeGetReservedSlot() ||
8411 calleeName
== TaggedParserAtomIndex::WellKnown::
8412 UnsafeGetObjectFromReservedSlot() ||
8413 calleeName
== TaggedParserAtomIndex::WellKnown::
8414 UnsafeGetInt32FromReservedSlot() ||
8415 calleeName
== TaggedParserAtomIndex::WellKnown::
8416 UnsafeGetStringFromReservedSlot()) {
8417 // Make sure that this call is correct, but don't emit any special code.
8418 assertSelfHostedUnsafeGetReservedSlot(argsList
);
8421 TaggedParserAtomIndex::WellKnown::UnsafeSetReservedSlot()) {
8422 // Make sure that this call is correct, but don't emit any special code.
8423 assertSelfHostedUnsafeSetReservedSlot(argsList
);
8429 uint32_t argc
= argsList
->count();
8430 bool isSpread
= IsSpreadOp(op
);
8431 bool isOptimizableSpread
= isSpread
&& argc
== 1;
8432 bool isDefaultDerivedClassConstructor
=
8433 sc
->isFunctionBox() && sc
->asFunctionBox()->isDerivedClassConstructor() &&
8434 sc
->asFunctionBox()->isSyntheticFunction();
8435 MOZ_ASSERT_IF(isDefaultDerivedClassConstructor
, isOptimizableSpread
);
8436 CallOrNewEmitter
cone(
8439 ? isDefaultDerivedClassConstructor
8440 ? CallOrNewEmitter::ArgumentsKind::PassthroughRest
8441 : CallOrNewEmitter::ArgumentsKind::SingleSpread
8442 : CallOrNewEmitter::ArgumentsKind::Other
,
8445 if (!emitCalleeAndThis(calleeNode
, callNode
, cone
)) {
8446 // [stack] CALLEE THIS
8449 if (!emitArguments(argsList
, isCall
, isSpread
, cone
)) {
8450 // [stack] CALLEE THIS ARGS...
8454 // Push new.target for construct calls.
8455 if (IsConstructOp(op
)) {
8456 if (op
== JSOp::SuperCall
|| op
== JSOp::SpreadSuperCall
) {
8457 if (!emitNewTarget(callNode
)) {
8458 // [stack] CALLEE THIS ARGS.. NEW.TARGET
8462 // Repush the callee as new.target
8463 uint32_t effectiveArgc
= isSpread
? 1 : argc
;
8464 if (!emitDupAt(effectiveArgc
+ 1)) {
8465 // [stack] CALLEE THIS ARGS.. CALLEE
8471 ParseNode
* coordNode
= getCoordNode(callNode
, calleeNode
, op
, argsList
);
8473 if (!cone
.emitEnd(argc
, coordNode
->pn_pos
.begin
)) {
8481 // This list must be kept in the same order in several places:
8482 // - The binary operators in ParseNode.h ,
8483 // - the binary operators in TokenKind.h
8484 // - the precedence list in Parser.cpp
8485 static const JSOp ParseNodeKindToJSOp
[] = {
8486 // Some binary ops require special code generation (PrivateIn);
8487 // these should not use BinaryOpParseNodeKindToJSOp. This table fills those
8488 // slots with Nops to make the rest of the table lookup work.
8489 JSOp::Coalesce
, JSOp::Or
, JSOp::And
, JSOp::BitOr
, JSOp::BitXor
,
8490 JSOp::BitAnd
, JSOp::StrictEq
, JSOp::Eq
, JSOp::StrictNe
, JSOp::Ne
,
8491 JSOp::Lt
, JSOp::Le
, JSOp::Gt
, JSOp::Ge
, JSOp::Instanceof
,
8492 JSOp::In
, JSOp::Nop
, JSOp::Lsh
, JSOp::Rsh
, JSOp::Ursh
,
8493 JSOp::Add
, JSOp::Sub
, JSOp::Mul
, JSOp::Div
, JSOp::Mod
,
8496 static inline JSOp
BinaryOpParseNodeKindToJSOp(ParseNodeKind pnk
) {
8497 MOZ_ASSERT(pnk
>= ParseNodeKind::BinOpFirst
);
8498 MOZ_ASSERT(pnk
<= ParseNodeKind::BinOpLast
);
8499 int parseNodeFirst
= size_t(ParseNodeKind::BinOpFirst
);
8501 int jsopArraySize
= std::size(ParseNodeKindToJSOp
);
8502 int parseNodeKindListSize
=
8503 size_t(ParseNodeKind::BinOpLast
) - parseNodeFirst
+ 1;
8504 MOZ_ASSERT(jsopArraySize
== parseNodeKindListSize
);
8505 // Ensure we don't use this to find an op for a parse node
8506 // requiring special emission rules.
8507 MOZ_ASSERT(ParseNodeKindToJSOp
[size_t(pnk
) - parseNodeFirst
] != JSOp::Nop
);
8509 return ParseNodeKindToJSOp
[size_t(pnk
) - parseNodeFirst
];
8512 bool BytecodeEmitter::emitRightAssociative(ListNode
* node
) {
8513 // ** is the only right-associative operator.
8514 MOZ_ASSERT(node
->isKind(ParseNodeKind::PowExpr
));
8516 // Right-associative operator chain.
8517 for (ParseNode
* subexpr
: node
->contents()) {
8518 if (!updateSourceCoordNotesIfNonLiteral(subexpr
)) {
8521 if (!emitTree(subexpr
)) {
8525 for (uint32_t i
= 0; i
< node
->count() - 1; i
++) {
8526 if (!emit1(JSOp::Pow
)) {
8533 bool BytecodeEmitter::emitLeftAssociative(ListNode
* node
) {
8534 // Left-associative operator chain.
8535 if (!emitTree(node
->head())) {
8538 JSOp op
= BinaryOpParseNodeKindToJSOp(node
->getKind());
8539 ParseNode
* nextExpr
= node
->head()->pn_next
;
8541 if (!updateSourceCoordNotesIfNonLiteral(nextExpr
)) {
8544 if (!emitTree(nextExpr
)) {
8550 } while ((nextExpr
= nextExpr
->pn_next
));
8554 bool BytecodeEmitter::emitPrivateInExpr(ListNode
* node
) {
8555 MOZ_ASSERT(node
->head()->isKind(ParseNodeKind::PrivateName
));
8557 NameNode
& privateNameNode
= node
->head()->as
<NameNode
>();
8558 TaggedParserAtomIndex privateName
= privateNameNode
.name();
8560 PrivateOpEmitter
xoe(this, PrivateOpEmitter::Kind::ErgonomicBrandCheck
,
8563 ParseNode
* valueNode
= node
->head()->pn_next
;
8564 MOZ_ASSERT(valueNode
->pn_next
== nullptr);
8566 if (!emitTree(valueNode
)) {
8571 if (!xoe
.emitReference()) {
8572 // [stack] OBJ BRAND if private method
8573 // [stack] OBJ NAME if private field or accessor.
8577 if (!xoe
.emitBrandCheck()) {
8578 // [stack] OBJ BRAND BOOL if private method
8579 // [stack] OBJ NAME BOOL if private field or accessor.
8583 if (!emitUnpickN(2)) {
8584 // [stack] BOOL OBJ BRAND if private method
8585 // [stack] BOOL OBJ NAME if private field or accessor.
8598 * Special `emitTree` for Optional Chaining case.
8599 * Examples of this are `emitOptionalChain`, `emitDeleteOptionalChain` and
8600 * `emitCalleeAndThisForOptionalChain`.
8602 bool BytecodeEmitter::emitOptionalTree(
8603 ParseNode
* pn
, OptionalEmitter
& oe
,
8604 ValueUsage valueUsage
/* = ValueUsage::WantValue */) {
8605 AutoCheckRecursionLimit
recursion(fc
);
8606 if (!recursion
.check(fc
)) {
8609 ParseNodeKind kind
= pn
->getKind();
8611 case ParseNodeKind::OptionalDotExpr
: {
8612 OptionalPropertyAccess
* prop
= &pn
->as
<OptionalPropertyAccess
>();
8613 bool isSuper
= false;
8614 PropOpEmitter
poe(this, PropOpEmitter::Kind::Get
,
8615 PropOpEmitter::ObjKind::Other
);
8616 if (!emitOptionalDotExpression(prop
, poe
, isSuper
, oe
)) {
8621 case ParseNodeKind::DotExpr
: {
8622 PropertyAccess
* prop
= &pn
->as
<PropertyAccess
>();
8623 bool isSuper
= prop
->isSuper();
8624 PropOpEmitter
poe(this, PropOpEmitter::Kind::Get
,
8625 isSuper
? PropOpEmitter::ObjKind::Super
8626 : PropOpEmitter::ObjKind::Other
);
8627 if (!emitOptionalDotExpression(prop
, poe
, isSuper
, oe
)) {
8633 case ParseNodeKind::OptionalElemExpr
: {
8634 OptionalPropertyByValue
* elem
= &pn
->as
<OptionalPropertyByValue
>();
8635 bool isSuper
= false;
8636 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
8637 ElemOpEmitter
eoe(this, ElemOpEmitter::Kind::Get
,
8638 ElemOpEmitter::ObjKind::Other
);
8640 if (!emitOptionalElemExpression(elem
, eoe
, isSuper
, oe
)) {
8645 case ParseNodeKind::ElemExpr
: {
8646 PropertyByValue
* elem
= &pn
->as
<PropertyByValue
>();
8647 bool isSuper
= elem
->isSuper();
8648 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
8649 ElemOpEmitter
eoe(this, ElemOpEmitter::Kind::Get
,
8650 isSuper
? ElemOpEmitter::ObjKind::Super
8651 : ElemOpEmitter::ObjKind::Other
);
8653 if (!emitOptionalElemExpression(elem
, eoe
, isSuper
, oe
)) {
8658 case ParseNodeKind::PrivateMemberExpr
:
8659 case ParseNodeKind::OptionalPrivateMemberExpr
: {
8660 PrivateMemberAccessBase
* privateExpr
= &pn
->as
<PrivateMemberAccessBase
>();
8661 PrivateOpEmitter
xoe(this, PrivateOpEmitter::Kind::Get
,
8662 privateExpr
->privateName().name());
8663 if (!emitOptionalPrivateExpression(privateExpr
, xoe
, oe
)) {
8668 case ParseNodeKind::CallExpr
:
8669 case ParseNodeKind::OptionalCallExpr
:
8670 if (!emitOptionalCall(&pn
->as
<CallNode
>(), oe
, valueUsage
)) {
8674 // List of accepted ParseNodeKinds that might appear only at the beginning
8675 // of an Optional Chain.
8676 // For example, a taggedTemplateExpr node might occur if we have
8677 // `test`?.b, with `test` as the taggedTemplateExpr ParseNode.
8680 // https://tc39.es/ecma262/#sec-primary-expression
8681 bool isPrimaryExpression
=
8682 kind
== ParseNodeKind::ThisExpr
|| kind
== ParseNodeKind::Name
||
8683 kind
== ParseNodeKind::PrivateName
||
8684 kind
== ParseNodeKind::NullExpr
|| kind
== ParseNodeKind::TrueExpr
||
8685 kind
== ParseNodeKind::FalseExpr
||
8686 kind
== ParseNodeKind::NumberExpr
||
8687 kind
== ParseNodeKind::BigIntExpr
||
8688 kind
== ParseNodeKind::StringExpr
||
8689 kind
== ParseNodeKind::ArrayExpr
||
8690 kind
== ParseNodeKind::ObjectExpr
||
8691 kind
== ParseNodeKind::Function
|| kind
== ParseNodeKind::ClassDecl
||
8692 kind
== ParseNodeKind::RegExpExpr
||
8693 kind
== ParseNodeKind::TemplateStringExpr
||
8694 kind
== ParseNodeKind::TemplateStringListExpr
||
8695 kind
== ParseNodeKind::RawUndefinedExpr
|| pn
->isInParens();
8697 // https://tc39.es/ecma262/#sec-left-hand-side-expressions
8698 bool isMemberExpression
= isPrimaryExpression
||
8699 kind
== ParseNodeKind::TaggedTemplateExpr
||
8700 kind
== ParseNodeKind::NewExpr
||
8701 kind
== ParseNodeKind::NewTargetExpr
||
8702 kind
== ParseNodeKind::ImportMetaExpr
;
8704 bool isCallExpression
= kind
== ParseNodeKind::SetThis
||
8705 kind
== ParseNodeKind::CallImportExpr
;
8707 MOZ_ASSERT(isMemberExpression
|| isCallExpression
,
8708 "Unknown ParseNodeKind for OptionalChain");
8710 return emitTree(pn
);
8715 // Handle the case of a call made on a OptionalChainParseNode.
8716 // For example `(a?.b)()` and `(a?.b)?.()`.
8717 bool BytecodeEmitter::emitCalleeAndThisForOptionalChain(
8718 UnaryNode
* optionalChain
, CallNode
* callNode
, CallOrNewEmitter
& cone
) {
8719 ParseNode
* calleeNode
= optionalChain
->kid();
8721 // Create a new OptionalEmitter, in order to emit the right bytecode
8723 OptionalEmitter
oe(this, bytecodeSection().stackDepth());
8725 if (!emitOptionalCalleeAndThis(calleeNode
, callNode
, cone
, oe
)) {
8726 // [stack] CALLEE THIS
8730 // complete the jump if necessary. This will set both the "this" value
8731 // and the "callee" value to undefined, if the callee is undefined. It
8732 // does not matter much what the this value is, the function call will
8733 // fail if it is not optional, and be set to undefined otherwise.
8734 if (!oe
.emitOptionalJumpTarget(JSOp::Undefined
,
8735 OptionalEmitter::Kind::Reference
)) {
8736 // [stack] # If shortcircuit
8737 // [stack] UNDEFINED UNDEFINED
8738 // [stack] # otherwise
8739 // [stack] CALLEE THIS
8745 bool BytecodeEmitter::emitOptionalChain(UnaryNode
* optionalChain
,
8746 ValueUsage valueUsage
) {
8747 ParseNode
* expr
= optionalChain
->kid();
8749 OptionalEmitter
oe(this, bytecodeSection().stackDepth());
8751 if (!emitOptionalTree(expr
, oe
, valueUsage
)) {
8756 if (!oe
.emitOptionalJumpTarget(JSOp::Undefined
)) {
8757 // [stack] # If shortcircuit
8758 // [stack] UNDEFINED
8759 // [stack] # otherwise
8767 bool BytecodeEmitter::emitOptionalDotExpression(PropertyAccessBase
* prop
,
8770 OptionalEmitter
& oe
) {
8771 if (!poe
.prepareForObj()) {
8777 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
8778 if (!emitGetThisForSuperBase(base
)) {
8783 if (!emitOptionalTree(&prop
->expression(), oe
)) {
8789 if (prop
->isKind(ParseNodeKind::OptionalDotExpr
)) {
8790 MOZ_ASSERT(!isSuper
);
8791 if (!oe
.emitJumpShortCircuit()) {
8792 // [stack] # if Jump
8793 // [stack] UNDEFINED-OR-NULL
8794 // [stack] # otherwise
8800 if (!poe
.emitGet(prop
->key().atom())) {
8808 bool BytecodeEmitter::emitOptionalElemExpression(PropertyByValueBase
* elem
,
8811 OptionalEmitter
& oe
) {
8812 if (!eoe
.prepareForObj()) {
8818 UnaryNode
* base
= &elem
->expression().as
<UnaryNode
>();
8819 if (!emitGetThisForSuperBase(base
)) {
8824 if (!emitOptionalTree(&elem
->expression(), oe
)) {
8830 if (elem
->isKind(ParseNodeKind::OptionalElemExpr
)) {
8831 MOZ_ASSERT(!isSuper
);
8832 if (!oe
.emitJumpShortCircuit()) {
8833 // [stack] # if Jump
8834 // [stack] UNDEFINED-OR-NULL
8835 // [stack] # otherwise
8841 if (!eoe
.prepareForKey()) {
8846 if (!emitTree(&elem
->key())) {
8847 // [stack] OBJ? OBJ KEY
8851 if (!eoe
.emitGet()) {
8859 bool BytecodeEmitter::emitOptionalPrivateExpression(
8860 PrivateMemberAccessBase
* privateExpr
, PrivateOpEmitter
& xoe
,
8861 OptionalEmitter
& oe
) {
8862 if (!emitOptionalTree(&privateExpr
->expression(), oe
)) {
8867 if (privateExpr
->isKind(ParseNodeKind::OptionalPrivateMemberExpr
)) {
8868 if (!oe
.emitJumpShortCircuit()) {
8869 // [stack] # if Jump
8870 // [stack] UNDEFINED-OR-NULL
8871 // [stack] # otherwise
8877 if (!xoe
.emitReference()) {
8881 if (!xoe
.emitGet()) {
8882 // [stack] CALLEE THIS # if call
8883 // [stack] VALUE # otherwise
8890 bool BytecodeEmitter::emitShortCircuit(ListNode
* node
, ValueUsage valueUsage
) {
8891 MOZ_ASSERT(node
->isKind(ParseNodeKind::OrExpr
) ||
8892 node
->isKind(ParseNodeKind::CoalesceExpr
) ||
8893 node
->isKind(ParseNodeKind::AndExpr
));
8896 * JSOp::Or converts the operand on the stack to boolean, leaves the original
8897 * value on the stack and jumps if true; otherwise it falls into the next
8898 * bytecode, which pops the left operand and then evaluates the right operand.
8899 * The jump goes around the right operand evaluation.
8901 * JSOp::And converts the operand on the stack to boolean and jumps if false;
8902 * otherwise it falls into the right operand's bytecode.
8905 TDZCheckCache
tdzCache(this);
8908 switch (node
->getKind()) {
8909 case ParseNodeKind::OrExpr
:
8912 case ParseNodeKind::CoalesceExpr
:
8913 op
= JSOp::Coalesce
;
8915 case ParseNodeKind::AndExpr
:
8919 MOZ_CRASH("Unexpected ParseNodeKind");
8924 // Left-associative operator chain: avoid too much recursion.
8926 // Emit all nodes but the last.
8927 for (ParseNode
* expr
: node
->contentsTo(node
->last())) {
8928 if (!emitTree(expr
)) {
8931 if (!emitJump(op
, &jump
)) {
8934 if (!emit1(JSOp::Pop
)) {
8939 // Emit the last node
8940 if (!emitTree(node
->last(), valueUsage
)) {
8944 if (!emitJumpTargetAndPatch(jump
)) {
8950 bool BytecodeEmitter::emitSequenceExpr(ListNode
* node
, ValueUsage valueUsage
) {
8951 for (ParseNode
* child
: node
->contentsTo(node
->last())) {
8952 if (!updateSourceCoordNotes(child
->pn_pos
.begin
)) {
8955 if (!emitTree(child
, ValueUsage::IgnoreValue
)) {
8958 if (!emit1(JSOp::Pop
)) {
8963 ParseNode
* child
= node
->last();
8964 if (!updateSourceCoordNotes(child
->pn_pos
.begin
)) {
8967 if (!emitTree(child
, valueUsage
)) {
8973 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
8974 // the comment on emitSwitch.
8975 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitIncOrDec(UnaryNode
* incDec
,
8976 ValueUsage valueUsage
) {
8977 switch (incDec
->kid()->getKind()) {
8978 case ParseNodeKind::DotExpr
:
8979 return emitPropIncDec(incDec
, valueUsage
);
8980 case ParseNodeKind::ElemExpr
:
8981 return emitElemIncDec(incDec
, valueUsage
);
8982 case ParseNodeKind::PrivateMemberExpr
:
8983 return emitPrivateIncDec(incDec
, valueUsage
);
8984 case ParseNodeKind::CallExpr
:
8985 return emitCallIncDec(incDec
);
8987 return emitNameIncDec(incDec
, valueUsage
);
8991 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
8992 // the comment on emitSwitch.
8993 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitLabeledStatement(
8994 const LabeledStatement
* labeledStmt
) {
8995 auto name
= labeledStmt
->label();
8996 LabelEmitter
label(this);
8998 label
.emitLabel(name
);
9000 if (!emitTree(labeledStmt
->statement())) {
9003 if (!label
.emitEnd()) {
9010 bool BytecodeEmitter::emitConditionalExpression(
9011 ConditionalExpression
& conditional
, ValueUsage valueUsage
) {
9012 CondEmitter
cond(this);
9013 if (!cond
.emitCond()) {
9017 ParseNode
* conditionNode
= &conditional
.condition();
9018 auto conditionKind
= IfEmitter::ConditionKind::Positive
;
9019 if (conditionNode
->isKind(ParseNodeKind::NotExpr
)) {
9020 conditionNode
= conditionNode
->as
<UnaryNode
>().kid();
9021 conditionKind
= IfEmitter::ConditionKind::Negative
;
9024 // NOTE: NotExpr of conditionNode may be unwrapped, and in that case the
9025 // negation is handled by conditionKind.
9026 if (!emitTree(conditionNode
)) {
9030 if (!cond
.emitThenElse(conditionKind
)) {
9034 if (!emitTree(&conditional
.thenExpression(), valueUsage
)) {
9038 if (!cond
.emitElse()) {
9042 if (!emitTree(&conditional
.elseExpression(), valueUsage
)) {
9046 if (!cond
.emitEnd()) {
9049 MOZ_ASSERT(cond
.pushed() == 1);
9054 // Check for an object-literal property list that can be handled by the
9055 // ObjLiteral writer. We ensure that for each `prop: value` pair, the key is a
9056 // constant name or numeric index, there is no accessor specified, and the value
9057 // can be encoded by an ObjLiteral instruction (constant number, string,
9058 // boolean, null/undefined).
9059 void BytecodeEmitter::isPropertyListObjLiteralCompatible(ListNode
* obj
,
9061 bool* withoutValues
) {
9063 bool valuesOK
= true;
9064 uint32_t propCount
= 0;
9066 for (ParseNode
* propdef
: obj
->contents()) {
9067 if (!propdef
->is
<BinaryNode
>()) {
9073 BinaryNode
* prop
= &propdef
->as
<BinaryNode
>();
9074 ParseNode
* key
= prop
->left();
9075 ParseNode
* value
= prop
->right();
9077 // Computed keys not OK (ObjLiteral data stores constant keys).
9078 if (key
->isKind(ParseNodeKind::ComputedName
)) {
9083 // BigIntExprs should have been lowered to computed names at parse
9084 // time, and so should be excluded above.
9085 MOZ_ASSERT(!key
->isKind(ParseNodeKind::BigIntExpr
));
9087 // Numeric keys OK as long as they are integers and in range.
9088 if (key
->isKind(ParseNodeKind::NumberExpr
)) {
9089 double numValue
= key
->as
<NumericLiteral
>().value();
9091 if (!NumberIsInt32(numValue
, &i
)) {
9095 if (!ObjLiteralWriter::arrayIndexInRange(i
)) {
9101 MOZ_ASSERT(key
->isKind(ParseNodeKind::ObjectPropertyName
) ||
9102 key
->isKind(ParseNodeKind::StringExpr
) ||
9103 key
->isKind(ParseNodeKind::NumberExpr
));
9105 AccessorType accessorType
=
9106 prop
->is
<PropertyDefinition
>()
9107 ? prop
->as
<PropertyDefinition
>().accessorType()
9108 : AccessorType::None
;
9109 if (accessorType
!= AccessorType::None
) {
9114 if (!isRHSObjLiteralCompatible(value
)) {
9119 if (propCount
> SharedPropMap::MaxPropsForNonDictionary
) {
9120 // JSOp::NewObject cannot accept dictionary-mode objects.
9124 *withValues
= keysOK
&& valuesOK
;
9125 *withoutValues
= keysOK
;
9128 bool BytecodeEmitter::isArrayObjLiteralCompatible(ListNode
* array
) {
9129 for (ParseNode
* elem
: array
->contents()) {
9130 if (elem
->isKind(ParseNodeKind::Spread
)) {
9133 if (!isRHSObjLiteralCompatible(elem
)) {
9140 bool BytecodeEmitter::emitPropertyList(ListNode
* obj
, PropertyEmitter
& pe
,
9141 PropListType type
) {
9142 // [stack] CTOR? OBJ
9144 size_t curFieldKeyIndex
= 0;
9145 size_t curStaticFieldKeyIndex
= 0;
9146 for (ParseNode
* propdef
: obj
->contents()) {
9147 if (propdef
->is
<ClassField
>()) {
9148 MOZ_ASSERT(type
== ClassBody
);
9149 // Only handle computing field keys here: the .initializers lambda array
9150 // is created elsewhere.
9151 ClassField
* field
= &propdef
->as
<ClassField
>();
9152 if (field
->name().getKind() == ParseNodeKind::ComputedName
) {
9155 ? TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_()
9156 : TaggedParserAtomIndex::WellKnown::dot_fieldKeys_();
9157 if (!emitGetName(fieldKeys
)) {
9158 // [stack] CTOR OBJ ARRAY
9162 ParseNode
* nameExpr
= field
->name().as
<UnaryNode
>().kid();
9164 if (!emitTree(nameExpr
, ValueUsage::WantValue
)) {
9165 // [stack] CTOR OBJ ARRAY KEY
9169 if (!emit1(JSOp::ToPropertyKey
)) {
9170 // [stack] CTOR OBJ ARRAY KEY
9174 size_t fieldKeysIndex
;
9175 if (field
->isStatic()) {
9176 fieldKeysIndex
= curStaticFieldKeyIndex
++;
9178 fieldKeysIndex
= curFieldKeyIndex
++;
9181 if (!emitUint32Operand(JSOp::InitElemArray
, fieldKeysIndex
)) {
9182 // [stack] CTOR OBJ ARRAY
9186 if (!emit1(JSOp::Pop
)) {
9194 if (propdef
->isKind(ParseNodeKind::StaticClassBlock
)) {
9195 // Static class blocks are emitted as part of
9196 // emitCreateMemberInitializers.
9200 if (propdef
->is
<LexicalScopeNode
>()) {
9201 // Constructors are sometimes wrapped in LexicalScopeNodes. As we
9202 // already handled emitting the constructor, skip it.
9204 propdef
->as
<LexicalScopeNode
>().scopeBody()->is
<ClassMethod
>());
9208 // Handle __proto__: v specially because *only* this form, and no other
9209 // involving "__proto__", performs [[Prototype]] mutation.
9210 if (propdef
->isKind(ParseNodeKind::MutateProto
)) {
9212 MOZ_ASSERT(type
== ObjectLiteral
);
9213 if (!pe
.prepareForProtoValue(propdef
->pn_pos
.begin
)) {
9217 if (!emitTree(propdef
->as
<UnaryNode
>().kid())) {
9218 // [stack] OBJ PROTO
9221 if (!pe
.emitMutateProto()) {
9228 if (propdef
->isKind(ParseNodeKind::Spread
)) {
9229 MOZ_ASSERT(type
== ObjectLiteral
);
9231 if (!pe
.prepareForSpreadOperand(propdef
->pn_pos
.begin
)) {
9235 if (!emitTree(propdef
->as
<UnaryNode
>().kid())) {
9236 // [stack] OBJ OBJ VAL
9239 if (!pe
.emitSpread()) {
9246 BinaryNode
* prop
= &propdef
->as
<BinaryNode
>();
9248 ParseNode
* key
= prop
->left();
9249 AccessorType accessorType
;
9250 if (prop
->is
<ClassMethod
>()) {
9251 ClassMethod
& method
= prop
->as
<ClassMethod
>();
9252 accessorType
= method
.accessorType();
9254 if (!method
.isStatic() && key
->isKind(ParseNodeKind::PrivateName
) &&
9255 accessorType
!= AccessorType::None
) {
9256 // Private non-static accessors are stamped onto instances from
9257 // initializers; see emitCreateMemberInitializers.
9260 } else if (prop
->is
<PropertyDefinition
>()) {
9261 accessorType
= prop
->as
<PropertyDefinition
>().accessorType();
9263 accessorType
= AccessorType::None
;
9266 auto emitValue
= [this, &key
, &prop
, accessorType
, &pe
]() {
9267 // [stack] CTOR? OBJ CTOR? KEY?
9269 ParseNode
* propVal
= prop
->right();
9270 if (propVal
->isDirectRHSAnonFunction()) {
9271 // The following branches except for the last `else` clause emit the
9272 // cases handled in NameResolver::resolveFun (see NameFunctions.cpp)
9273 if (key
->isKind(ParseNodeKind::ObjectPropertyName
) ||
9274 key
->isKind(ParseNodeKind::PrivateName
) ||
9275 key
->isKind(ParseNodeKind::StringExpr
)) {
9276 auto keyAtom
= key
->as
<NameNode
>().atom();
9277 if (!emitAnonymousFunctionWithName(propVal
, keyAtom
)) {
9278 // [stack] CTOR? OBJ CTOR? VAL
9281 } else if (key
->isKind(ParseNodeKind::NumberExpr
)) {
9282 MOZ_ASSERT(accessorType
== AccessorType::None
);
9284 auto keyAtom
= key
->as
<NumericLiteral
>().toAtom(fc
, parserAtoms());
9288 if (!emitAnonymousFunctionWithName(propVal
, keyAtom
)) {
9289 // [stack] CTOR? OBJ CTOR? KEY VAL
9292 } else if (key
->isKind(ParseNodeKind::ComputedName
) &&
9293 (key
->as
<UnaryNode
>().kid()->isKind(
9294 ParseNodeKind::NumberExpr
) ||
9295 key
->as
<UnaryNode
>().kid()->isKind(
9296 ParseNodeKind::StringExpr
)) &&
9297 accessorType
== AccessorType::None
) {
9298 ParseNode
* keyKid
= key
->as
<UnaryNode
>().kid();
9299 if (keyKid
->isKind(ParseNodeKind::NumberExpr
)) {
9301 keyKid
->as
<NumericLiteral
>().toAtom(fc
, parserAtoms());
9305 if (!emitAnonymousFunctionWithName(propVal
, keyAtom
)) {
9306 // [stack] CTOR? OBJ CTOR? KEY VAL
9310 MOZ_ASSERT(keyKid
->isKind(ParseNodeKind::StringExpr
));
9311 auto keyAtom
= keyKid
->as
<NameNode
>().atom();
9312 if (!emitAnonymousFunctionWithName(propVal
, keyAtom
)) {
9313 // [stack] CTOR? OBJ CTOR? KEY VAL
9318 // Either a proper computed property name or a synthetic computed
9319 // property name for BigInt keys.
9320 MOZ_ASSERT(key
->isKind(ParseNodeKind::ComputedName
));
9322 FunctionPrefixKind prefix
=
9323 accessorType
== AccessorType::None
? FunctionPrefixKind::None
9324 : accessorType
== AccessorType::Getter
? FunctionPrefixKind::Get
9325 : FunctionPrefixKind::Set
;
9327 if (!emitAnonymousFunctionWithComputedName(propVal
, prefix
)) {
9328 // [stack] CTOR? OBJ CTOR? KEY VAL
9333 if (!emitTree(propVal
)) {
9334 // [stack] CTOR? OBJ CTOR? KEY? VAL
9339 if (propVal
->is
<FunctionNode
>() &&
9340 propVal
->as
<FunctionNode
>().funbox()->needsHomeObject()) {
9341 if (!pe
.emitInitHomeObject()) {
9342 // [stack] CTOR? OBJ CTOR? KEY? FUN
9347 #ifdef ENABLE_DECORATORS
9348 if (prop
->is
<ClassMethod
>()) {
9349 ClassMethod
& method
= prop
->as
<ClassMethod
>();
9350 if (method
.decorators() && !method
.decorators()->empty()) {
9351 DecoratorEmitter::Kind kind
;
9352 switch (method
.accessorType()) {
9353 case AccessorType::Getter
:
9354 kind
= DecoratorEmitter::Getter
;
9356 case AccessorType::Setter
:
9357 kind
= DecoratorEmitter::Setter
;
9359 case AccessorType::None
:
9360 kind
= DecoratorEmitter::Method
;
9364 // The decorators are applied to the current value on the stack,
9365 // possibly replacing it.
9366 DecoratorEmitter
de(this);
9367 if (!de
.emitApplyDecoratorsToElementDefinition(
9368 kind
, key
, method
.decorators(), method
.isStatic())) {
9369 // [stack] CTOR? OBJ CTOR? KEY? VAL
9379 PropertyEmitter::Kind kind
=
9380 (type
== ClassBody
&& propdef
->as
<ClassMethod
>().isStatic())
9381 ? PropertyEmitter::Kind::Static
9382 : PropertyEmitter::Kind::Prototype
;
9383 if (key
->isKind(ParseNodeKind::ObjectPropertyName
) ||
9384 key
->isKind(ParseNodeKind::StringExpr
)) {
9385 // [stack] CTOR? OBJ
9387 auto keyAtom
= key
->as
<NameNode
>().atom();
9389 // emitClass took care of constructor already.
9390 if (type
== ClassBody
&&
9391 keyAtom
== TaggedParserAtomIndex::WellKnown::constructor() &&
9392 !propdef
->as
<ClassMethod
>().isStatic()) {
9396 if (!pe
.prepareForPropValue(propdef
->pn_pos
.begin
, kind
)) {
9397 // [stack] CTOR? OBJ CTOR?
9402 // [stack] CTOR? OBJ CTOR? VAL
9406 if (!pe
.emitInit(accessorType
, keyAtom
)) {
9407 // [stack] CTOR? OBJ
9414 if (key
->isKind(ParseNodeKind::NumberExpr
)) {
9415 // [stack] CTOR? OBJ
9416 if (!pe
.prepareForIndexPropKey(propdef
->pn_pos
.begin
, kind
)) {
9417 // [stack] CTOR? OBJ CTOR?
9420 if (!emitNumberOp(key
->as
<NumericLiteral
>().value())) {
9421 // [stack] CTOR? OBJ CTOR? KEY
9424 if (!pe
.prepareForIndexPropValue()) {
9425 // [stack] CTOR? OBJ CTOR? KEY
9429 // [stack] CTOR? OBJ CTOR? KEY VAL
9433 if (!pe
.emitInitIndexOrComputed(accessorType
)) {
9434 // [stack] CTOR? OBJ
9441 if (key
->isKind(ParseNodeKind::ComputedName
)) {
9442 // Either a proper computed property name or a synthetic computed property
9443 // name for BigInt keys.
9445 // [stack] CTOR? OBJ
9447 if (!pe
.prepareForComputedPropKey(propdef
->pn_pos
.begin
, kind
)) {
9448 // [stack] CTOR? OBJ CTOR?
9451 if (!emitTree(key
->as
<UnaryNode
>().kid())) {
9452 // [stack] CTOR? OBJ CTOR? KEY
9455 if (!pe
.prepareForComputedPropValue()) {
9456 // [stack] CTOR? OBJ CTOR? KEY
9460 // [stack] CTOR? OBJ CTOR? KEY VAL
9464 if (!pe
.emitInitIndexOrComputed(accessorType
)) {
9465 // [stack] CTOR? OBJ
9472 MOZ_ASSERT(key
->isKind(ParseNodeKind::PrivateName
));
9473 MOZ_ASSERT(type
== ClassBody
);
9475 auto* privateName
= &key
->as
<NameNode
>();
9477 if (kind
== PropertyEmitter::Kind::Prototype
) {
9478 MOZ_ASSERT(accessorType
== AccessorType::None
);
9479 if (!pe
.prepareForPrivateMethod()) {
9483 NameOpEmitter
noe(this, privateName
->atom(),
9484 NameOpEmitter::Kind::SimpleAssignment
);
9486 // Ensure the NameOp emitter doesn't push an environment onto the stack,
9487 // because that would change the stack location of the home object.
9488 MOZ_ASSERT(noe
.loc().kind() == NameLocation::Kind::FrameSlot
||
9489 noe
.loc().kind() == NameLocation::Kind::EnvironmentCoordinate
);
9491 if (!noe
.prepareForRhs()) {
9496 // [stack] CTOR OBJ METHOD
9499 if (!noe
.emitAssignment()) {
9500 // [stack] CTOR OBJ METHOD
9503 if (!emit1(JSOp::Pop
)) {
9507 if (!pe
.skipInit()) {
9514 MOZ_ASSERT(kind
== PropertyEmitter::Kind::Static
);
9518 if (!pe
.prepareForPrivateStaticMethod(propdef
->pn_pos
.begin
)) {
9519 // [stack] CTOR OBJ CTOR
9522 if (!emitGetPrivateName(privateName
)) {
9523 // [stack] CTOR OBJ CTOR KEY
9527 // [stack] CTOR OBJ CTOR KEY VAL
9531 if (!pe
.emitPrivateStaticMethod(accessorType
)) {
9536 if (privateName
->privateNameKind() == PrivateNameKind::Setter
) {
9537 if (!emitDupAt(1)) {
9538 // [stack] CTOR OBJ CTOR
9541 if (!emitGetPrivateName(privateName
)) {
9542 // [stack] CTOR OBJ CTOR NAME
9545 if (!emitAtomOp(JSOp::GetIntrinsic
,
9546 TaggedParserAtomIndex::WellKnown::NoPrivateGetter())) {
9547 // [stack] CTOR OBJ CTOR NAME FUN
9550 if (!emit1(JSOp::InitHiddenElemGetter
)) {
9551 // [stack] CTOR OBJ CTOR
9554 if (!emit1(JSOp::Pop
)) {
9564 bool BytecodeEmitter::emitPropertyListObjLiteral(ListNode
* obj
, JSOp op
,
9565 bool useObjLiteralValues
) {
9566 ObjLiteralWriter writer
;
9569 // In self-hosted JS, we check duplication only on debug build.
9570 mozilla::Maybe
<mozilla::HashSet
<frontend::TaggedParserAtomIndex
,
9571 frontend::TaggedParserAtomIndexHasher
>>
9572 selfHostedPropNames
;
9573 if (emitterMode
== BytecodeEmitter::SelfHosting
) {
9574 selfHostedPropNames
.emplace();
9578 if (op
== JSOp::Object
) {
9579 writer
.beginObject(op
);
9581 MOZ_ASSERT(op
== JSOp::NewObject
);
9582 writer
.beginShape(op
);
9585 for (ParseNode
* propdef
: obj
->contents()) {
9586 BinaryNode
* prop
= &propdef
->as
<BinaryNode
>();
9587 ParseNode
* key
= prop
->left();
9589 if (key
->is
<NameNode
>()) {
9590 if (emitterMode
== BytecodeEmitter::SelfHosting
) {
9591 auto propName
= key
->as
<NameNode
>().atom();
9593 // Self-hosted JS shouldn't contain duplicate properties.
9594 auto p
= selfHostedPropNames
->lookupForAdd(propName
);
9596 if (!selfHostedPropNames
->add(p
, propName
)) {
9597 js::ReportOutOfMemory(fc
);
9601 writer
.setPropNameNoDuplicateCheck(parserAtoms(), propName
);
9603 if (!writer
.setPropName(parserAtoms(), key
->as
<NameNode
>().atom())) {
9608 double numValue
= key
->as
<NumericLiteral
>().value();
9610 DebugOnly
<bool> numIsInt
=
9611 NumberIsInt32(numValue
, &i
); // checked previously.
9612 MOZ_ASSERT(numIsInt
);
9614 ObjLiteralWriter::arrayIndexInRange(i
)); // checked previously.
9616 // Ignore indexed properties if we're not storing property values, and
9617 // rely on InitElem ops to define those. These properties will be either
9618 // dense elements (not possible to represent in the literal's shape) or
9619 // sparse elements (enumerated separately, so this doesn't affect property
9620 // iteration order).
9621 if (!useObjLiteralValues
) {
9625 writer
.setPropIndex(i
);
9628 if (useObjLiteralValues
) {
9629 MOZ_ASSERT(op
== JSOp::Object
);
9630 ParseNode
* value
= prop
->right();
9631 if (!emitObjLiteralValue(writer
, value
)) {
9635 if (!writer
.propWithUndefinedValue(fc
)) {
9642 if (!addObjLiteralData(writer
, &index
)) {
9646 // JSOp::Object may only be used by (top-level) run-once scripts.
9647 MOZ_ASSERT_IF(op
== JSOp::Object
,
9648 sc
->isTopLevelContext() && sc
->treatAsRunOnce());
9650 if (!emitGCIndexOp(op
, index
)) {
9658 bool BytecodeEmitter::emitDestructuringRestExclusionSetObjLiteral(
9659 ListNode
* pattern
) {
9660 // Note: if we want to squeeze out a little more performance, we could switch
9661 // to the `JSOp::Object` opcode, because the exclusion set object is never
9662 // exposed to the user, so it's safe to bake the object into the bytecode.
9663 constexpr JSOp op
= JSOp::NewObject
;
9665 ObjLiteralWriter writer
;
9666 writer
.beginShape(op
);
9668 for (ParseNode
* member
: pattern
->contents()) {
9669 if (member
->isKind(ParseNodeKind::Spread
)) {
9670 MOZ_ASSERT(!member
->pn_next
, "unexpected trailing element after spread");
9674 TaggedParserAtomIndex atom
;
9675 if (member
->isKind(ParseNodeKind::MutateProto
)) {
9676 atom
= TaggedParserAtomIndex::WellKnown::proto_();
9678 ParseNode
* key
= member
->as
<BinaryNode
>().left();
9679 atom
= key
->as
<NameNode
>().atom();
9682 if (!writer
.setPropName(parserAtoms(), atom
)) {
9686 if (!writer
.propWithUndefinedValue(fc
)) {
9692 if (!addObjLiteralData(writer
, &index
)) {
9696 if (!emitGCIndexOp(op
, index
)) {
9704 bool BytecodeEmitter::emitObjLiteralArray(ListNode
* array
) {
9705 MOZ_ASSERT(checkSingletonContext());
9707 constexpr JSOp op
= JSOp::Object
;
9709 ObjLiteralWriter writer
;
9710 writer
.beginArray(op
);
9712 writer
.beginDenseArrayElements();
9713 for (ParseNode
* elem
: array
->contents()) {
9714 if (!emitObjLiteralValue(writer
, elem
)) {
9720 if (!addObjLiteralData(writer
, &index
)) {
9724 if (!emitGCIndexOp(op
, index
)) {
9732 bool BytecodeEmitter::isRHSObjLiteralCompatible(ParseNode
* value
) {
9733 return value
->isKind(ParseNodeKind::NumberExpr
) ||
9734 value
->isKind(ParseNodeKind::TrueExpr
) ||
9735 value
->isKind(ParseNodeKind::FalseExpr
) ||
9736 value
->isKind(ParseNodeKind::NullExpr
) ||
9737 value
->isKind(ParseNodeKind::RawUndefinedExpr
) ||
9738 value
->isKind(ParseNodeKind::StringExpr
) ||
9739 value
->isKind(ParseNodeKind::TemplateStringExpr
);
9742 bool BytecodeEmitter::emitObjLiteralValue(ObjLiteralWriter
& writer
,
9744 MOZ_ASSERT(isRHSObjLiteralCompatible(value
));
9745 if (value
->isKind(ParseNodeKind::NumberExpr
)) {
9746 double numValue
= value
->as
<NumericLiteral
>().value();
9749 if (NumberIsInt32(numValue
, &i
)) {
9752 v
.setDouble(numValue
);
9754 if (!writer
.propWithConstNumericValue(fc
, v
)) {
9757 } else if (value
->isKind(ParseNodeKind::TrueExpr
)) {
9758 if (!writer
.propWithTrueValue(fc
)) {
9761 } else if (value
->isKind(ParseNodeKind::FalseExpr
)) {
9762 if (!writer
.propWithFalseValue(fc
)) {
9765 } else if (value
->isKind(ParseNodeKind::NullExpr
)) {
9766 if (!writer
.propWithNullValue(fc
)) {
9769 } else if (value
->isKind(ParseNodeKind::RawUndefinedExpr
)) {
9770 if (!writer
.propWithUndefinedValue(fc
)) {
9773 } else if (value
->isKind(ParseNodeKind::StringExpr
) ||
9774 value
->isKind(ParseNodeKind::TemplateStringExpr
)) {
9775 if (!writer
.propWithAtomValue(fc
, parserAtoms(),
9776 value
->as
<NameNode
>().atom())) {
9780 MOZ_CRASH("Unexpected parse node");
9785 static bool NeedsPrivateBrand(ParseNode
* member
) {
9786 return member
->is
<ClassMethod
>() &&
9787 member
->as
<ClassMethod
>().name().isKind(ParseNodeKind::PrivateName
) &&
9788 !member
->as
<ClassMethod
>().isStatic();
9791 mozilla::Maybe
<MemberInitializers
> BytecodeEmitter::setupMemberInitializers(
9792 ListNode
* classMembers
, FieldPlacement placement
) {
9793 bool isStatic
= placement
== FieldPlacement::Static
;
9795 size_t numFields
= 0;
9796 size_t numPrivateInitializers
= 0;
9797 bool hasPrivateBrand
= false;
9798 for (ParseNode
* member
: classMembers
->contents()) {
9799 if (NeedsFieldInitializer(member
, isStatic
)) {
9801 } else if (NeedsAccessorInitializer(member
, isStatic
)) {
9802 numPrivateInitializers
++;
9803 hasPrivateBrand
= true;
9804 } else if (NeedsPrivateBrand(member
)) {
9805 hasPrivateBrand
= true;
9809 // If there are more initializers than can be represented, return invalid.
9810 if (numFields
+ numPrivateInitializers
>
9811 MemberInitializers::MaxInitializers
) {
9815 MemberInitializers(hasPrivateBrand
, numFields
+ numPrivateInitializers
));
9818 // Purpose of .fieldKeys:
9819 // Computed field names (`["x"] = 2;`) must be ran at class-evaluation time,
9820 // not object construction time. The transformation to do so is roughly as
9824 // [keyExpr] = valueExpr;
9827 // let .fieldKeys = [keyExpr];
9828 // let .initializers = [
9830 // this[.fieldKeys[0]] = valueExpr;
9835 // .initializers[0]();
9839 // BytecodeEmitter::emitCreateFieldKeys does `let .fieldKeys = [...];`
9840 // BytecodeEmitter::emitPropertyList fills in the elements of the array.
9841 // See GeneralParser::fieldInitializer for the `this[.fieldKeys[0]]` part.
9842 bool BytecodeEmitter::emitCreateFieldKeys(ListNode
* obj
,
9843 FieldPlacement placement
) {
9844 bool isStatic
= placement
== FieldPlacement::Static
;
9845 auto isFieldWithComputedName
= [isStatic
](ParseNode
* propdef
) {
9846 return propdef
->is
<ClassField
>() &&
9847 propdef
->as
<ClassField
>().isStatic() == isStatic
&&
9848 propdef
->as
<ClassField
>().name().getKind() ==
9849 ParseNodeKind::ComputedName
;
9852 size_t numFieldKeys
= std::count_if(
9853 obj
->contents().begin(), obj
->contents().end(), isFieldWithComputedName
);
9854 if (numFieldKeys
== 0) {
9859 isStatic
? TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_()
9860 : TaggedParserAtomIndex::WellKnown::dot_fieldKeys_();
9861 NameOpEmitter
noe(this, fieldKeys
, NameOpEmitter::Kind::Initialize
);
9862 if (!noe
.prepareForRhs()) {
9866 if (!emitUint32Operand(JSOp::NewArray
, numFieldKeys
)) {
9871 if (!noe
.emitAssignment()) {
9876 if (!emit1(JSOp::Pop
)) {
9884 static bool HasInitializer(ParseNode
* node
, bool isStaticContext
) {
9885 return (node
->is
<ClassField
>() &&
9886 node
->as
<ClassField
>().isStatic() == isStaticContext
) ||
9887 (isStaticContext
&& node
->is
<StaticClassBlock
>());
9890 static FunctionNode
* GetInitializer(ParseNode
* node
, bool isStaticContext
) {
9891 MOZ_ASSERT(HasInitializer(node
, isStaticContext
));
9892 MOZ_ASSERT_IF(!node
->is
<ClassField
>(), isStaticContext
);
9893 return node
->is
<ClassField
>() ? node
->as
<ClassField
>().initializer()
9894 : node
->as
<StaticClassBlock
>().function();
9897 static bool IsPrivateInstanceAccessor(const ClassMethod
* classMethod
) {
9898 return !classMethod
->isStatic() &&
9899 classMethod
->name().isKind(ParseNodeKind::PrivateName
) &&
9900 classMethod
->accessorType() != AccessorType::None
;
9903 bool BytecodeEmitter::emitCreateMemberInitializers(ClassEmitter
& ce
,
9905 FieldPlacement placement
9906 #ifdef ENABLE_DECORATORS
9911 // FieldPlacement::Instance, hasHeritage == false
9914 // FieldPlacement::Instance, hasHeritage == true
9915 // [stack] HOMEOBJ HERITAGE
9917 // FieldPlacement::Static
9918 // [stack] CTOR HOMEOBJ
9919 #ifdef ENABLE_DECORATORS
9920 MOZ_ASSERT_IF(placement
== FieldPlacement::Static
, !hasHeritage
);
9922 mozilla::Maybe
<MemberInitializers
> memberInitializers
=
9923 setupMemberInitializers(obj
, placement
);
9924 if (!memberInitializers
) {
9925 ReportAllocationOverflow(fc
);
9929 size_t numInitializers
= memberInitializers
->numMemberInitializers
;
9930 if (numInitializers
== 0) {
9934 bool isStatic
= placement
== FieldPlacement::Static
;
9935 if (!ce
.prepareForMemberInitializers(numInitializers
, isStatic
)) {
9936 // [stack] HOMEOBJ HERITAGE? ARRAY
9938 // [stack] CTOR HOMEOBJ ARRAY
9942 // Private accessors could be used in the field initializers, so make sure
9943 // accessor initializers appear earlier in the .initializers array so they
9944 // run first. Static private methods are not initialized using initializers
9945 // (emitPropertyList emits bytecode to stamp them onto the constructor), so
9946 // skip this step if isStatic.
9948 if (!emitPrivateMethodInitializers(ce
, obj
)) {
9953 for (ParseNode
* propdef
: obj
->contents()) {
9954 if (!HasInitializer(propdef
, isStatic
)) {
9958 FunctionNode
* initializer
= GetInitializer(propdef
, isStatic
);
9960 if (!ce
.prepareForMemberInitializer()) {
9963 if (!emitTree(initializer
)) {
9964 // [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA
9966 // [stack] CTOR HOMEOBJ ARRAY LAMBDA
9969 if (initializer
->funbox()->needsHomeObject()) {
9970 MOZ_ASSERT(initializer
->funbox()->allowSuperProperty());
9971 if (!ce
.emitMemberInitializerHomeObject(isStatic
)) {
9972 // [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA
9974 // [stack] CTOR HOMEOBJ ARRAY LAMBDA
9978 if (!ce
.emitStoreMemberInitializer()) {
9979 // [stack] HOMEOBJ HERITAGE? ARRAY
9981 // [stack] CTOR HOMEOBJ ARRAY
9986 #ifdef ENABLE_DECORATORS
9987 // Index to use to append new initializers returned by decorators to the array
9988 if (!emitNumberOp(numInitializers
)) {
9989 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX
9991 // [stack] CTOR HOMEOBJ ARRAY INDEX
9995 for (ParseNode
* propdef
: obj
->contents()) {
9996 if (!propdef
->is
<ClassField
>()) {
9999 ClassField
* field
= &propdef
->as
<ClassField
>();
10000 if (field
->isStatic() != isStatic
) {
10003 if (field
->decorators() && !field
->decorators()->empty()) {
10004 DecoratorEmitter
de(this);
10005 if (!field
->hasAccessor()) {
10006 if (!de
.emitApplyDecoratorsToFieldDefinition(
10007 &field
->name(), field
->decorators(), field
->isStatic())) {
10008 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS
10010 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS
10014 ClassMethod
* accessorGetterNode
= field
->accessorGetterNode();
10015 auto accessorGetterKeyAtom
=
10016 accessorGetterNode
->left()->as
<NameNode
>().atom();
10017 ClassMethod
* accessorSetterNode
= field
->accessorSetterNode();
10018 auto accessorSetterKeyAtom
=
10019 accessorSetterNode
->left()->as
<NameNode
>().atom();
10020 if (!IsPrivateInstanceAccessor(accessorGetterNode
)) {
10021 if (!emitTree(&accessorGetterNode
->method())) {
10022 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER
10024 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER
10027 if (!emitTree(&accessorSetterNode
->method())) {
10028 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER SETTER
10030 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER SETTER
10034 MOZ_ASSERT(IsPrivateInstanceAccessor(accessorSetterNode
));
10035 auto getAccessor
= [this](
10036 ClassMethod
* classMethod
,
10037 TaggedParserAtomIndex
& updatedAtom
) -> bool {
10040 // Synthesize a name for the lexical variable that will store the
10041 // private method body.
10042 TaggedParserAtomIndex name
=
10043 classMethod
->name().as
<NameNode
>().atom();
10044 AccessorType accessorType
= classMethod
->accessorType();
10045 StringBuffer
storedMethodName(fc
);
10046 if (!storedMethodName
.append(parserAtoms(), name
)) {
10049 if (!storedMethodName
.append(accessorType
== AccessorType::Getter
10054 updatedAtom
= storedMethodName
.finishParserAtom(parserAtoms(), fc
);
10055 if (!updatedAtom
) {
10059 return emitGetName(updatedAtom
);
10060 // [stack] ACCESSOR
10063 if (!getAccessor(accessorGetterNode
, accessorGetterKeyAtom
)) {
10064 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER
10066 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER
10070 if (!getAccessor(accessorSetterNode
, accessorSetterKeyAtom
)) {
10071 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER SETTER
10073 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER SETTER
10078 if (!de
.emitApplyDecoratorsToAccessorDefinition(
10079 &field
->name(), field
->decorators(), field
->isStatic())) {
10080 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER SETTER INITS
10082 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER SETTER INITS
10086 if (!emitUnpickN(2)) {
10087 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER SETTER
10089 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER SETTER
10093 if (!IsPrivateInstanceAccessor(accessorGetterNode
)) {
10095 if (!emitPickN(hasHeritage
? 6 : 5)) {
10096 // [stack] HERITAGE? ARRAY INDEX INITS GETTER SETTER HOMEOBJ
10100 if (!emitPickN(6)) {
10101 // [stack] HOMEOBJ ARRAY INDEX INITS GETTER SETTER CTOR
10104 if (!emitPickN(6)) {
10105 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ
10110 PropertyEmitter::Kind kind
= field
->isStatic()
10111 ? PropertyEmitter::Kind::Static
10112 : PropertyEmitter::Kind::Prototype
;
10113 if (!accessorGetterNode
->name().isKind(ParseNodeKind::PrivateName
)) {
10115 !accessorSetterNode
->name().isKind(ParseNodeKind::PrivateName
));
10117 if (!ce
.prepareForPropValue(propdef
->pn_pos
.begin
, kind
)) {
10118 // [stack] HERITAGE? ARRAY INDEX INITS GETTER SETTER HOMEOBJ
10120 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ CTOR
10123 if (!emitPickN(isStatic
? 3 : 1)) {
10124 // [stack] HERITAGE? ARRAY INDEX INITS GETTER HOMEOBJ SETTER
10126 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR SETTER
10129 if (!ce
.emitInit(AccessorType::Setter
, accessorSetterKeyAtom
)) {
10130 // [stack] HERITAGE? ARRAY INDEX INITS GETTER HOMEOBJ
10132 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ
10136 if (!ce
.prepareForPropValue(propdef
->pn_pos
.begin
, kind
)) {
10137 // [stack] HERITAGE? ARRAY INDEX INITS GETTER HOMEOBJ
10139 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR
10142 if (!emitPickN(isStatic
? 3 : 1)) {
10143 // [stack] HERITAGE? ARRAY INDEX INITS HOMEOBJ GETTER
10145 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ CTOR GETTER
10148 if (!ce
.emitInit(AccessorType::Getter
, accessorGetterKeyAtom
)) {
10149 // [stack] HERITAGE? ARRAY INDEX INITS HOMEOBJ
10151 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ
10155 MOZ_ASSERT(isStatic
);
10156 // The getter and setter share the same name.
10157 if (!emitNewPrivateName(accessorSetterKeyAtom
,
10158 accessorSetterKeyAtom
)) {
10161 if (!ce
.prepareForPrivateStaticMethod(propdef
->pn_pos
.begin
)) {
10162 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ CTOR
10165 if (!emitGetPrivateName(
10166 &accessorSetterNode
->name().as
<NameNode
>())) {
10167 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ CTOR
10171 if (!emitPickN(4)) {
10172 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR KEY
10176 if (!ce
.emitPrivateStaticMethod(AccessorType::Setter
)) {
10177 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ
10181 if (!ce
.prepareForPrivateStaticMethod(propdef
->pn_pos
.begin
)) {
10182 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR
10185 if (!emitGetPrivateName(
10186 &accessorGetterNode
->name().as
<NameNode
>())) {
10187 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR KEY
10190 if (!emitPickN(4)) {
10191 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ CTOR KEY GETTER
10194 if (!ce
.emitPrivateStaticMethod(AccessorType::Getter
)) {
10195 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ
10201 if (!emitUnpickN(hasHeritage
? 4 : 3)) {
10202 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS
10206 if (!emitUnpickN(4)) {
10207 // [stack] HOMEOBJ ARRAY INDEX INITS CTOR
10210 if (!emitUnpickN(4)) {
10211 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS
10216 MOZ_ASSERT(IsPrivateInstanceAccessor(accessorSetterNode
));
10218 if (!emitLexicalInitialization(accessorSetterKeyAtom
)) {
10219 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER SETTER
10221 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER SETTER
10225 if (!emitPopN(1)) {
10226 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER
10228 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER
10232 if (!emitLexicalInitialization(accessorGetterKeyAtom
)) {
10233 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER
10235 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER
10239 if (!emitPopN(1)) {
10240 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS
10242 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS
10247 if (!emit1(JSOp::InitElemInc
)) {
10248 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX
10250 // [stack] CTOR HOMEOBJ ARRAY INDEX
10257 if (!emitPopN(1)) {
10258 // [stack] HOMEOBJ HERITAGE? ARRAY
10260 // [stack] CTOR HOMEOBJ ARRAY
10265 if (!ce
.emitMemberInitializersEnd()) {
10266 // [stack] HOMEOBJ HERITAGE?
10268 // [stack] CTOR HOMEOBJ
10275 bool BytecodeEmitter::emitPrivateMethodInitializers(ClassEmitter
& ce
,
10277 for (ParseNode
* propdef
: obj
->contents()) {
10278 if (!propdef
->is
<ClassMethod
>()) {
10281 auto* classMethod
= &propdef
->as
<ClassMethod
>();
10283 // Skip over anything which isn't a private instance accessor.
10284 if (!IsPrivateInstanceAccessor(classMethod
)) {
10288 if (!ce
.prepareForMemberInitializer()) {
10289 // [stack] HOMEOBJ HERITAGE? ARRAY
10291 // [stack] CTOR HOMEOBJ ARRAY
10295 // Synthesize a name for the lexical variable that will store the
10296 // private method body.
10297 TaggedParserAtomIndex name
= classMethod
->name().as
<NameNode
>().atom();
10298 AccessorType accessorType
= classMethod
->accessorType();
10299 StringBuffer
storedMethodName(fc
);
10300 if (!storedMethodName
.append(parserAtoms(), name
)) {
10303 if (!storedMethodName
.append(
10304 accessorType
== AccessorType::Getter
? ".getter" : ".setter")) {
10307 auto storedMethodAtom
=
10308 storedMethodName
.finishParserAtom(parserAtoms(), fc
);
10310 // Emit the private method body and store it as a lexical var.
10311 if (!emitFunction(&classMethod
->method())) {
10312 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
10314 // [stack] CTOR HOMEOBJ ARRAY METHOD
10317 // The private method body needs to access the home object,
10318 // and the CE knows where that is on the stack.
10319 if (classMethod
->method().funbox()->needsHomeObject()) {
10320 if (!ce
.emitMemberInitializerHomeObject(false)) {
10321 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
10323 // [stack] CTOR HOMEOBJ ARRAY METHOD
10327 if (!emitLexicalInitialization(storedMethodAtom
)) {
10328 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
10330 // [stack] CTOR HOMEOBJ ARRAY METHOD
10333 if (!emit1(JSOp::Pop
)) {
10334 // [stack] HOMEOBJ HERITAGE? ARRAY
10336 // [stack] CTOR HOMEOBJ ARRAY
10340 if (!emitPrivateMethodInitializer(classMethod
, storedMethodAtom
)) {
10341 // [stack] HOMEOBJ HERITAGE? ARRAY
10343 // [stack] CTOR HOMEOBJ ARRAY
10347 // Store the emitted initializer function into the .initializers array.
10348 if (!ce
.emitStoreMemberInitializer()) {
10349 // [stack] HOMEOBJ HERITAGE? ARRAY
10351 // [stack] CTOR HOMEOBJ ARRAY
10359 bool BytecodeEmitter::emitPrivateMethodInitializer(
10360 ClassMethod
* classMethod
, TaggedParserAtomIndex storedMethodAtom
) {
10361 MOZ_ASSERT(IsPrivateInstanceAccessor(classMethod
));
10363 auto* name
= &classMethod
->name().as
<NameNode
>();
10365 // Emit the synthesized initializer function.
10366 FunctionNode
* funNode
= classMethod
->initializerIfPrivate();
10367 MOZ_ASSERT(funNode
);
10368 FunctionBox
* funbox
= funNode
->funbox();
10369 FunctionEmitter
fe(this, funbox
, funNode
->syntaxKind(),
10370 FunctionEmitter::IsHoisted::No
);
10371 if (!fe
.prepareForNonLazy()) {
10376 BytecodeEmitter
bce2(this, funbox
);
10377 if (!bce2
.init(funNode
->pn_pos
)) {
10380 ParamsBodyNode
* paramsBody
= funNode
->body();
10381 FunctionScriptEmitter
fse(&bce2
, funbox
, Nothing(), Nothing());
10382 if (!fse
.prepareForParameters()) {
10386 if (!bce2
.emitFunctionFormalParameters(paramsBody
)) {
10390 if (!fse
.prepareForBody()) {
10395 if (!bce2
.emit1(JSOp::FunctionThis
)) {
10399 if (!bce2
.emitGetPrivateName(name
)) {
10400 // [stack] THIS NAME
10403 if (!bce2
.emitGetName(storedMethodAtom
)) {
10404 // [stack] THIS NAME METHOD
10408 switch (name
->privateNameKind()) {
10409 case PrivateNameKind::Setter
:
10410 if (!bce2
.emit1(JSOp::InitHiddenElemSetter
)) {
10414 if (!bce2
.emitGetPrivateName(name
)) {
10415 // [stack] THIS NAME
10418 if (!bce2
.emitAtomOp(
10419 JSOp::GetIntrinsic
,
10420 TaggedParserAtomIndex::WellKnown::NoPrivateGetter())) {
10421 // [stack] THIS NAME FUN
10424 if (!bce2
.emit1(JSOp::InitHiddenElemGetter
)) {
10429 case PrivateNameKind::Getter
:
10430 case PrivateNameKind::GetterSetter
:
10431 if (classMethod
->accessorType() == AccessorType::Getter
) {
10432 if (!bce2
.emit1(JSOp::InitHiddenElemGetter
)) {
10437 if (!bce2
.emit1(JSOp::InitHiddenElemSetter
)) {
10444 MOZ_CRASH("Invalid op");
10447 // Pop remaining THIS.
10448 if (!bce2
.emit1(JSOp::Pop
)) {
10453 if (!fse
.emitEndBody()) {
10457 if (!fse
.intoStencil()) {
10461 if (!fe
.emitNonLazyEnd()) {
10462 // [stack] HOMEOBJ HERITAGE? ARRAY FUN
10464 // [stack] CTOR HOMEOBJ ARRAY FUN
10471 const MemberInitializers
& BytecodeEmitter::findMemberInitializersForCall() {
10472 for (BytecodeEmitter
* current
= this; current
; current
= current
->parent
) {
10473 if (current
->sc
->isFunctionBox()) {
10474 FunctionBox
* funbox
= current
->sc
->asFunctionBox();
10476 if (funbox
->isArrow()) {
10480 // If we found a non-arrow / non-constructor we were never allowed to
10481 // expect fields in the first place.
10482 MOZ_RELEASE_ASSERT(funbox
->isClassConstructor());
10484 return funbox
->useMemberInitializers() ? funbox
->memberInitializers()
10485 : MemberInitializers::Empty();
10489 MOZ_RELEASE_ASSERT(compilationState
.scopeContext
.memberInitializers
);
10490 return *compilationState
.scopeContext
.memberInitializers
;
10493 bool BytecodeEmitter::emitInitializeInstanceMembers(
10494 bool isDerivedClassConstructor
) {
10495 const MemberInitializers
& memberInitializers
=
10496 findMemberInitializersForCall();
10497 MOZ_ASSERT(memberInitializers
.valid
);
10499 if (memberInitializers
.hasPrivateBrand
) {
10500 // This is guaranteed to run after super(), so we don't need TDZ checks.
10501 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
10505 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_privateBrand_())) {
10506 // [stack] THIS BRAND
10509 if (isDerivedClassConstructor
) {
10510 if (!emitCheckPrivateField(ThrowCondition::ThrowHas
,
10511 ThrowMsgKind::PrivateBrandDoubleInit
)) {
10512 // [stack] THIS BRAND BOOL
10515 if (!emit1(JSOp::Pop
)) {
10516 // [stack] THIS BRAND
10520 if (!emit1(JSOp::Null
)) {
10521 // [stack] THIS BRAND NULL
10524 if (!emit1(JSOp::InitHiddenElem
)) {
10528 if (!emit1(JSOp::Pop
)) {
10534 size_t numInitializers
= memberInitializers
.numMemberInitializers
;
10535 if (numInitializers
> 0) {
10536 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) {
10541 for (size_t index
= 0; index
< numInitializers
; index
++) {
10542 if (index
< numInitializers
- 1) {
10543 // We Dup to keep the array around (it is consumed in the bytecode
10544 // below) for next iterations of this loop, except for the last
10545 // iteration, which avoids an extra Pop at the end of the loop.
10546 if (!emit1(JSOp::Dup
)) {
10547 // [stack] ARRAY ARRAY
10552 if (!emitNumberOp(index
)) {
10553 // [stack] ARRAY? ARRAY INDEX
10557 if (!emit1(JSOp::GetElem
)) {
10558 // [stack] ARRAY? FUNC
10562 // This is guaranteed to run after super(), so we don't need TDZ checks.
10563 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
10564 // [stack] ARRAY? FUNC THIS
10568 // Callee is always internal function.
10569 if (!emitCall(JSOp::CallIgnoresRv
, 0)) {
10570 // [stack] ARRAY? RVAL
10574 if (!emit1(JSOp::Pop
)) {
10579 #ifdef ENABLE_DECORATORS
10580 // Decorators Proposal
10581 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-initializeinstanceelements
10582 // 4. For each element e of elements, do
10583 // 4.a. If elementRecord.[[Kind]] is field or accessor, then
10584 // 4.a.i. Perform ? InitializeFieldOrAccessor(O, elementRecord).
10587 // TODO: (See Bug 1817993) At the moment, we're applying the initialization
10588 // logic in two steps. The pre-decorator initialization code runs, stores
10589 // the initial value, and then we retrieve it here and apply the
10590 // initializers added by decorators. We should unify these two steps.
10591 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) {
10596 if (!emit1(JSOp::Dup
)) {
10597 // [stack] ARRAY ARRAY
10601 if (!emitAtomOp(JSOp::GetProp
,
10602 TaggedParserAtomIndex::WellKnown::length())) {
10603 // [stack] ARRAY LENGTH
10607 if (!emitNumberOp(static_cast<double>(numInitializers
))) {
10608 // [stack] ARRAY LENGTH INDEX
10612 InternalWhileEmitter
wh(this);
10613 // At this point, we have no context to determine offsets in the
10614 // code for this while statement. Ideally, it would correspond to
10615 // the field we're initializing.
10616 if (!wh
.emitCond()) {
10617 // [stack] ARRAY LENGTH INDEX
10621 if (!emit1(JSOp::Dup
)) {
10622 // [stack] ARRAY LENGTH INDEX INDEX
10626 if (!emitDupAt(2)) {
10627 // [stack] ARRAY LENGTH INDEX INDEX LENGTH
10631 if (!emit1(JSOp::Lt
)) {
10632 // [stack] ARRAY LENGTH INDEX BOOL
10636 if (!wh
.emitBody()) {
10637 // [stack] ARRAY LENGTH INDEX
10641 if (!emitDupAt(2)) {
10642 // [stack] ARRAY LENGTH INDEX ARRAY
10646 if (!emitDupAt(1)) {
10647 // [stack] ARRAY LENGTH INDEX ARRAY INDEX
10651 // Retrieve initializers for this field
10652 if (!emit1(JSOp::GetElem
)) {
10653 // [stack] ARRAY LENGTH INDEX INITIALIZERS
10657 // This is guaranteed to run after super(), so we don't need TDZ checks.
10658 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
10659 // [stack] ARRAY LENGTH INDEX INITIALIZERS THIS
10663 if (!emit1(JSOp::Swap
)) {
10664 // [stack] ARRAY LENGTH INDEX THIS INITIALIZERS
10668 DecoratorEmitter
de(this);
10669 if (!de
.emitInitializeFieldOrAccessor()) {
10670 // [stack] ARRAY LENGTH INDEX
10674 if (!emit1(JSOp::Inc
)) {
10675 // [stack] ARRAY LENGTH INDEX
10679 if (!wh
.emitEnd()) {
10680 // [stack] ARRAY LENGTH INDEX
10684 if (!emitPopN(3)) {
10688 // 5. Return unused.
10694 bool BytecodeEmitter::emitInitializeStaticFields(ListNode
* classMembers
) {
10695 auto isStaticField
= [](ParseNode
* propdef
) {
10696 return HasInitializer(propdef
, true);
10699 std::count_if(classMembers
->contents().begin(),
10700 classMembers
->contents().end(), isStaticField
);
10702 if (numFields
== 0) {
10707 TaggedParserAtomIndex::WellKnown::dot_staticInitializers_())) {
10708 // [stack] CTOR ARRAY
10712 for (size_t fieldIndex
= 0; fieldIndex
< numFields
; fieldIndex
++) {
10713 bool hasNext
= fieldIndex
< numFields
- 1;
10715 // We Dup to keep the array around (it is consumed in the bytecode below)
10716 // for next iterations of this loop, except for the last iteration, which
10717 // avoids an extra Pop at the end of the loop.
10718 if (!emit1(JSOp::Dup
)) {
10719 // [stack] CTOR ARRAY ARRAY
10724 if (!emitNumberOp(fieldIndex
)) {
10725 // [stack] CTOR ARRAY? ARRAY INDEX
10729 if (!emit1(JSOp::GetElem
)) {
10730 // [stack] CTOR ARRAY? FUNC
10734 if (!emitDupAt(1 + hasNext
)) {
10735 // [stack] CTOR ARRAY? FUNC CTOR
10739 // Callee is always internal function.
10740 if (!emitCall(JSOp::CallIgnoresRv
, 0)) {
10741 // [stack] CTOR ARRAY? RVAL
10745 if (!emit1(JSOp::Pop
)) {
10746 // [stack] CTOR ARRAY?
10751 #ifdef ENABLE_DECORATORS
10752 // Decorators Proposal
10753 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-initializeinstanceelements
10754 // 4. For each element e of elements, do
10755 // 4.a. If elementRecord.[[Kind]] is field or accessor, then
10756 // 4.a.i. Perform ? InitializeFieldOrAccessor(O, elementRecord).
10759 // TODO: (See Bug 1817993) At the moment, we're applying the initialization
10760 // logic in two steps. The pre-decorator initialization code runs, stores
10761 // the initial value, and then we retrieve it here and apply the
10762 // initializers added by decorators. We should unify these two steps.
10764 TaggedParserAtomIndex::WellKnown::dot_staticInitializers_())) {
10765 // [stack] CTOR ARRAY
10769 if (!emit1(JSOp::Dup
)) {
10770 // [stack] CTOR ARRAY ARRAY
10774 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::length())) {
10775 // [stack] CTOR ARRAY LENGTH
10779 if (!emitNumberOp(static_cast<double>(numFields
))) {
10780 // [stack] CTOR ARRAY LENGTH INDEX
10784 InternalWhileEmitter
wh(this);
10785 // At this point, we have no context to determine offsets in the
10786 // code for this while statement. Ideally, it would correspond to
10787 // the field we're initializing.
10788 if (!wh
.emitCond()) {
10789 // [stack] CTOR ARRAY LENGTH INDEX
10793 if (!emit1(JSOp::Dup
)) {
10794 // [stack] CTOR ARRAY LENGTH INDEX INDEX
10798 if (!emitDupAt(2)) {
10799 // [stack] CTOR ARRAY LENGTH INDEX INDEX LENGTH
10803 if (!emit1(JSOp::Lt
)) {
10804 // [stack] CTOR ARRAY LENGTH INDEX BOOL
10808 if (!wh
.emitBody()) {
10809 // [stack] CTOR ARRAY LENGTH INDEX
10813 if (!emitDupAt(2)) {
10814 // [stack] CTOR ARRAY LENGTH INDEX ARRAY
10818 if (!emitDupAt(1)) {
10819 // [stack] CTOR ARRAY LENGTH INDEX ARRAY INDEX
10823 // Retrieve initializers for this field
10824 if (!emit1(JSOp::GetElem
)) {
10825 // [stack] CTOR ARRAY LENGTH INDEX INITIALIZERS
10829 if (!emitDupAt(4)) {
10830 // [stack] CTOR ARRAY LENGTH INDEX INITIALIZERS CTOR
10834 if (!emit1(JSOp::Swap
)) {
10835 // [stack] CTOR ARRAY LENGTH INDEX CTOR INITIALIZERS
10839 DecoratorEmitter
de(this);
10840 if (!de
.emitInitializeFieldOrAccessor()) {
10841 // [stack] CTOR ARRAY LENGTH INDEX
10845 if (!emit1(JSOp::Inc
)) {
10846 // [stack] CTOR ARRAY LENGTH INDEX
10850 if (!wh
.emitEnd()) {
10851 // [stack] CTOR ARRAY LENGTH INDEX
10855 if (!emitPopN(3)) {
10859 // 5. Return unused.
10862 // Overwrite |.staticInitializers| and |.staticFieldKeys| with undefined to
10863 // avoid keeping the arrays alive indefinitely.
10864 auto clearStaticFieldSlot
= [&](TaggedParserAtomIndex name
) {
10865 NameOpEmitter
noe(this, name
, NameOpEmitter::Kind::SimpleAssignment
);
10866 if (!noe
.prepareForRhs()) {
10867 // [stack] ENV? VAL?
10871 if (!emit1(JSOp::Undefined
)) {
10872 // [stack] ENV? VAL? UNDEFINED
10876 if (!noe
.emitAssignment()) {
10881 if (!emit1(JSOp::Pop
)) {
10889 if (!clearStaticFieldSlot(
10890 TaggedParserAtomIndex::WellKnown::dot_staticInitializers_())) {
10894 auto isStaticFieldWithComputedName
= [](ParseNode
* propdef
) {
10895 return propdef
->is
<ClassField
>() && propdef
->as
<ClassField
>().isStatic() &&
10896 propdef
->as
<ClassField
>().name().getKind() ==
10897 ParseNodeKind::ComputedName
;
10900 if (std::any_of(classMembers
->contents().begin(),
10901 classMembers
->contents().end(),
10902 isStaticFieldWithComputedName
)) {
10903 if (!clearStaticFieldSlot(
10904 TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_())) {
10912 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
10913 // the comment on emitSwitch.
10914 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitObject(ListNode
* objNode
) {
10915 // Note: this method uses the ObjLiteralWriter and emits ObjLiteralStencil
10916 // objects into the GCThingList, which will evaluate them into real GC objects
10917 // or shapes during JSScript::fullyInitFromEmitter. Eventually we want
10918 // JSOp::Object to be a real opcode, but for now, performance constraints
10919 // limit us to evaluating object literals at the end of parse, when we're
10920 // allowed to allocate GC things.
10922 // There are four cases here, in descending order of preference:
10924 // 1. The list of property names is "normal" and constant (no computed
10925 // values, no integer indices), the values are all simple constants
10926 // (numbers, booleans, strings), *and* this occurs in a run-once
10927 // (singleton) context. In this case, we can emit ObjLiteral
10928 // instructions to build an object with values, and the object will be
10929 // attached to a JSOp::Object opcode, whose semantics are for the backend
10930 // to simply steal the object from the script.
10932 // 2. The list of property names is "normal" and constant as above, *and* this
10933 // occurs in a run-once (singleton) context, but some values are complex
10934 // (computed expressions, sub-objects, functions, etc.). In this case, we
10935 // can still use JSOp::Object (because singleton context), but the object
10936 // has |undefined| property values and InitProp ops are emitted to set the
10939 // 3. The list of property names is "normal" and constant as above, but this
10940 // occurs in a non-run-once (non-singleton) context. In this case, we can
10941 // use the ObjLiteral functionality to describe an *empty* object (all
10942 // values left undefined) with the right fields, which will become a
10943 // JSOp::NewObject opcode using the object's shape to speed up the creation
10944 // of the object each time it executes. The emitted bytecode still needs
10945 // InitProp ops to set the values in this case.
10947 // 4. Any other case. As a fallback, we use NewInit to create a new, empty
10948 // object (i.e., `{}`) and then emit bytecode to initialize its properties
10951 bool useObjLiteral
= false;
10952 bool useObjLiteralValues
= false;
10953 isPropertyListObjLiteralCompatible(objNode
, &useObjLiteralValues
,
10958 ObjectEmitter
oe(this);
10959 if (useObjLiteral
) {
10960 bool singleton
= checkSingletonContext() &&
10961 !objNode
->hasNonConstInitializer() && objNode
->head();
10968 useObjLiteralValues
= false;
10969 op
= JSOp::NewObject
;
10972 // Use an ObjLiteral op. This will record ObjLiteral insns in the
10973 // objLiteralWriter's buffer and add a fixup to the list of ObjLiteral
10974 // fixups so that at GC-publish time at the end of parse, the full object
10975 // (case 1 or 2) or shape (case 3) can be allocated and the bytecode can be
10976 // patched to refer to it.
10977 if (!emitPropertyListObjLiteral(objNode
, op
, useObjLiteralValues
)) {
10981 // Put the ObjectEmitter in the right state. This tells it that there will
10982 // already be an object on the stack as a result of the (eventual)
10983 // NewObject or Object op, and prepares it to emit values if needed.
10984 if (!oe
.emitObjectWithTemplateOnStack()) {
10988 if (!useObjLiteralValues
) {
10989 // Case 2 or 3 above: we still need to emit bytecode to fill in the
10990 // object's property values.
10991 if (!emitPropertyList(objNode
, oe
, ObjectLiteral
)) {
10997 // Case 4 above: no ObjLiteral use, just bytecode to build the object from
10999 if (!oe
.emitObject(objNode
->count())) {
11003 if (!emitPropertyList(objNode
, oe
, ObjectLiteral
)) {
11009 if (!oe
.emitEnd()) {
11017 bool BytecodeEmitter::emitArrayLiteral(ListNode
* array
) {
11018 // Emit JSOp::Object if the array consists entirely of primitive values and we
11019 // are in a singleton context.
11020 if (checkSingletonContext() && !array
->hasNonConstInitializer() &&
11021 !array
->empty() && isArrayObjLiteralCompatible(array
)) {
11022 return emitObjLiteralArray(array
);
11025 return emitArray(array
);
11028 bool BytecodeEmitter::emitArray(ListNode
* array
) {
11030 * Emit code for [a, b, c] that is equivalent to constructing a new
11031 * array and in source order evaluating each element value and adding
11032 * it to the array, without invoking latent setters. We use the
11033 * JSOp::NewInit and JSOp::InitElemArray bytecodes to ignore setters and
11034 * to avoid dup'ing and popping the array as each element is added, as
11035 * JSOp::SetElem/JSOp::SetProp would do.
11038 uint32_t nspread
= 0;
11039 for (ParseNode
* elem
: array
->contents()) {
11040 if (elem
->isKind(ParseNodeKind::Spread
)) {
11045 // Array literal's length is limited to NELEMENTS_LIMIT in parser.
11046 static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT
<= INT32_MAX
,
11047 "array literals' maximum length must not exceed limits "
11048 "required by BaselineCompiler::emit_NewArray, "
11049 "BaselineCompiler::emit_InitElemArray, "
11050 "and DoSetElemFallback's handling of JSOp::InitElemArray");
11052 uint32_t count
= array
->count();
11053 MOZ_ASSERT(count
>= nspread
);
11054 MOZ_ASSERT(count
<= NativeObject::MAX_DENSE_ELEMENTS_COUNT
,
11055 "the parser must throw an error if the array exceeds maximum "
11058 // For arrays with spread, this is a very pessimistic allocation, the
11059 // minimum possible final size.
11060 if (!emitUint32Operand(JSOp::NewArray
, count
- nspread
)) {
11065 uint32_t index
= 0;
11066 bool afterSpread
= false;
11067 for (ParseNode
* elem
: array
->contents()) {
11068 if (elem
->isKind(ParseNodeKind::Spread
)) {
11069 if (!afterSpread
) {
11070 afterSpread
= true;
11071 if (!emitNumberOp(index
)) {
11072 // [stack] ARRAY INDEX
11077 ParseNode
* expr
= elem
->as
<UnaryNode
>().kid();
11078 SelfHostedIter selfHostedIter
= getSelfHostedIterFor(expr
);
11080 if (!updateSourceCoordNotes(elem
->pn_pos
.begin
)) {
11083 if (!emitIterable(expr
, selfHostedIter
)) {
11084 // [stack] ARRAY INDEX ITERABLE
11087 if (!emitIterator(selfHostedIter
)) {
11088 // [stack] ARRAY INDEX NEXT ITER
11091 if (!emit2(JSOp::Pick
, 3)) {
11092 // [stack] INDEX NEXT ITER ARRAY
11095 if (!emit2(JSOp::Pick
, 3)) {
11096 // [stack] NEXT ITER ARRAY INDEX
11099 if (!emitSpread(selfHostedIter
)) {
11100 // [stack] ARRAY INDEX
11104 if (!updateSourceCoordNotesIfNonLiteral(elem
)) {
11107 if (elem
->isKind(ParseNodeKind::Elision
)) {
11108 if (!emit1(JSOp::Hole
)) {
11112 if (!emitTree(elem
, ValueUsage::WantValue
)) {
11113 // [stack] ARRAY INDEX? VALUE
11119 if (!emit1(JSOp::InitElemInc
)) {
11120 // [stack] ARRAY (INDEX+1)
11124 if (!emitUint32Operand(JSOp::InitElemArray
, index
)) {
11133 MOZ_ASSERT(index
== count
);
11135 if (!emit1(JSOp::Pop
)) {
11143 bool BytecodeEmitter::emitSpreadIntoArray(UnaryNode
* elem
) {
11144 MOZ_ASSERT(elem
->isKind(ParseNodeKind::Spread
));
11146 if (!updateSourceCoordNotes(elem
->pn_pos
.begin
)) {
11151 SelfHostedIter selfHostedIter
= getSelfHostedIterFor(elem
->kid());
11152 MOZ_ASSERT(selfHostedIter
== SelfHostedIter::Deny
||
11153 selfHostedIter
== SelfHostedIter::AllowContent
);
11155 if (!emitIterator(selfHostedIter
)) {
11156 // [stack] NEXT ITER
11160 if (!emitUint32Operand(JSOp::NewArray
, 0)) {
11161 // [stack] NEXT ITER ARRAY
11165 if (!emitNumberOp(0)) {
11166 // [stack] NEXT ITER ARRAY INDEX
11170 if (!emitSpread(selfHostedIter
)) {
11171 // [stack] ARRAY INDEX
11175 if (!emit1(JSOp::Pop
)) {
11182 #ifdef ENABLE_RECORD_TUPLE
11183 bool BytecodeEmitter::emitRecordLiteral(ListNode
* record
) {
11184 if (!emitUint32Operand(JSOp::InitRecord
, record
->count())) {
11189 for (ParseNode
* propdef
: record
->contents()) {
11190 if (propdef
->isKind(ParseNodeKind::Spread
)) {
11191 if (!emitTree(propdef
->as
<UnaryNode
>().kid())) {
11192 // [stack] RECORD SPREADEE
11195 if (!emit1(JSOp::AddRecordSpread
)) {
11200 BinaryNode
* prop
= &propdef
->as
<BinaryNode
>();
11202 ParseNode
* key
= prop
->left();
11203 ParseNode
* value
= prop
->right();
11205 switch (key
->getKind()) {
11206 case ParseNodeKind::ObjectPropertyName
:
11207 if (!emitStringOp(JSOp::String
, key
->as
<NameNode
>().atom())) {
11211 case ParseNodeKind::ComputedName
:
11212 if (!emitTree(key
->as
<UnaryNode
>().kid())) {
11217 MOZ_ASSERT(key
->isKind(ParseNodeKind::StringExpr
) ||
11218 key
->isKind(ParseNodeKind::NumberExpr
) ||
11219 key
->isKind(ParseNodeKind::BigIntExpr
));
11220 if (!emitTree(key
)) {
11225 // [stack] RECORD KEY
11227 if (!emitTree(value
)) {
11228 // [stack] RECORD KEY VALUE
11232 if (!emit1(JSOp::AddRecordProperty
)) {
11239 if (!emit1(JSOp::FinishRecord
)) {
11247 bool BytecodeEmitter::emitTupleLiteral(ListNode
* tuple
) {
11248 if (!emitUint32Operand(JSOp::InitTuple
, tuple
->count())) {
11253 for (ParseNode
* elt
: tuple
->contents()) {
11254 if (elt
->isKind(ParseNodeKind::Spread
)) {
11255 ParseNode
* expr
= elt
->as
<UnaryNode
>().kid();
11256 auto selfHostedIter
= getSelfHostedIterFor(expr
);
11258 if (!emitIterable(expr
, selfHostedIter
)) {
11259 // [stack] TUPLE ITERABLE
11262 if (!emitIterator(selfHostedIter
)) {
11263 // [stack] TUPLE NEXT ITER
11266 if (!emit2(JSOp::Pick
, 2)) {
11267 // [stack] NEXT ITER TUPLE
11270 if (!emitSpread(selfHostedIter
, /* spreadeeStackItems = */ 1,
11271 JSOp::AddTupleElement
)) {
11276 // Update location to throw errors about non-primitive elements
11277 // in the correct position.
11278 if (!updateSourceCoordNotesIfNonLiteral(elt
)) {
11282 if (!emitTree(elt
)) {
11283 // [stack] TUPLE VALUE
11287 if (!emit1(JSOp::AddTupleElement
)) {
11294 if (!emit1(JSOp::FinishTuple
)) {
11303 static inline JSOp
UnaryOpParseNodeKindToJSOp(ParseNodeKind pnk
) {
11305 case ParseNodeKind::ThrowStmt
:
11306 return JSOp::Throw
;
11307 case ParseNodeKind::VoidExpr
:
11309 case ParseNodeKind::NotExpr
:
11311 case ParseNodeKind::BitNotExpr
:
11312 return JSOp::BitNot
;
11313 case ParseNodeKind::PosExpr
:
11315 case ParseNodeKind::NegExpr
:
11318 MOZ_CRASH("unexpected unary op");
11322 bool BytecodeEmitter::emitUnary(UnaryNode
* unaryNode
) {
11323 if (!updateSourceCoordNotes(unaryNode
->pn_pos
.begin
)) {
11327 JSOp op
= UnaryOpParseNodeKindToJSOp(unaryNode
->getKind());
11328 ValueUsage valueUsage
=
11329 op
== JSOp::Void
? ValueUsage::IgnoreValue
: ValueUsage::WantValue
;
11330 if (!emitTree(unaryNode
->kid(), valueUsage
)) {
11336 bool BytecodeEmitter::emitTypeof(UnaryNode
* typeofNode
, JSOp op
) {
11337 MOZ_ASSERT(op
== JSOp::Typeof
|| op
== JSOp::TypeofExpr
);
11339 if (!updateSourceCoordNotes(typeofNode
->pn_pos
.begin
)) {
11343 if (!emitTree(typeofNode
->kid())) {
11350 bool BytecodeEmitter::emitFunctionFormalParameters(ParamsBodyNode
* paramsBody
) {
11351 FunctionBox
* funbox
= sc
->asFunctionBox();
11353 bool hasRest
= funbox
->hasRest();
11355 FunctionParamsEmitter
fpe(this, funbox
);
11356 for (ParseNode
* arg
: paramsBody
->parameters()) {
11357 ParseNode
* bindingElement
= arg
;
11358 ParseNode
* initializer
= nullptr;
11359 if (arg
->isKind(ParseNodeKind::AssignExpr
)) {
11360 bindingElement
= arg
->as
<BinaryNode
>().left();
11361 initializer
= arg
->as
<BinaryNode
>().right();
11363 bool hasInitializer
= !!initializer
;
11365 hasRest
&& arg
->pn_next
== *std::end(paramsBody
->parameters());
11366 bool isDestructuring
= !bindingElement
->isKind(ParseNodeKind::Name
);
11368 // Left-hand sides are either simple names or destructuring patterns.
11369 MOZ_ASSERT(bindingElement
->isKind(ParseNodeKind::Name
) ||
11370 bindingElement
->isKind(ParseNodeKind::ArrayExpr
) ||
11371 bindingElement
->isKind(ParseNodeKind::ObjectExpr
));
11373 auto emitDefaultInitializer
= [this, &initializer
, &bindingElement
]() {
11376 if (!this->emitInitializer(initializer
, bindingElement
)) {
11383 auto emitDestructuring
= [this, &bindingElement
]() {
11386 if (!this->emitDestructuringOps(&bindingElement
->as
<ListNode
>(),
11387 DestructuringFlavor::Declaration
)) {
11396 if (isDestructuring
) {
11397 if (!fpe
.prepareForDestructuringRest()) {
11401 if (!emitDestructuring()) {
11405 if (!fpe
.emitDestructuringRestEnd()) {
11410 auto paramName
= bindingElement
->as
<NameNode
>().name();
11411 if (!fpe
.emitRest(paramName
)) {
11420 if (isDestructuring
) {
11421 if (hasInitializer
) {
11422 if (!fpe
.prepareForDestructuringDefaultInitializer()) {
11426 if (!emitDefaultInitializer()) {
11430 if (!fpe
.prepareForDestructuringDefault()) {
11434 if (!emitDestructuring()) {
11438 if (!fpe
.emitDestructuringDefaultEnd()) {
11443 if (!fpe
.prepareForDestructuring()) {
11447 if (!emitDestructuring()) {
11451 if (!fpe
.emitDestructuringEnd()) {
11460 if (hasInitializer
) {
11461 if (!fpe
.prepareForDefault()) {
11465 if (!emitDefaultInitializer()) {
11469 auto paramName
= bindingElement
->as
<NameNode
>().name();
11470 if (!fpe
.emitDefaultEnd(paramName
)) {
11478 auto paramName
= bindingElement
->as
<NameNode
>().name();
11479 if (!fpe
.emitSimple(paramName
)) {
11488 bool BytecodeEmitter::emitInitializeFunctionSpecialNames() {
11489 FunctionBox
* funbox
= sc
->asFunctionBox();
11493 auto emitInitializeFunctionSpecialName
=
11494 [](BytecodeEmitter
* bce
, TaggedParserAtomIndex name
, JSOp op
) {
11495 // A special name must be slotful, either on the frame or on the
11496 // call environment.
11497 MOZ_ASSERT(bce
->lookupName(name
).hasKnownSlot());
11499 NameOpEmitter
noe(bce
, name
, NameOpEmitter::Kind::Initialize
);
11500 if (!noe
.prepareForRhs()) {
11504 if (!bce
->emit1(op
)) {
11505 // [stack] THIS/ARGUMENTS/NEW.TARGET
11508 if (!noe
.emitAssignment()) {
11509 // [stack] THIS/ARGUMENTS/NEW.TARGET
11512 if (!bce
->emit1(JSOp::Pop
)) {
11520 // Do nothing if the function doesn't have an arguments binding.
11521 if (funbox
->needsArgsObj()) {
11522 // Self-hosted code should use the more efficient ArgumentsLength and
11523 // GetArgument intrinsics instead of `arguments`.
11524 MOZ_ASSERT(emitterMode
!= BytecodeEmitter::SelfHosting
);
11525 if (!emitInitializeFunctionSpecialName(
11526 this, TaggedParserAtomIndex::WellKnown::arguments(),
11527 JSOp::Arguments
)) {
11533 // Do nothing if the function doesn't have a this-binding (this
11534 // happens for instance if it doesn't use this/eval or if it's an
11535 // arrow function).
11536 if (funbox
->functionHasThisBinding()) {
11537 if (!emitInitializeFunctionSpecialName(
11538 this, TaggedParserAtomIndex::WellKnown::dot_this_(),
11539 JSOp::FunctionThis
)) {
11544 // Do nothing if the function doesn't have a new.target-binding (this happens
11545 // for instance if it doesn't use new.target/eval or if it's an arrow
11547 if (funbox
->functionHasNewTargetBinding()) {
11548 if (!emitInitializeFunctionSpecialName(
11549 this, TaggedParserAtomIndex::WellKnown::dot_newTarget_(),
11550 JSOp::NewTarget
)) {
11555 // Do nothing if the function doesn't implicitly return a promise result.
11556 if (funbox
->needsPromiseResult()) {
11557 if (!emitInitializeFunctionSpecialName(
11558 this, TaggedParserAtomIndex::WellKnown::dot_generator_(),
11559 JSOp::Generator
)) {
11567 bool BytecodeEmitter::emitLexicalInitialization(NameNode
* name
) {
11568 return emitLexicalInitialization(name
->name());
11571 bool BytecodeEmitter::emitLexicalInitialization(TaggedParserAtomIndex name
) {
11572 NameOpEmitter
noe(this, name
, NameOpEmitter::Kind::Initialize
);
11573 if (!noe
.prepareForRhs()) {
11577 // The caller has pushed the RHS to the top of the stack. Assert that the
11578 // binding can be initialized without a binding object on the stack, and that
11579 // no JSOp::BindName or JSOp::BindGName ops were emitted.
11580 MOZ_ASSERT(noe
.loc().isLexical() || noe
.loc().isSynthetic() ||
11581 noe
.loc().isPrivateMethod());
11582 MOZ_ASSERT(!noe
.emittedBindOp());
11584 if (!noe
.emitAssignment()) {
11591 static MOZ_ALWAYS_INLINE ParseNode
* FindConstructor(ListNode
* classMethods
) {
11592 for (ParseNode
* classElement
: classMethods
->contents()) {
11593 ParseNode
* unwrappedElement
= classElement
;
11594 if (unwrappedElement
->is
<LexicalScopeNode
>()) {
11595 unwrappedElement
= unwrappedElement
->as
<LexicalScopeNode
>().scopeBody();
11597 if (unwrappedElement
->is
<ClassMethod
>()) {
11598 ClassMethod
& method
= unwrappedElement
->as
<ClassMethod
>();
11599 ParseNode
& methodName
= method
.name();
11600 if (!method
.isStatic() &&
11601 (methodName
.isKind(ParseNodeKind::ObjectPropertyName
) ||
11602 methodName
.isKind(ParseNodeKind::StringExpr
)) &&
11603 methodName
.as
<NameNode
>().atom() ==
11604 TaggedParserAtomIndex::WellKnown::constructor()) {
11605 return classElement
;
11612 bool BytecodeEmitter::emitNewPrivateName(TaggedParserAtomIndex bindingName
,
11613 TaggedParserAtomIndex symbolName
) {
11614 if (!emitAtomOp(JSOp::NewPrivateName
, symbolName
)) {
11615 // [stack] HERITAGE PRIVATENAME
11619 // Add a binding for #name => privatename
11620 if (!emitLexicalInitialization(bindingName
)) {
11621 // [stack] HERITAGE PRIVATENAME
11625 // Pop Private name off the stack.
11626 if (!emit1(JSOp::Pop
)) {
11627 // [stack] HERITAGE
11634 bool BytecodeEmitter::emitNewPrivateNames(
11635 TaggedParserAtomIndex privateBrandName
, ListNode
* classMembers
) {
11636 bool hasPrivateBrand
= false;
11638 for (ParseNode
* classElement
: classMembers
->contents()) {
11639 ParseNode
* elementName
;
11640 if (classElement
->is
<ClassMethod
>()) {
11641 elementName
= &classElement
->as
<ClassMethod
>().name();
11642 } else if (classElement
->is
<ClassField
>()) {
11643 elementName
= &classElement
->as
<ClassField
>().name();
11648 if (!elementName
->isKind(ParseNodeKind::PrivateName
)) {
11652 // Non-static private methods' private names are optimized away.
11653 bool isOptimized
= false;
11654 if (classElement
->is
<ClassMethod
>() &&
11655 !classElement
->as
<ClassMethod
>().isStatic()) {
11656 hasPrivateBrand
= true;
11657 if (classElement
->as
<ClassMethod
>().accessorType() ==
11658 AccessorType::None
) {
11659 isOptimized
= true;
11663 if (!isOptimized
) {
11664 auto privateName
= elementName
->as
<NameNode
>().name();
11665 if (!emitNewPrivateName(privateName
, privateName
)) {
11671 if (hasPrivateBrand
) {
11672 // We don't make a private name for every optimized method, but we need one
11673 // private name per class, the `.privateBrand`.
11674 if (!emitNewPrivateName(
11675 TaggedParserAtomIndex::WellKnown::dot_privateBrand_(),
11676 privateBrandName
)) {
11683 // This follows ES6 14.5.14 (ClassDefinitionEvaluation) and ES6 14.5.15
11684 // (BindingClassDeclarationEvaluation).
11685 bool BytecodeEmitter::emitClass(
11686 ClassNode
* classNode
,
11687 ClassNameKind nameKind
/* = ClassNameKind::BindingName */,
11688 TaggedParserAtomIndex
11689 nameForAnonymousClass
/* = TaggedParserAtomIndex::null() */) {
11690 MOZ_ASSERT((nameKind
== ClassNameKind::InferredName
) ==
11691 bool(nameForAnonymousClass
));
11693 ParseNode
* heritageExpression
= classNode
->heritage();
11694 ListNode
* classMembers
= classNode
->memberList();
11695 ParseNode
* constructor
= FindConstructor(classMembers
);
11697 // If |nameKind != ClassNameKind::ComputedName|
11702 ClassEmitter
ce(this);
11703 TaggedParserAtomIndex innerName
;
11704 ClassEmitter::Kind kind
= ClassEmitter::Kind::Expression
;
11705 if (ClassNames
* names
= classNode
->names()) {
11706 MOZ_ASSERT(nameKind
== ClassNameKind::BindingName
);
11707 innerName
= names
->innerBinding()->name();
11708 MOZ_ASSERT(innerName
);
11710 if (names
->outerBinding()) {
11711 MOZ_ASSERT(names
->outerBinding()->name());
11712 MOZ_ASSERT(names
->outerBinding()->name() == innerName
);
11713 kind
= ClassEmitter::Kind::Declaration
;
11717 if (LexicalScopeNode
* scopeBindings
= classNode
->scopeBindings()) {
11718 if (!ce
.emitScope(scopeBindings
->scopeBindings())) {
11724 bool isDerived
= !!heritageExpression
;
11726 if (!updateSourceCoordNotes(classNode
->pn_pos
.begin
)) {
11729 if (!markStepBreakpoint()) {
11732 if (!emitTree(heritageExpression
)) {
11733 // [stack] HERITAGE
11738 // The class body scope holds any private names. Those mustn't be visible in
11739 // the heritage expression and hence the scope must be emitted after the
11740 // heritage expression.
11741 if (ClassBodyScopeNode
* bodyScopeBindings
= classNode
->bodyScopeBindings()) {
11742 if (!ce
.emitBodyScope(bodyScopeBindings
->scopeBindings())) {
11743 // [stack] HERITAGE
11747 // The spec does not say anything about private brands being symbols. It's
11748 // an implementation detail. So we can give the special private brand
11749 // symbol any description we want and users won't normally see it. For
11750 // debugging, use the class name.
11751 auto privateBrandName
= innerName
;
11753 privateBrandName
= nameForAnonymousClass
11754 ? nameForAnonymousClass
11755 : TaggedParserAtomIndex::WellKnown::anonymous();
11757 if (!emitNewPrivateNames(privateBrandName
, classMembers
)) {
11762 bool hasNameOnStack
= nameKind
== ClassNameKind::ComputedName
;
11764 if (!ce
.emitDerivedClass(innerName
, nameForAnonymousClass
,
11766 // [stack] HERITAGE HOMEOBJ
11770 if (!ce
.emitClass(innerName
, nameForAnonymousClass
, hasNameOnStack
)) {
11776 // Stack currently has HOMEOBJ followed by optional HERITAGE. When HERITAGE
11777 // is not used, an implicit value of %FunctionPrototype% is implied.
11779 // See |Parser::classMember(...)| for the reason why |.initializers| is
11780 // created within its own scope.
11781 Maybe
<LexicalScopeEmitter
> lse
;
11782 FunctionNode
* ctor
;
11783 if (constructor
->is
<LexicalScopeNode
>()) {
11784 LexicalScopeNode
* constructorScope
= &constructor
->as
<LexicalScopeNode
>();
11786 // The constructor scope should only contain the |.initializers| binding.
11787 MOZ_ASSERT(!constructorScope
->isEmptyScope());
11788 MOZ_ASSERT(constructorScope
->scopeBindings()->length
== 1);
11789 MOZ_ASSERT(GetScopeDataTrailingNames(constructorScope
->scopeBindings())[0]
11791 TaggedParserAtomIndex::WellKnown::dot_initializers_());
11793 auto needsInitializer
= [](ParseNode
* propdef
) {
11794 return NeedsFieldInitializer(propdef
, false) ||
11795 NeedsAccessorInitializer(propdef
, false);
11798 // As an optimization omit the |.initializers| binding when no instance
11799 // fields or private methods are present.
11800 bool needsInitializers
=
11801 std::any_of(classMembers
->contents().begin(),
11802 classMembers
->contents().end(), needsInitializer
);
11803 if (needsInitializers
) {
11805 if (!lse
->emitScope(ScopeKind::Lexical
,
11806 constructorScope
->scopeBindings())) {
11810 // Any class with field initializers will have a constructor
11811 if (!emitCreateMemberInitializers(ce
, classMembers
,
11812 FieldPlacement::Instance
11813 #ifdef ENABLE_DECORATORS
11822 ctor
= &constructorScope
->scopeBody()->as
<ClassMethod
>().method();
11824 // The |.initializers| binding is never emitted when in self-hosting mode.
11825 MOZ_ASSERT(emitterMode
== BytecodeEmitter::SelfHosting
);
11826 ctor
= &constructor
->as
<ClassMethod
>().method();
11829 bool needsHomeObject
= ctor
->funbox()->needsHomeObject();
11830 // HERITAGE is consumed inside emitFunction.
11831 if (nameKind
== ClassNameKind::InferredName
) {
11832 if (!setFunName(ctor
->funbox(), nameForAnonymousClass
)) {
11836 if (!emitFunction(ctor
, isDerived
)) {
11837 // [stack] HOMEOBJ CTOR
11840 if (lse
.isSome()) {
11841 if (!lse
->emitEnd()) {
11846 if (!ce
.emitInitConstructor(needsHomeObject
)) {
11847 // [stack] CTOR HOMEOBJ
11851 if (!emitCreateFieldKeys(classMembers
, FieldPlacement::Instance
)) {
11855 if (!emitCreateMemberInitializers(ce
, classMembers
, FieldPlacement::Static
11856 #ifdef ENABLE_DECORATORS
11864 if (!emitCreateFieldKeys(classMembers
, FieldPlacement::Static
)) {
11868 if (!emitPropertyList(classMembers
, ce
, ClassBody
)) {
11869 // [stack] CTOR HOMEOBJ
11873 if (!ce
.emitBinding()) {
11878 if (!emitInitializeStaticFields(classMembers
)) {
11883 #if ENABLE_DECORATORS
11884 if (classNode
->decorators() != nullptr) {
11885 DecoratorEmitter
de(this);
11886 NameNode
* className
=
11887 classNode
->names() ? classNode
->names()->innerBinding() : nullptr;
11888 if (!de
.emitApplyDecoratorsToClassDefinition(className
,
11889 classNode
->decorators())) {
11896 if (!ce
.emitEnd(kind
)) {
11897 // [stack] # class declaration
11899 // [stack] # class expression
11907 bool BytecodeEmitter::emitExportDefault(BinaryNode
* exportNode
) {
11908 MOZ_ASSERT(exportNode
->isKind(ParseNodeKind::ExportDefaultStmt
));
11910 ParseNode
* valueNode
= exportNode
->left();
11911 if (valueNode
->isDirectRHSAnonFunction()) {
11912 MOZ_ASSERT(exportNode
->right());
11914 if (!emitAnonymousFunctionWithName(
11915 valueNode
, TaggedParserAtomIndex::WellKnown::default_())) {
11919 if (!emitTree(valueNode
)) {
11924 if (ParseNode
* binding
= exportNode
->right()) {
11925 if (!emitLexicalInitialization(&binding
->as
<NameNode
>())) {
11929 if (!emit1(JSOp::Pop
)) {
11937 bool BytecodeEmitter::emitTree(
11938 ParseNode
* pn
, ValueUsage valueUsage
/* = ValueUsage::WantValue */,
11939 EmitLineNumberNote emitLineNote
/* = EMIT_LINENOTE */) {
11940 AutoCheckRecursionLimit
recursion(fc
);
11941 if (!recursion
.check(fc
)) {
11945 /* Emit notes to tell the current bytecode's source line number.
11946 However, a couple trees require special treatment; see the
11947 relevant emitter functions for details. */
11948 if (emitLineNote
== EMIT_LINENOTE
&&
11949 !ParseNodeRequiresSpecialLineNumberNotes(pn
)) {
11950 if (!updateLineNumberNotes(pn
->pn_pos
.begin
)) {
11955 switch (pn
->getKind()) {
11956 case ParseNodeKind::Function
:
11957 if (!emitFunction(&pn
->as
<FunctionNode
>())) {
11962 case ParseNodeKind::ParamsBody
:
11963 MOZ_ASSERT_UNREACHABLE(
11964 "ParamsBody should be handled in emitFunctionScript.");
11967 case ParseNodeKind::IfStmt
:
11968 if (!emitIf(&pn
->as
<TernaryNode
>())) {
11973 case ParseNodeKind::SwitchStmt
:
11974 if (!emitSwitch(&pn
->as
<SwitchStatement
>())) {
11979 case ParseNodeKind::WhileStmt
:
11980 if (!emitWhile(&pn
->as
<BinaryNode
>())) {
11985 case ParseNodeKind::DoWhileStmt
:
11986 if (!emitDo(&pn
->as
<BinaryNode
>())) {
11991 case ParseNodeKind::ForStmt
:
11992 if (!emitFor(&pn
->as
<ForNode
>())) {
11997 case ParseNodeKind::BreakStmt
:
11998 // Ensure that the column of the 'break' is set properly.
11999 if (!updateSourceCoordNotes(pn
->pn_pos
.begin
)) {
12002 if (!markStepBreakpoint()) {
12006 if (!emitBreak(pn
->as
<BreakStatement
>().label())) {
12011 case ParseNodeKind::ContinueStmt
:
12012 // Ensure that the column of the 'continue' is set properly.
12013 if (!updateSourceCoordNotes(pn
->pn_pos
.begin
)) {
12016 if (!markStepBreakpoint()) {
12020 if (!emitContinue(pn
->as
<ContinueStatement
>().label())) {
12025 case ParseNodeKind::WithStmt
:
12026 if (!emitWith(&pn
->as
<BinaryNode
>())) {
12031 case ParseNodeKind::TryStmt
:
12032 if (!emitTry(&pn
->as
<TryNode
>())) {
12037 case ParseNodeKind::Catch
:
12038 if (!emitCatch(&pn
->as
<BinaryNode
>())) {
12043 case ParseNodeKind::VarStmt
:
12044 if (!emitDeclarationList(&pn
->as
<ListNode
>())) {
12049 case ParseNodeKind::ReturnStmt
:
12050 if (!emitReturn(&pn
->as
<UnaryNode
>())) {
12055 case ParseNodeKind::YieldStarExpr
:
12056 if (!emitYieldStar(pn
->as
<UnaryNode
>().kid())) {
12061 case ParseNodeKind::Generator
:
12062 if (!emit1(JSOp::Generator
)) {
12067 case ParseNodeKind::InitialYield
:
12068 if (!emitInitialYield(&pn
->as
<UnaryNode
>())) {
12073 case ParseNodeKind::YieldExpr
:
12074 if (!emitYield(&pn
->as
<UnaryNode
>())) {
12079 case ParseNodeKind::AwaitExpr
:
12080 if (!emitAwaitInInnermostScope(&pn
->as
<UnaryNode
>())) {
12085 case ParseNodeKind::StatementList
:
12086 if (!emitStatementList(&pn
->as
<ListNode
>())) {
12091 case ParseNodeKind::EmptyStmt
:
12094 case ParseNodeKind::ExpressionStmt
:
12095 if (!emitExpressionStatement(&pn
->as
<UnaryNode
>())) {
12100 case ParseNodeKind::LabelStmt
:
12101 if (!emitLabeledStatement(&pn
->as
<LabeledStatement
>())) {
12106 case ParseNodeKind::CommaExpr
:
12107 if (!emitSequenceExpr(&pn
->as
<ListNode
>(), valueUsage
)) {
12112 case ParseNodeKind::InitExpr
:
12113 case ParseNodeKind::AssignExpr
:
12114 case ParseNodeKind::AddAssignExpr
:
12115 case ParseNodeKind::SubAssignExpr
:
12116 case ParseNodeKind::BitOrAssignExpr
:
12117 case ParseNodeKind::BitXorAssignExpr
:
12118 case ParseNodeKind::BitAndAssignExpr
:
12119 case ParseNodeKind::LshAssignExpr
:
12120 case ParseNodeKind::RshAssignExpr
:
12121 case ParseNodeKind::UrshAssignExpr
:
12122 case ParseNodeKind::MulAssignExpr
:
12123 case ParseNodeKind::DivAssignExpr
:
12124 case ParseNodeKind::ModAssignExpr
:
12125 case ParseNodeKind::PowAssignExpr
: {
12126 BinaryNode
* assignNode
= &pn
->as
<BinaryNode
>();
12127 if (!emitAssignmentOrInit(assignNode
->getKind(), assignNode
->left(),
12128 assignNode
->right())) {
12134 case ParseNodeKind::CoalesceAssignExpr
:
12135 case ParseNodeKind::OrAssignExpr
:
12136 case ParseNodeKind::AndAssignExpr
:
12137 if (!emitShortCircuitAssignment(&pn
->as
<AssignmentNode
>())) {
12142 case ParseNodeKind::ConditionalExpr
:
12143 if (!emitConditionalExpression(pn
->as
<ConditionalExpression
>(),
12149 case ParseNodeKind::OrExpr
:
12150 case ParseNodeKind::CoalesceExpr
:
12151 case ParseNodeKind::AndExpr
:
12152 if (!emitShortCircuit(&pn
->as
<ListNode
>(), valueUsage
)) {
12157 case ParseNodeKind::AddExpr
:
12158 case ParseNodeKind::SubExpr
:
12159 case ParseNodeKind::BitOrExpr
:
12160 case ParseNodeKind::BitXorExpr
:
12161 case ParseNodeKind::BitAndExpr
:
12162 case ParseNodeKind::StrictEqExpr
:
12163 case ParseNodeKind::EqExpr
:
12164 case ParseNodeKind::StrictNeExpr
:
12165 case ParseNodeKind::NeExpr
:
12166 case ParseNodeKind::LtExpr
:
12167 case ParseNodeKind::LeExpr
:
12168 case ParseNodeKind::GtExpr
:
12169 case ParseNodeKind::GeExpr
:
12170 case ParseNodeKind::InExpr
:
12171 case ParseNodeKind::InstanceOfExpr
:
12172 case ParseNodeKind::LshExpr
:
12173 case ParseNodeKind::RshExpr
:
12174 case ParseNodeKind::UrshExpr
:
12175 case ParseNodeKind::MulExpr
:
12176 case ParseNodeKind::DivExpr
:
12177 case ParseNodeKind::ModExpr
:
12178 if (!emitLeftAssociative(&pn
->as
<ListNode
>())) {
12183 case ParseNodeKind::PrivateInExpr
:
12184 if (!emitPrivateInExpr(&pn
->as
<ListNode
>())) {
12189 case ParseNodeKind::PowExpr
:
12190 if (!emitRightAssociative(&pn
->as
<ListNode
>())) {
12195 case ParseNodeKind::TypeOfNameExpr
:
12196 if (!emitTypeof(&pn
->as
<UnaryNode
>(), JSOp::Typeof
)) {
12201 case ParseNodeKind::TypeOfExpr
:
12202 if (!emitTypeof(&pn
->as
<UnaryNode
>(), JSOp::TypeofExpr
)) {
12207 case ParseNodeKind::ThrowStmt
:
12208 if (!updateSourceCoordNotes(pn
->pn_pos
.begin
)) {
12211 if (!markStepBreakpoint()) {
12215 case ParseNodeKind::VoidExpr
:
12216 case ParseNodeKind::NotExpr
:
12217 case ParseNodeKind::BitNotExpr
:
12218 case ParseNodeKind::PosExpr
:
12219 case ParseNodeKind::NegExpr
:
12220 if (!emitUnary(&pn
->as
<UnaryNode
>())) {
12225 case ParseNodeKind::PreIncrementExpr
:
12226 case ParseNodeKind::PreDecrementExpr
:
12227 case ParseNodeKind::PostIncrementExpr
:
12228 case ParseNodeKind::PostDecrementExpr
:
12229 if (!emitIncOrDec(&pn
->as
<UnaryNode
>(), valueUsage
)) {
12234 case ParseNodeKind::DeleteNameExpr
:
12235 if (!emitDeleteName(&pn
->as
<UnaryNode
>())) {
12240 case ParseNodeKind::DeletePropExpr
:
12241 if (!emitDeleteProperty(&pn
->as
<UnaryNode
>())) {
12246 case ParseNodeKind::DeleteElemExpr
:
12247 if (!emitDeleteElement(&pn
->as
<UnaryNode
>())) {
12252 case ParseNodeKind::DeleteExpr
:
12253 if (!emitDeleteExpression(&pn
->as
<UnaryNode
>())) {
12258 case ParseNodeKind::DeleteOptionalChainExpr
:
12259 if (!emitDeleteOptionalChain(&pn
->as
<UnaryNode
>())) {
12264 case ParseNodeKind::OptionalChain
:
12265 if (!emitOptionalChain(&pn
->as
<UnaryNode
>(), valueUsage
)) {
12270 case ParseNodeKind::DotExpr
: {
12271 PropertyAccess
* prop
= &pn
->as
<PropertyAccess
>();
12272 bool isSuper
= prop
->isSuper();
12273 PropOpEmitter
poe(this, PropOpEmitter::Kind::Get
,
12274 isSuper
? PropOpEmitter::ObjKind::Super
12275 : PropOpEmitter::ObjKind::Other
);
12276 if (!poe
.prepareForObj()) {
12280 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
12281 if (!emitGetThisForSuperBase(base
)) {
12286 if (!emitPropLHS(prop
)) {
12291 if (!poe
.emitGet(prop
->key().atom())) {
12298 case ParseNodeKind::ElemExpr
: {
12299 PropertyByValue
* elem
= &pn
->as
<PropertyByValue
>();
12300 bool isSuper
= elem
->isSuper();
12301 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
12302 ElemOpEmitter
eoe(this, ElemOpEmitter::Kind::Get
,
12303 isSuper
? ElemOpEmitter::ObjKind::Super
12304 : ElemOpEmitter::ObjKind::Other
);
12305 if (!emitElemObjAndKey(elem
, isSuper
, eoe
)) {
12306 // [stack] # if Super
12307 // [stack] THIS KEY
12308 // [stack] # otherwise
12312 if (!eoe
.emitGet()) {
12320 case ParseNodeKind::PrivateMemberExpr
: {
12321 PrivateMemberAccess
* privateExpr
= &pn
->as
<PrivateMemberAccess
>();
12322 PrivateOpEmitter
xoe(this, PrivateOpEmitter::Kind::Get
,
12323 privateExpr
->privateName().name());
12324 if (!emitTree(&privateExpr
->expression())) {
12328 if (!xoe
.emitReference()) {
12329 // [stack] OBJ NAME
12332 if (!xoe
.emitGet()) {
12340 case ParseNodeKind::NewExpr
:
12341 case ParseNodeKind::TaggedTemplateExpr
:
12342 case ParseNodeKind::CallExpr
:
12343 case ParseNodeKind::SuperCallExpr
:
12344 if (!emitCallOrNew(&pn
->as
<CallNode
>(), valueUsage
)) {
12349 case ParseNodeKind::LexicalScope
:
12350 if (!emitLexicalScope(&pn
->as
<LexicalScopeNode
>())) {
12355 case ParseNodeKind::ConstDecl
:
12356 case ParseNodeKind::LetDecl
:
12357 if (!emitDeclarationList(&pn
->as
<ListNode
>())) {
12362 case ParseNodeKind::ImportDecl
:
12363 MOZ_ASSERT(sc
->isModuleContext());
12366 case ParseNodeKind::ExportStmt
: {
12367 MOZ_ASSERT(sc
->isModuleContext());
12368 UnaryNode
* node
= &pn
->as
<UnaryNode
>();
12369 ParseNode
* decl
= node
->kid();
12370 if (decl
->getKind() != ParseNodeKind::ExportSpecList
) {
12371 if (!emitTree(decl
)) {
12378 case ParseNodeKind::ExportDefaultStmt
:
12379 MOZ_ASSERT(sc
->isModuleContext());
12380 if (!emitExportDefault(&pn
->as
<BinaryNode
>())) {
12385 case ParseNodeKind::ExportFromStmt
:
12386 MOZ_ASSERT(sc
->isModuleContext());
12389 case ParseNodeKind::CallSiteObj
:
12390 if (!emitCallSiteObject(&pn
->as
<CallSiteNode
>())) {
12395 case ParseNodeKind::ArrayExpr
:
12396 if (!emitArrayLiteral(&pn
->as
<ListNode
>())) {
12401 case ParseNodeKind::ObjectExpr
:
12402 if (!emitObject(&pn
->as
<ListNode
>())) {
12407 case ParseNodeKind::Name
:
12408 if (!emitGetName(&pn
->as
<NameNode
>())) {
12413 case ParseNodeKind::PrivateName
:
12414 if (!emitGetPrivateName(&pn
->as
<NameNode
>())) {
12419 case ParseNodeKind::TemplateStringListExpr
:
12420 if (!emitTemplateString(&pn
->as
<ListNode
>())) {
12425 case ParseNodeKind::TemplateStringExpr
:
12426 case ParseNodeKind::StringExpr
:
12427 if (!emitStringOp(JSOp::String
, pn
->as
<NameNode
>().atom())) {
12432 case ParseNodeKind::NumberExpr
:
12433 if (!emitNumberOp(pn
->as
<NumericLiteral
>().value())) {
12438 case ParseNodeKind::BigIntExpr
:
12439 if (!emitBigIntOp(&pn
->as
<BigIntLiteral
>())) {
12444 case ParseNodeKind::RegExpExpr
: {
12445 GCThingIndex index
;
12446 if (!perScriptData().gcThingList().append(&pn
->as
<RegExpLiteral
>(),
12450 if (!emitRegExp(index
)) {
12456 case ParseNodeKind::TrueExpr
:
12457 if (!emit1(JSOp::True
)) {
12461 case ParseNodeKind::FalseExpr
:
12462 if (!emit1(JSOp::False
)) {
12466 case ParseNodeKind::NullExpr
:
12467 if (!emit1(JSOp::Null
)) {
12471 case ParseNodeKind::RawUndefinedExpr
:
12472 if (!emit1(JSOp::Undefined
)) {
12477 case ParseNodeKind::ThisExpr
:
12478 if (!emitThisLiteral(&pn
->as
<ThisLiteral
>())) {
12483 case ParseNodeKind::DebuggerStmt
:
12484 if (!updateSourceCoordNotes(pn
->pn_pos
.begin
)) {
12487 if (!markStepBreakpoint()) {
12490 if (!emit1(JSOp::Debugger
)) {
12495 case ParseNodeKind::ClassDecl
:
12496 if (!emitClass(&pn
->as
<ClassNode
>())) {
12501 case ParseNodeKind::NewTargetExpr
:
12502 if (!emitNewTarget(&pn
->as
<NewTargetNode
>())) {
12507 case ParseNodeKind::ImportMetaExpr
:
12508 if (!emit1(JSOp::ImportMeta
)) {
12513 case ParseNodeKind::CallImportExpr
: {
12514 BinaryNode
* spec
= &pn
->as
<BinaryNode
>().right()->as
<BinaryNode
>();
12516 if (!emitTree(spec
->left())) {
12517 // [stack] specifier
12521 if (!spec
->right()->isKind(ParseNodeKind::PosHolder
)) {
12522 // [stack] specifier options
12523 if (!emitTree(spec
->right())) {
12527 // [stack] specifier undefined
12528 if (!emit1(JSOp::Undefined
)) {
12533 if (!emit1(JSOp::DynamicImport
)) {
12540 case ParseNodeKind::SetThis
:
12541 if (!emitSetThis(&pn
->as
<BinaryNode
>())) {
12546 #ifdef ENABLE_RECORD_TUPLE
12547 case ParseNodeKind::RecordExpr
:
12548 if (!emitRecordLiteral(&pn
->as
<ListNode
>())) {
12553 case ParseNodeKind::TupleExpr
:
12554 if (!emitTupleLiteral(&pn
->as
<ListNode
>())) {
12560 case ParseNodeKind::PropertyNameExpr
:
12561 case ParseNodeKind::PosHolder
:
12562 MOZ_FALLTHROUGH_ASSERT(
12563 "Should never try to emit ParseNodeKind::PosHolder or ::Property");
12572 static bool AllocSrcNote(FrontendContext
* fc
, SrcNotesVector
& notes
,
12573 unsigned size
, unsigned* index
) {
12574 size_t oldLength
= notes
.length();
12576 if (MOZ_UNLIKELY(oldLength
+ size
> MaxSrcNotesLength
)) {
12577 ReportAllocationOverflow(fc
);
12581 if (!notes
.growByUninitialized(size
)) {
12585 *index
= oldLength
;
12589 bool BytecodeEmitter::addTryNote(TryNoteKind kind
, uint32_t stackDepth
,
12590 BytecodeOffset start
, BytecodeOffset end
) {
12591 MOZ_ASSERT(!inPrologue());
12592 return bytecodeSection().tryNoteList().append(kind
, stackDepth
, start
, end
);
12595 bool BytecodeEmitter::newSrcNote(SrcNoteType type
, unsigned* indexp
) {
12596 SrcNotesVector
& notes
= bytecodeSection().notes();
12600 * Compute delta from the last annotated bytecode's offset. If it's too
12601 * big to fit in sn, allocate one or more xdelta notes and reset sn.
12603 BytecodeOffset offset
= bytecodeSection().offset();
12604 ptrdiff_t delta
= (offset
- bytecodeSection().lastNoteOffset()).value();
12605 bytecodeSection().setLastNoteOffset(offset
);
12607 auto allocator
= [&](unsigned size
) -> SrcNote
* {
12608 if (!AllocSrcNote(fc
, notes
, size
, &index
)) {
12611 return ¬es
[index
];
12614 if (!SrcNoteWriter::writeNote(type
, delta
, allocator
)) {
12622 if (type
== SrcNoteType::NewLine
|| type
== SrcNoteType::SetLine
) {
12623 lastLineOnlySrcNoteIndex
= index
;
12625 lastLineOnlySrcNoteIndex
= LastSrcNoteIsNotLineOnly
;
12631 bool BytecodeEmitter::newSrcNote2(SrcNoteType type
, ptrdiff_t offset
,
12632 unsigned* indexp
) {
12634 if (!newSrcNote(type
, &index
)) {
12637 if (!newSrcNoteOperand(offset
)) {
12646 bool BytecodeEmitter::convertLastNewLineToNewLineColumn(
12647 JS::LimitedColumnNumberZeroOrigin column
) {
12648 SrcNotesVector
& notes
= bytecodeSection().notes();
12649 MOZ_ASSERT(lastLineOnlySrcNoteIndex
== notes
.length() - 1);
12650 SrcNote
* sn
= ¬es
[lastLineOnlySrcNoteIndex
];
12651 MOZ_ASSERT(sn
->type() == SrcNoteType::NewLine
);
12653 SrcNoteWriter::convertNote(sn
, SrcNoteType::NewLineColumn
);
12654 if (!newSrcNoteOperand(SrcNote::NewLineColumn::toOperand(column
))) {
12658 lastLineOnlySrcNoteIndex
= LastSrcNoteIsNotLineOnly
;
12662 bool BytecodeEmitter::convertLastSetLineToSetLineColumn(
12663 JS::LimitedColumnNumberZeroOrigin column
) {
12664 SrcNotesVector
& notes
= bytecodeSection().notes();
12665 // The Line operand is either 1 byte or 4 bytes.
12666 MOZ_ASSERT(lastLineOnlySrcNoteIndex
== notes
.length() - 1 - 1 ||
12667 lastLineOnlySrcNoteIndex
== notes
.length() - 1 - 4);
12668 SrcNote
* sn
= ¬es
[lastLineOnlySrcNoteIndex
];
12669 MOZ_ASSERT(sn
->type() == SrcNoteType::SetLine
);
12671 SrcNoteWriter::convertNote(sn
, SrcNoteType::SetLineColumn
);
12672 if (!newSrcNoteOperand(SrcNote::SetLineColumn::columnToOperand(column
))) {
12676 lastLineOnlySrcNoteIndex
= LastSrcNoteIsNotLineOnly
;
12680 bool BytecodeEmitter::newSrcNoteOperand(ptrdiff_t operand
) {
12681 if (!SrcNote::isRepresentableOperand(operand
)) {
12682 reportError(nullptr, JSMSG_NEED_DIET
, "script");
12686 SrcNotesVector
& notes
= bytecodeSection().notes();
12688 auto allocator
= [&](unsigned size
) -> SrcNote
* {
12690 if (!AllocSrcNote(fc
, notes
, size
, &index
)) {
12693 return ¬es
[index
];
12696 return SrcNoteWriter::writeOperand(operand
, allocator
);
12699 bool BytecodeEmitter::intoScriptStencil(ScriptIndex scriptIndex
) {
12700 js::UniquePtr
<ImmutableScriptData
> immutableScriptData
=
12701 createImmutableScriptData();
12702 if (!immutableScriptData
) {
12706 MOZ_ASSERT(outermostScope().hasNonSyntacticScopeOnChain() ==
12707 sc
->hasNonSyntacticScope());
12709 auto& things
= perScriptData().gcThingList().objects();
12710 if (!compilationState
.appendGCThings(fc
, scriptIndex
, things
)) {
12714 // Hand over the ImmutableScriptData instance generated by BCE.
12716 SharedImmutableScriptData::createWith(fc
, std::move(immutableScriptData
));
12721 // De-duplicate the bytecode within the runtime.
12722 if (!compilationState
.sharedData
.addAndShare(fc
, scriptIndex
, sharedData
)) {
12726 ScriptStencil
& script
= compilationState
.scriptData
[scriptIndex
];
12727 script
.setHasSharedData();
12729 // Update flags specific to functions.
12730 if (sc
->isFunctionBox()) {
12731 FunctionBox
* funbox
= sc
->asFunctionBox();
12732 MOZ_ASSERT(&script
== &funbox
->functionStencil());
12733 funbox
->copyUpdatedImmutableFlags();
12734 MOZ_ASSERT(script
.isFunction());
12736 ScriptStencilExtra
& scriptExtra
= compilationState
.scriptExtra
[scriptIndex
];
12737 sc
->copyScriptExtraFields(scriptExtra
);
12743 SelfHostedIter
BytecodeEmitter::getSelfHostedIterFor(ParseNode
* parseNode
) {
12744 if (emitterMode
== BytecodeEmitter::SelfHosting
&&
12745 parseNode
->isKind(ParseNodeKind::CallExpr
)) {
12746 auto* callee
= parseNode
->as
<CallNode
>().callee();
12747 if (callee
->isName(TaggedParserAtomIndex::WellKnown::allowContentIter())) {
12748 return SelfHostedIter::AllowContent
;
12750 if (callee
->isName(
12751 TaggedParserAtomIndex::WellKnown::allowContentIterWith())) {
12752 return SelfHostedIter::AllowContentWith
;
12754 if (callee
->isName(
12755 TaggedParserAtomIndex::WellKnown::allowContentIterWithNext())) {
12756 return SelfHostedIter::AllowContentWithNext
;
12760 return SelfHostedIter::Deny
;
12763 #if defined(DEBUG) || defined(JS_JITSPEW)
12764 void BytecodeEmitter::dumpAtom(TaggedParserAtomIndex index
) const {
12765 parserAtoms().dump(index
);