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::LimitedColumnNumberOneOrigin, JS::ColumnNumberOffset
62 #include "js/friend/ErrorMessages.h" // JSMSG_*
63 #include "js/friend/StackLimits.h" // AutoCheckRecursionLimit
64 #include "util/StringBuffer.h" // StringBuffer
65 #include "vm/BytecodeUtil.h" // JOF_*, IsArgOp, IsLocalOp, SET_UINT24, SET_ICINDEX, BytecodeFallsThrough, BytecodeIsJumpTarget
66 #include "vm/CompletionKind.h" // CompletionKind
67 #include "vm/FunctionPrefixKind.h" // FunctionPrefixKind
68 #include "vm/GeneratorObject.h" // AbstractGeneratorObject
69 #include "vm/Opcodes.h" // JSOp, JSOpLength_*
70 #include "vm/PropMap.h" // SharedPropMap::MaxPropsForNonDictionary
71 #include "vm/Scope.h" // GetScopeDataTrailingNames
72 #include "vm/SharedStencil.h" // ScopeNote
73 #include "vm/ThrowMsgKind.h" // ThrowMsgKind
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
,
143 JS::LimitedColumnNumberOneOrigin(sc
->extent().column
)),
144 perScriptData_(fc
, compilationState
),
145 errorReporter_(errorReporter
),
146 compilationState(compilationState
),
147 suppressBreakpointsAndSourceNotes(
148 ShouldSuppressBreakpointsAndSourceNotes(sc
, emitterMode
)),
149 emitterMode(emitterMode
) {
150 MOZ_ASSERT_IF(parent
, fc
== parent
->fc
);
153 BytecodeEmitter::BytecodeEmitter(BytecodeEmitter
* parent
, SharedContext
* sc
)
154 : BytecodeEmitter(parent
, parent
->fc
, sc
, parent
->errorReporter_
,
155 parent
->compilationState
, parent
->emitterMode
) {}
157 BytecodeEmitter::BytecodeEmitter(FrontendContext
* fc
,
158 const EitherParser
& parser
, SharedContext
* sc
,
159 CompilationState
& compilationState
,
160 EmitterMode emitterMode
)
161 : BytecodeEmitter(nullptr, fc
, sc
, parser
.errorReporter(), compilationState
,
166 void BytecodeEmitter::initFromBodyPosition(TokenPos bodyPosition
) {
167 setScriptStartOffsetIfUnset(bodyPosition
.begin
);
168 setFunctionBodyEndPos(bodyPosition
.end
);
171 bool BytecodeEmitter::init() {
173 if (!compilationState
.prepareSharedDataStorage(fc
)) {
177 return perScriptData_
.init(fc
);
180 bool BytecodeEmitter::init(TokenPos bodyPosition
) {
181 initFromBodyPosition(bodyPosition
);
185 template <typename T
>
186 T
* BytecodeEmitter::findInnermostNestableControl() const {
187 return NestableControl::findNearest
<T
>(innermostNestableControl
);
190 template <typename T
, typename Predicate
/* (T*) -> bool */>
191 T
* BytecodeEmitter::findInnermostNestableControl(Predicate predicate
) const {
192 return NestableControl::findNearest
<T
>(innermostNestableControl
, predicate
);
195 NameLocation
BytecodeEmitter::lookupName(TaggedParserAtomIndex name
) {
196 return innermostEmitterScope()->lookup(this, name
);
199 void BytecodeEmitter::lookupPrivate(TaggedParserAtomIndex name
,
201 Maybe
<NameLocation
>& brandLoc
) {
202 innermostEmitterScope()->lookupPrivate(this, name
, loc
, brandLoc
);
205 Maybe
<NameLocation
> BytecodeEmitter::locationOfNameBoundInScope(
206 TaggedParserAtomIndex name
, EmitterScope
* target
) {
207 return innermostEmitterScope()->locationBoundInScope(name
, target
);
210 template <typename T
>
211 Maybe
<NameLocation
> BytecodeEmitter::locationOfNameBoundInScopeType(
212 TaggedParserAtomIndex name
, EmitterScope
* source
) {
213 EmitterScope
* aScope
= source
;
214 while (!aScope
->scope(this).is
<T
>()) {
215 aScope
= aScope
->enclosingInFrame();
217 return source
->locationBoundInScope(name
, aScope
);
220 bool BytecodeEmitter::markStepBreakpoint() {
221 if (skipBreakpointSrcNotes()) {
225 if (!newSrcNote(SrcNoteType::BreakpointStepSep
)) {
229 // We track the location of the most recent separator for use in
230 // markSimpleBreakpoint. Note that this means that the position must already
231 // be set before markStepBreakpoint is called.
232 bytecodeSection().updateSeparatorPosition();
237 bool BytecodeEmitter::markSimpleBreakpoint() {
238 if (skipBreakpointSrcNotes()) {
242 // If a breakable call ends up being the same location as the most recent
243 // expression start, we need to skip marking it breakable in order to avoid
244 // having two breakpoints with the same line/column position.
245 // Note: This assumes that the position for the call has already been set.
246 if (!bytecodeSection().isDuplicateLocation()) {
247 if (!newSrcNote(SrcNoteType::Breakpoint
)) {
255 bool BytecodeEmitter::emitCheck(JSOp op
, ptrdiff_t delta
,
256 BytecodeOffset
* offset
) {
257 size_t oldLength
= bytecodeSection().code().length();
258 *offset
= BytecodeOffset(oldLength
);
260 size_t newLength
= oldLength
+ size_t(delta
);
261 if (MOZ_UNLIKELY(newLength
> MaxBytecodeLength
)) {
262 ReportAllocationOverflow(fc
);
266 if (!bytecodeSection().code().growByUninitialized(delta
)) {
270 if (BytecodeOpHasIC(op
)) {
271 // Even if every bytecode op is a JOF_IC op and the function has ARGC_LIMIT
272 // arguments, numICEntries cannot overflow.
273 static_assert(MaxBytecodeLength
+ 1 /* this */ + ARGC_LIMIT
<= UINT32_MAX
,
274 "numICEntries must not overflow");
275 bytecodeSection().incrementNumICEntries();
282 bool BytecodeEmitter::checkStrictOrSloppy(JSOp op
) {
283 if (IsCheckStrictOp(op
) && !sc
->strict()) {
286 if (IsCheckSloppyOp(op
) && sc
->strict()) {
293 bool BytecodeEmitter::emit1(JSOp op
) {
294 MOZ_ASSERT(checkStrictOrSloppy(op
));
296 BytecodeOffset offset
;
297 if (!emitCheck(op
, 1, &offset
)) {
301 jsbytecode
* code
= bytecodeSection().code(offset
);
302 code
[0] = jsbytecode(op
);
303 bytecodeSection().updateDepth(op
, offset
);
307 bool BytecodeEmitter::emit2(JSOp op
, uint8_t op1
) {
308 MOZ_ASSERT(checkStrictOrSloppy(op
));
310 BytecodeOffset offset
;
311 if (!emitCheck(op
, 2, &offset
)) {
315 jsbytecode
* code
= bytecodeSection().code(offset
);
316 code
[0] = jsbytecode(op
);
317 code
[1] = jsbytecode(op1
);
318 bytecodeSection().updateDepth(op
, offset
);
322 bool BytecodeEmitter::emit3(JSOp op
, jsbytecode op1
, jsbytecode op2
) {
323 MOZ_ASSERT(checkStrictOrSloppy(op
));
325 /* These should filter through emitVarOp. */
326 MOZ_ASSERT(!IsArgOp(op
));
327 MOZ_ASSERT(!IsLocalOp(op
));
329 BytecodeOffset offset
;
330 if (!emitCheck(op
, 3, &offset
)) {
334 jsbytecode
* code
= bytecodeSection().code(offset
);
335 code
[0] = jsbytecode(op
);
338 bytecodeSection().updateDepth(op
, offset
);
342 bool BytecodeEmitter::emitN(JSOp op
, size_t extra
, BytecodeOffset
* offset
) {
343 MOZ_ASSERT(checkStrictOrSloppy(op
));
344 ptrdiff_t length
= 1 + ptrdiff_t(extra
);
347 if (!emitCheck(op
, length
, &off
)) {
351 jsbytecode
* code
= bytecodeSection().code(off
);
352 code
[0] = jsbytecode(op
);
353 /* The remaining |extra| bytes are set by the caller */
356 * Don't updateDepth if op's use-count comes from the immediate
357 * operand yet to be stored in the extra bytes after op.
359 if (CodeSpec(op
).nuses
>= 0) {
360 bytecodeSection().updateDepth(op
, off
);
369 bool BytecodeEmitter::emitJumpTargetOp(JSOp op
, BytecodeOffset
* off
) {
370 MOZ_ASSERT(BytecodeIsJumpTarget(op
));
372 // Record the current IC-entry index at start of this op.
373 uint32_t numEntries
= bytecodeSection().numICEntries();
375 size_t n
= GetOpLength(op
) - 1;
376 MOZ_ASSERT(GetOpLength(op
) >= 1 + ICINDEX_LEN
);
378 if (!emitN(op
, n
, off
)) {
382 SET_ICINDEX(bytecodeSection().code(*off
), numEntries
);
386 bool BytecodeEmitter::emitJumpTarget(JumpTarget
* target
) {
387 BytecodeOffset off
= bytecodeSection().offset();
389 // Alias consecutive jump targets.
390 if (bytecodeSection().lastTargetOffset().valid() &&
391 off
== bytecodeSection().lastTargetOffset() +
392 BytecodeOffsetDiff(JSOpLength_JumpTarget
)) {
393 target
->offset
= bytecodeSection().lastTargetOffset();
397 target
->offset
= off
;
398 bytecodeSection().setLastTargetOffset(off
);
400 BytecodeOffset opOff
;
401 return emitJumpTargetOp(JSOp::JumpTarget
, &opOff
);
404 bool BytecodeEmitter::emitJumpNoFallthrough(JSOp op
, JumpList
* jump
) {
405 BytecodeOffset offset
;
406 if (!emitCheck(op
, 5, &offset
)) {
410 jsbytecode
* code
= bytecodeSection().code(offset
);
411 code
[0] = jsbytecode(op
);
412 MOZ_ASSERT(!jump
->offset
.valid() ||
413 (0 <= jump
->offset
.value() && jump
->offset
< offset
));
414 jump
->push(bytecodeSection().code(BytecodeOffset(0)), offset
);
415 bytecodeSection().updateDepth(op
, offset
);
419 bool BytecodeEmitter::emitJump(JSOp op
, JumpList
* jump
) {
420 if (!emitJumpNoFallthrough(op
, jump
)) {
423 if (BytecodeFallsThrough(op
)) {
424 JumpTarget fallthrough
;
425 if (!emitJumpTarget(&fallthrough
)) {
432 void BytecodeEmitter::patchJumpsToTarget(JumpList jump
, JumpTarget target
) {
434 !jump
.offset
.valid() ||
435 (0 <= jump
.offset
.value() && jump
.offset
<= bytecodeSection().offset()));
436 MOZ_ASSERT(0 <= target
.offset
.value() &&
437 target
.offset
<= bytecodeSection().offset());
439 jump
.offset
.valid() &&
440 target
.offset
+ BytecodeOffsetDiff(4) <= bytecodeSection().offset(),
441 BytecodeIsJumpTarget(JSOp(*bytecodeSection().code(target
.offset
))));
442 jump
.patchAll(bytecodeSection().code(BytecodeOffset(0)), target
);
445 bool BytecodeEmitter::emitJumpTargetAndPatch(JumpList jump
) {
446 if (!jump
.offset
.valid()) {
450 if (!emitJumpTarget(&target
)) {
453 patchJumpsToTarget(jump
, target
);
457 bool BytecodeEmitter::emitCall(JSOp op
, uint16_t argc
,
458 const Maybe
<uint32_t>& sourceCoordOffset
) {
459 if (sourceCoordOffset
.isSome()) {
460 if (!updateSourceCoordNotes(*sourceCoordOffset
)) {
464 return emit3(op
, ARGC_LO(argc
), ARGC_HI(argc
));
467 bool BytecodeEmitter::emitCall(JSOp op
, uint16_t argc
, ParseNode
* pn
) {
468 return emitCall(op
, argc
, pn
? Some(pn
->pn_pos
.begin
) : Nothing());
471 bool BytecodeEmitter::emitDupAt(unsigned slotFromTop
, unsigned count
) {
472 MOZ_ASSERT(slotFromTop
< unsigned(bytecodeSection().stackDepth()));
473 MOZ_ASSERT(slotFromTop
+ 1 >= count
);
475 if (slotFromTop
== 0 && count
== 1) {
476 return emit1(JSOp::Dup
);
479 if (slotFromTop
== 1 && count
== 2) {
480 return emit1(JSOp::Dup2
);
483 if (slotFromTop
>= Bit(24)) {
484 reportError(nullptr, JSMSG_TOO_MANY_LOCALS
);
488 for (unsigned i
= 0; i
< count
; i
++) {
490 if (!emitN(JSOp::DupAt
, 3, &off
)) {
494 jsbytecode
* pc
= bytecodeSection().code(off
);
495 SET_UINT24(pc
, slotFromTop
);
501 bool BytecodeEmitter::emitPopN(unsigned n
) {
505 return emit1(JSOp::Pop
);
508 // 2 JSOp::Pop instructions (2 bytes) are shorter than JSOp::PopN (3 bytes).
510 return emit1(JSOp::Pop
) && emit1(JSOp::Pop
);
513 return emitUint16Operand(JSOp::PopN
, n
);
516 bool BytecodeEmitter::emitPickN(uint8_t n
) {
520 return emit1(JSOp::Swap
);
523 return emit2(JSOp::Pick
, n
);
526 bool BytecodeEmitter::emitUnpickN(uint8_t n
) {
530 return emit1(JSOp::Swap
);
533 return emit2(JSOp::Unpick
, n
);
536 bool BytecodeEmitter::emitCheckIsObj(CheckIsObjectKind kind
) {
537 return emit2(JSOp::CheckIsObj
, uint8_t(kind
));
540 bool BytecodeEmitter::emitBuiltinObject(BuiltinObjectKind kind
) {
541 return emit2(JSOp::BuiltinObject
, uint8_t(kind
));
544 /* Updates line number notes, not column notes. */
545 bool BytecodeEmitter::updateLineNumberNotes(uint32_t offset
) {
546 if (skipLocationSrcNotes()) {
550 const ErrorReporter
& er
= errorReporter();
551 std::optional
<bool> onThisLineStatus
=
552 er
.isOnThisLine(offset
, bytecodeSection().currentLine());
553 if (!onThisLineStatus
.has_value()) {
554 er
.errorNoOffset(JSMSG_OUT_OF_MEMORY
);
558 bool onThisLine
= *onThisLineStatus
;
561 unsigned line
= er
.lineAt(offset
);
562 unsigned delta
= line
- bytecodeSection().currentLine();
564 // If we use a `SetLine` note below, we want it to be relative to the
565 // scripts initial line number for better chance of sharing.
566 unsigned initialLine
= sc
->extent().lineno
;
567 MOZ_ASSERT(line
>= initialLine
);
570 * Encode any change in the current source line number by using
571 * either several SrcNoteType::NewLine notes or just one
572 * SrcNoteType::SetLine note, whichever consumes less space.
574 * NB: We handle backward line number deltas (possible with for
575 * loops where the update part is emitted after the body, but its
576 * line number is <= any line number in the body) here by letting
577 * unsigned delta_ wrap to a very large number, which triggers a
578 * SrcNoteType::SetLine.
580 bytecodeSection().setCurrentLine(line
, offset
);
581 if (delta
>= SrcNote::SetLine::lengthFor(line
, initialLine
)) {
582 if (!newSrcNote2(SrcNoteType::SetLine
,
583 SrcNote::SetLine::toOperand(line
, initialLine
))) {
588 if (!newSrcNote(SrcNoteType::NewLine
)) {
591 } while (--delta
!= 0);
594 bytecodeSection().updateSeparatorPositionIfPresent();
599 /* Updates the line number and column number information in the source notes. */
600 bool BytecodeEmitter::updateSourceCoordNotes(uint32_t offset
) {
601 if (skipLocationSrcNotes()) {
605 if (!updateLineNumberNotes(offset
)) {
609 JS::LimitedColumnNumberOneOrigin columnIndex
=
610 errorReporter().columnAt(offset
);
612 // Assert colspan is always representable.
613 static_assert((0 - ptrdiff_t(JS::LimitedColumnNumberOneOrigin::Limit
)) >=
614 SrcNote::ColSpan::MinColSpan
);
615 static_assert((ptrdiff_t(JS::LimitedColumnNumberOneOrigin::Limit
) - 0) <=
616 SrcNote::ColSpan::MaxColSpan
);
618 JS::ColumnNumberOffset colspan
= columnIndex
- bytecodeSection().lastColumn();
620 if (colspan
!= JS::ColumnNumberOffset::zero()) {
621 if (lastLineOnlySrcNoteIndex
!= LastSrcNoteIsNotLineOnly
) {
622 MOZ_ASSERT(bytecodeSection().lastColumn() ==
623 JS::LimitedColumnNumberOneOrigin());
625 const SrcNotesVector
& notes
= bytecodeSection().notes();
626 SrcNoteType type
= notes
[lastLineOnlySrcNoteIndex
].type();
627 if (type
== SrcNoteType::NewLine
) {
628 if (!convertLastNewLineToNewLineColumn(columnIndex
)) {
632 MOZ_ASSERT(type
== SrcNoteType::SetLine
);
633 if (!convertLastSetLineToSetLineColumn(columnIndex
)) {
638 if (!newSrcNote2(SrcNoteType::ColSpan
,
639 SrcNote::ColSpan::toOperand(colspan
))) {
643 bytecodeSection().setLastColumn(columnIndex
, offset
);
644 bytecodeSection().updateSeparatorPositionIfPresent();
649 bool BytecodeEmitter::updateSourceCoordNotesIfNonLiteral(ParseNode
* node
) {
650 if (node
->isLiteral()) {
653 return updateSourceCoordNotes(node
->pn_pos
.begin
);
656 uint32_t BytecodeEmitter::getOffsetForLoop(ParseNode
* nextpn
) {
657 // Try to give the JSOp::LoopHead the same line number as the next
658 // instruction. nextpn is often a block, in which case the next instruction
659 // typically comes from the first statement inside.
660 if (nextpn
->is
<LexicalScopeNode
>()) {
661 nextpn
= nextpn
->as
<LexicalScopeNode
>().scopeBody();
663 if (nextpn
->isKind(ParseNodeKind::StatementList
)) {
664 if (ParseNode
* firstStatement
= nextpn
->as
<ListNode
>().head()) {
665 nextpn
= firstStatement
;
669 return nextpn
->pn_pos
.begin
;
672 bool BytecodeEmitter::emitUint16Operand(JSOp op
, uint32_t operand
) {
673 MOZ_ASSERT(operand
<= UINT16_MAX
);
674 if (!emit3(op
, UINT16_LO(operand
), UINT16_HI(operand
))) {
680 bool BytecodeEmitter::emitUint32Operand(JSOp op
, uint32_t operand
) {
682 if (!emitN(op
, 4, &off
)) {
685 SET_UINT32(bytecodeSection().code(off
), operand
);
689 bool BytecodeEmitter::emitGoto(NestableControl
* target
, GotoKind kind
) {
690 NonLocalExitControl
nle(this, kind
== GotoKind::Continue
691 ? NonLocalExitKind::Continue
692 : NonLocalExitKind::Break
);
693 return nle
.emitNonLocalJump(target
);
696 AbstractScopePtr
BytecodeEmitter::innermostScope() const {
697 return innermostEmitterScope()->scope(this);
700 ScopeIndex
BytecodeEmitter::innermostScopeIndex() const {
701 return *innermostEmitterScope()->scopeIndex(this);
704 bool BytecodeEmitter::emitGCIndexOp(JSOp op
, GCThingIndex index
) {
705 MOZ_ASSERT(checkStrictOrSloppy(op
));
707 constexpr size_t OpLength
= 1 + GCTHING_INDEX_LEN
;
708 MOZ_ASSERT(GetOpLength(op
) == OpLength
);
710 BytecodeOffset offset
;
711 if (!emitCheck(op
, OpLength
, &offset
)) {
715 jsbytecode
* code
= bytecodeSection().code(offset
);
716 code
[0] = jsbytecode(op
);
717 SET_GCTHING_INDEX(code
, index
);
718 bytecodeSection().updateDepth(op
, offset
);
722 bool BytecodeEmitter::emitAtomOp(JSOp op
, TaggedParserAtomIndex atom
) {
725 // .generator lookups should be emitted as JSOp::GetAliasedVar instead of
726 // JSOp::GetName etc, to bypass |with| objects on the scope chain.
727 // It's safe to emit .this lookups though because |with| objects skip
729 MOZ_ASSERT_IF(op
== JSOp::GetName
|| op
== JSOp::GetGName
,
730 atom
!= TaggedParserAtomIndex::WellKnown::dot_generator_());
733 if (!makeAtomIndex(atom
, ParserAtom::Atomize::Yes
, &index
)) {
737 return emitAtomOp(op
, index
);
740 bool BytecodeEmitter::emitAtomOp(JSOp op
, GCThingIndex atomIndex
) {
741 MOZ_ASSERT(JOF_OPTYPE(op
) == JOF_ATOM
);
743 auto atom
= perScriptData().gcThingList().getAtom(atomIndex
);
744 MOZ_ASSERT(compilationState
.parserAtoms
.isInstantiatedAsJSAtom(atom
));
746 return emitGCIndexOp(op
, atomIndex
);
749 bool BytecodeEmitter::emitStringOp(JSOp op
, TaggedParserAtomIndex atom
) {
752 if (!makeAtomIndex(atom
, ParserAtom::Atomize::No
, &index
)) {
756 return emitStringOp(op
, index
);
759 bool BytecodeEmitter::emitStringOp(JSOp op
, GCThingIndex atomIndex
) {
760 MOZ_ASSERT(JOF_OPTYPE(op
) == JOF_STRING
);
761 return emitGCIndexOp(op
, atomIndex
);
764 bool BytecodeEmitter::emitInternedScopeOp(GCThingIndex index
, JSOp op
) {
765 MOZ_ASSERT(JOF_OPTYPE(op
) == JOF_SCOPE
);
766 MOZ_ASSERT(index
< perScriptData().gcThingList().length());
767 return emitGCIndexOp(op
, index
);
770 bool BytecodeEmitter::emitInternedObjectOp(GCThingIndex index
, JSOp op
) {
771 MOZ_ASSERT(JOF_OPTYPE(op
) == JOF_OBJECT
);
772 MOZ_ASSERT(index
< perScriptData().gcThingList().length());
773 return emitGCIndexOp(op
, index
);
776 bool BytecodeEmitter::emitRegExp(GCThingIndex index
) {
777 return emitGCIndexOp(JSOp::RegExp
, index
);
780 bool BytecodeEmitter::emitLocalOp(JSOp op
, uint32_t slot
) {
781 MOZ_ASSERT(JOF_OPTYPE(op
) != JOF_ENVCOORD
);
782 MOZ_ASSERT(IsLocalOp(op
));
785 if (!emitN(op
, LOCALNO_LEN
, &off
)) {
789 SET_LOCALNO(bytecodeSection().code(off
), slot
);
793 bool BytecodeEmitter::emitArgOp(JSOp op
, uint16_t slot
) {
794 MOZ_ASSERT(IsArgOp(op
));
796 if (!emitN(op
, ARGNO_LEN
, &off
)) {
800 SET_ARGNO(bytecodeSection().code(off
), slot
);
804 bool BytecodeEmitter::emitEnvCoordOp(JSOp op
, EnvironmentCoordinate ec
) {
805 MOZ_ASSERT(JOF_OPTYPE(op
) == JOF_ENVCOORD
||
806 JOF_OPTYPE(op
) == JOF_DEBUGCOORD
);
808 constexpr size_t N
= ENVCOORD_HOPS_LEN
+ ENVCOORD_SLOT_LEN
;
809 MOZ_ASSERT(GetOpLength(op
) == 1 + N
);
812 if (!emitN(op
, N
, &off
)) {
816 jsbytecode
* pc
= bytecodeSection().code(off
);
817 SET_ENVCOORD_HOPS(pc
, ec
.hops());
818 pc
+= ENVCOORD_HOPS_LEN
;
819 SET_ENVCOORD_SLOT(pc
, ec
.slot());
820 pc
+= ENVCOORD_SLOT_LEN
;
824 JSOp
BytecodeEmitter::strictifySetNameOp(JSOp op
) {
828 op
= JSOp::StrictSetName
;
833 op
= JSOp::StrictSetGName
;
841 bool BytecodeEmitter::checkSideEffects(ParseNode
* pn
, bool* answer
) {
842 AutoCheckRecursionLimit
recursion(fc
);
843 if (!recursion
.check(fc
)) {
849 switch (pn
->getKind()) {
850 // Trivial cases with no side effects.
851 case ParseNodeKind::EmptyStmt
:
852 case ParseNodeKind::TrueExpr
:
853 case ParseNodeKind::FalseExpr
:
854 case ParseNodeKind::NullExpr
:
855 case ParseNodeKind::RawUndefinedExpr
:
856 case ParseNodeKind::Elision
:
857 case ParseNodeKind::Generator
:
858 MOZ_ASSERT(pn
->is
<NullaryNode
>());
862 case ParseNodeKind::ObjectPropertyName
:
863 case ParseNodeKind::PrivateName
: // no side effects, unlike
864 // ParseNodeKind::Name
865 case ParseNodeKind::StringExpr
:
866 case ParseNodeKind::TemplateStringExpr
:
867 MOZ_ASSERT(pn
->is
<NameNode
>());
871 case ParseNodeKind::RegExpExpr
:
872 MOZ_ASSERT(pn
->is
<RegExpLiteral
>());
876 case ParseNodeKind::NumberExpr
:
877 MOZ_ASSERT(pn
->is
<NumericLiteral
>());
881 case ParseNodeKind::BigIntExpr
:
882 MOZ_ASSERT(pn
->is
<BigIntLiteral
>());
886 // |this| can throw in derived class constructors, including nested arrow
887 // functions or eval.
888 case ParseNodeKind::ThisExpr
:
889 MOZ_ASSERT(pn
->is
<UnaryNode
>());
890 *answer
= sc
->needsThisTDZChecks();
893 // |new.target| doesn't have any side-effects.
894 case ParseNodeKind::NewTargetExpr
: {
895 MOZ_ASSERT(pn
->is
<NewTargetNode
>());
900 // Trivial binary nodes with more token pos holders.
901 case ParseNodeKind::ImportMetaExpr
: {
902 MOZ_ASSERT(pn
->as
<BinaryNode
>().left()->isKind(ParseNodeKind::PosHolder
));
904 pn
->as
<BinaryNode
>().right()->isKind(ParseNodeKind::PosHolder
));
909 case ParseNodeKind::BreakStmt
:
910 MOZ_ASSERT(pn
->is
<BreakStatement
>());
914 case ParseNodeKind::ContinueStmt
:
915 MOZ_ASSERT(pn
->is
<ContinueStatement
>());
919 case ParseNodeKind::DebuggerStmt
:
920 MOZ_ASSERT(pn
->is
<DebuggerStatement
>());
924 // Watch out for getters!
925 case ParseNodeKind::OptionalDotExpr
:
926 case ParseNodeKind::DotExpr
:
927 MOZ_ASSERT(pn
->is
<BinaryNode
>());
931 // Unary cases with side effects only if the child has them.
932 case ParseNodeKind::TypeOfExpr
:
933 case ParseNodeKind::VoidExpr
:
934 case ParseNodeKind::NotExpr
:
935 return checkSideEffects(pn
->as
<UnaryNode
>().kid(), answer
);
937 // Even if the name expression is effect-free, performing ToPropertyKey on
938 // it might not be effect-free:
940 // RegExp.prototype.toString = () => { throw 42; };
941 // ({ [/regex/]: 0 }); // ToPropertyKey(/regex/) throws 42
944 // ({ [new.target]: 0 });
946 // Q.toString = () => { throw 17; };
947 // new Q; // new.target will be Q, ToPropertyKey(Q) throws 17
948 case ParseNodeKind::ComputedName
:
949 MOZ_ASSERT(pn
->is
<UnaryNode
>());
953 // Looking up or evaluating the associated name could throw.
954 case ParseNodeKind::TypeOfNameExpr
:
955 MOZ_ASSERT(pn
->is
<UnaryNode
>());
959 // This unary case has side effects on the enclosing object, sure. But
960 // that's not the question this function answers: it's whether the
961 // operation may have a side effect on something *other* than the result
962 // of the overall operation in which it's embedded. The answer to that
963 // is no, because an object literal having a mutated prototype only
964 // produces a value, without affecting anything else.
965 case ParseNodeKind::MutateProto
:
966 return checkSideEffects(pn
->as
<UnaryNode
>().kid(), answer
);
968 // Unary cases with obvious side effects.
969 case ParseNodeKind::PreIncrementExpr
:
970 case ParseNodeKind::PostIncrementExpr
:
971 case ParseNodeKind::PreDecrementExpr
:
972 case ParseNodeKind::PostDecrementExpr
:
973 case ParseNodeKind::ThrowStmt
:
974 MOZ_ASSERT(pn
->is
<UnaryNode
>());
978 // These might invoke valueOf/toString, even with a subexpression without
979 // side effects! Consider |+{ valueOf: null, toString: null }|.
980 case ParseNodeKind::BitNotExpr
:
981 case ParseNodeKind::PosExpr
:
982 case ParseNodeKind::NegExpr
:
983 MOZ_ASSERT(pn
->is
<UnaryNode
>());
987 // This invokes the (user-controllable) iterator protocol.
988 case ParseNodeKind::Spread
:
989 MOZ_ASSERT(pn
->is
<UnaryNode
>());
993 case ParseNodeKind::InitialYield
:
994 case ParseNodeKind::YieldStarExpr
:
995 case ParseNodeKind::YieldExpr
:
996 case ParseNodeKind::AwaitExpr
:
997 MOZ_ASSERT(pn
->is
<UnaryNode
>());
1001 // Deletion generally has side effects, even if isolated cases have none.
1002 case ParseNodeKind::DeleteNameExpr
:
1003 case ParseNodeKind::DeletePropExpr
:
1004 case ParseNodeKind::DeleteElemExpr
:
1005 case ParseNodeKind::DeleteOptionalChainExpr
:
1006 MOZ_ASSERT(pn
->is
<UnaryNode
>());
1010 // Deletion of a non-Reference expression has side effects only through
1011 // evaluating the expression.
1012 case ParseNodeKind::DeleteExpr
: {
1013 ParseNode
* expr
= pn
->as
<UnaryNode
>().kid();
1014 return checkSideEffects(expr
, answer
);
1017 case ParseNodeKind::ExpressionStmt
:
1018 return checkSideEffects(pn
->as
<UnaryNode
>().kid(), answer
);
1020 // Binary cases with obvious side effects.
1021 case ParseNodeKind::InitExpr
:
1025 case ParseNodeKind::AssignExpr
:
1026 case ParseNodeKind::AddAssignExpr
:
1027 case ParseNodeKind::SubAssignExpr
:
1028 case ParseNodeKind::CoalesceAssignExpr
:
1029 case ParseNodeKind::OrAssignExpr
:
1030 case ParseNodeKind::AndAssignExpr
:
1031 case ParseNodeKind::BitOrAssignExpr
:
1032 case ParseNodeKind::BitXorAssignExpr
:
1033 case ParseNodeKind::BitAndAssignExpr
:
1034 case ParseNodeKind::LshAssignExpr
:
1035 case ParseNodeKind::RshAssignExpr
:
1036 case ParseNodeKind::UrshAssignExpr
:
1037 case ParseNodeKind::MulAssignExpr
:
1038 case ParseNodeKind::DivAssignExpr
:
1039 case ParseNodeKind::ModAssignExpr
:
1040 case ParseNodeKind::PowAssignExpr
:
1041 MOZ_ASSERT(pn
->is
<AssignmentNode
>());
1045 case ParseNodeKind::SetThis
:
1046 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1050 case ParseNodeKind::StatementList
:
1051 // Strict equality operations and short circuit operators are well-behaved
1052 // and perform no conversions.
1053 case ParseNodeKind::CoalesceExpr
:
1054 case ParseNodeKind::OrExpr
:
1055 case ParseNodeKind::AndExpr
:
1056 case ParseNodeKind::StrictEqExpr
:
1057 case ParseNodeKind::StrictNeExpr
:
1058 // Any subexpression of a comma expression could be effectful.
1059 case ParseNodeKind::CommaExpr
:
1060 MOZ_ASSERT(!pn
->as
<ListNode
>().empty());
1062 // Subcomponents of a literal may be effectful.
1063 case ParseNodeKind::ArrayExpr
:
1064 case ParseNodeKind::ObjectExpr
:
1065 for (ParseNode
* item
: pn
->as
<ListNode
>().contents()) {
1066 if (!checkSideEffects(item
, answer
)) {
1075 #ifdef ENABLE_RECORD_TUPLE
1076 case ParseNodeKind::RecordExpr
:
1077 case ParseNodeKind::TupleExpr
:
1078 MOZ_CRASH("Record and Tuple are not supported yet");
1081 #ifdef ENABLE_DECORATORS
1082 case ParseNodeKind::DecoratorList
:
1083 MOZ_CRASH("Decorators are not supported yet");
1086 // Most other binary operations (parsed as lists in SpiderMonkey) may
1087 // perform conversions triggering side effects. Math operations perform
1088 // ToNumber and may fail invoking invalid user-defined toString/valueOf:
1089 // |5 < { toString: null }|. |instanceof| throws if provided a
1090 // non-object constructor: |null instanceof null|. |in| throws if given
1091 // a non-object RHS: |5 in null|.
1092 case ParseNodeKind::BitOrExpr
:
1093 case ParseNodeKind::BitXorExpr
:
1094 case ParseNodeKind::BitAndExpr
:
1095 case ParseNodeKind::EqExpr
:
1096 case ParseNodeKind::NeExpr
:
1097 case ParseNodeKind::LtExpr
:
1098 case ParseNodeKind::LeExpr
:
1099 case ParseNodeKind::GtExpr
:
1100 case ParseNodeKind::GeExpr
:
1101 case ParseNodeKind::InstanceOfExpr
:
1102 case ParseNodeKind::InExpr
:
1103 case ParseNodeKind::PrivateInExpr
:
1104 case ParseNodeKind::LshExpr
:
1105 case ParseNodeKind::RshExpr
:
1106 case ParseNodeKind::UrshExpr
:
1107 case ParseNodeKind::AddExpr
:
1108 case ParseNodeKind::SubExpr
:
1109 case ParseNodeKind::MulExpr
:
1110 case ParseNodeKind::DivExpr
:
1111 case ParseNodeKind::ModExpr
:
1112 case ParseNodeKind::PowExpr
:
1113 MOZ_ASSERT(pn
->as
<ListNode
>().count() >= 2);
1117 case ParseNodeKind::PropertyDefinition
:
1118 case ParseNodeKind::Case
: {
1119 BinaryNode
* node
= &pn
->as
<BinaryNode
>();
1120 if (!checkSideEffects(node
->left(), answer
)) {
1126 return checkSideEffects(node
->right(), answer
);
1130 case ParseNodeKind::ElemExpr
:
1131 case ParseNodeKind::OptionalElemExpr
:
1132 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1136 // Throws if the operand is not of the right class. Can also call a private
1138 case ParseNodeKind::PrivateMemberExpr
:
1139 case ParseNodeKind::OptionalPrivateMemberExpr
:
1143 // These affect visible names in this code, or in other code.
1144 case ParseNodeKind::ImportDecl
:
1145 case ParseNodeKind::ExportFromStmt
:
1146 case ParseNodeKind::ExportDefaultStmt
:
1147 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1152 case ParseNodeKind::ExportStmt
:
1153 MOZ_ASSERT(pn
->is
<UnaryNode
>());
1157 case ParseNodeKind::CallImportExpr
:
1158 case ParseNodeKind::CallImportSpec
:
1159 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1163 // Every part of a loop might be effect-free, but looping infinitely *is*
1164 // an effect. (Language lawyer trivia: C++ says threads can be assumed
1165 // to exit or have side effects, C++14 [intro.multithread]p27, so a C++
1166 // implementation's equivalent of the below could set |*answer = false;|
1167 // if all loop sub-nodes set |*answer = false|!)
1168 case ParseNodeKind::DoWhileStmt
:
1169 case ParseNodeKind::WhileStmt
:
1170 case ParseNodeKind::ForStmt
:
1171 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1175 // Declarations affect the name set of the relevant scope.
1176 case ParseNodeKind::VarStmt
:
1177 case ParseNodeKind::ConstDecl
:
1178 case ParseNodeKind::LetDecl
:
1179 MOZ_ASSERT(pn
->is
<ListNode
>());
1183 case ParseNodeKind::IfStmt
:
1184 case ParseNodeKind::ConditionalExpr
: {
1185 TernaryNode
* node
= &pn
->as
<TernaryNode
>();
1186 if (!checkSideEffects(node
->kid1(), answer
)) {
1192 if (!checkSideEffects(node
->kid2(), answer
)) {
1198 if ((pn
= node
->kid3())) {
1204 // Function calls can invoke non-local code.
1205 case ParseNodeKind::NewExpr
:
1206 case ParseNodeKind::CallExpr
:
1207 case ParseNodeKind::OptionalCallExpr
:
1208 case ParseNodeKind::TaggedTemplateExpr
:
1209 case ParseNodeKind::SuperCallExpr
:
1210 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1214 // Function arg lists can contain arbitrary expressions. Technically
1215 // this only causes side-effects if one of the arguments does, but since
1216 // the call being made will always trigger side-effects, it isn't needed.
1217 case ParseNodeKind::Arguments
:
1218 MOZ_ASSERT(pn
->is
<ListNode
>());
1222 case ParseNodeKind::OptionalChain
:
1223 MOZ_ASSERT(pn
->is
<UnaryNode
>());
1227 // Classes typically introduce names. Even if no name is introduced,
1228 // the heritage and/or class body (through computed property names)
1229 // usually have effects.
1230 case ParseNodeKind::ClassDecl
:
1231 MOZ_ASSERT(pn
->is
<ClassNode
>());
1235 // |with| calls |ToObject| on its expression and so throws if that value
1236 // is null/undefined.
1237 case ParseNodeKind::WithStmt
:
1238 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1242 case ParseNodeKind::ReturnStmt
:
1243 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1247 case ParseNodeKind::Name
:
1248 MOZ_ASSERT(pn
->is
<NameNode
>());
1252 // Shorthands could trigger getters: the |x| in the object literal in
1253 // |with ({ get x() { throw 42; } }) ({ x });|, for example, triggers
1254 // one. (Of course, it isn't necessary to use |with| for a shorthand to
1255 // trigger a getter.)
1256 case ParseNodeKind::Shorthand
:
1257 MOZ_ASSERT(pn
->is
<BinaryNode
>());
1261 case ParseNodeKind::Function
:
1262 MOZ_ASSERT(pn
->is
<FunctionNode
>());
1264 * A named function, contrary to ES3, is no longer effectful, because
1265 * we bind its name lexically (using JSOp::Callee) instead of creating
1266 * an Object instance and binding a readonly, permanent property in it
1267 * (the object and binding can be detected and hijacked or captured).
1268 * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
1273 case ParseNodeKind::Module
:
1277 case ParseNodeKind::TryStmt
: {
1278 TryNode
* tryNode
= &pn
->as
<TryNode
>();
1279 if (!checkSideEffects(tryNode
->body(), answer
)) {
1285 if (LexicalScopeNode
* catchScope
= tryNode
->catchScope()) {
1286 if (!checkSideEffects(catchScope
, answer
)) {
1293 if (ParseNode
* finallyBlock
= tryNode
->finallyBlock()) {
1294 if (!checkSideEffects(finallyBlock
, answer
)) {
1301 case ParseNodeKind::Catch
: {
1302 BinaryNode
* catchClause
= &pn
->as
<BinaryNode
>();
1303 if (ParseNode
* name
= catchClause
->left()) {
1304 if (!checkSideEffects(name
, answer
)) {
1311 return checkSideEffects(catchClause
->right(), answer
);
1314 case ParseNodeKind::SwitchStmt
: {
1315 SwitchStatement
* switchStmt
= &pn
->as
<SwitchStatement
>();
1316 if (!checkSideEffects(&switchStmt
->discriminant(), answer
)) {
1320 checkSideEffects(&switchStmt
->lexicalForCaseList(), answer
);
1323 case ParseNodeKind::LabelStmt
:
1324 return checkSideEffects(pn
->as
<LabeledStatement
>().statement(), answer
);
1326 case ParseNodeKind::LexicalScope
:
1327 return checkSideEffects(pn
->as
<LexicalScopeNode
>().scopeBody(), answer
);
1329 // We could methodically check every interpolated expression, but it's
1330 // probably not worth the trouble. Treat template strings as effect-free
1331 // only if they don't contain any substitutions.
1332 case ParseNodeKind::TemplateStringListExpr
: {
1333 ListNode
* list
= &pn
->as
<ListNode
>();
1334 MOZ_ASSERT(!list
->empty());
1335 MOZ_ASSERT((list
->count() % 2) == 1,
1336 "template strings must alternate template and substitution "
1338 *answer
= list
->count() > 1;
1342 // This should be unreachable but is left as-is for now.
1343 case ParseNodeKind::ParamsBody
:
1347 case ParseNodeKind::ForIn
: // by ParseNodeKind::For
1348 case ParseNodeKind::ForOf
: // by ParseNodeKind::For
1349 case ParseNodeKind::ForHead
: // by ParseNodeKind::For
1350 case ParseNodeKind::DefaultConstructor
: // by ParseNodeKind::ClassDecl
1351 case ParseNodeKind::ClassBodyScope
: // by ParseNodeKind::ClassDecl
1352 case ParseNodeKind::ClassMethod
: // by ParseNodeKind::ClassDecl
1353 case ParseNodeKind::ClassField
: // by ParseNodeKind::ClassDecl
1354 case ParseNodeKind::ClassNames
: // by ParseNodeKind::ClassDecl
1355 case ParseNodeKind::StaticClassBlock
: // by ParseNodeKind::ClassDecl
1356 case ParseNodeKind::ClassMemberList
: // by ParseNodeKind::ClassDecl
1357 case ParseNodeKind::ImportSpecList
: // by ParseNodeKind::Import
1358 case ParseNodeKind::ImportSpec
: // by ParseNodeKind::Import
1359 case ParseNodeKind::ImportNamespaceSpec
: // by ParseNodeKind::Import
1360 case ParseNodeKind::ImportAssertion
: // by ParseNodeKind::Import
1361 case ParseNodeKind::ImportAssertionList
: // by ParseNodeKind::Import
1362 case ParseNodeKind::ImportModuleRequest
: // by ParseNodeKind::Import
1363 case ParseNodeKind::ExportBatchSpecStmt
: // by ParseNodeKind::Export
1364 case ParseNodeKind::ExportSpecList
: // by ParseNodeKind::Export
1365 case ParseNodeKind::ExportSpec
: // by ParseNodeKind::Export
1366 case ParseNodeKind::ExportNamespaceSpec
: // by ParseNodeKind::Export
1367 case ParseNodeKind::CallSiteObj
: // by ParseNodeKind::TaggedTemplate
1368 case ParseNodeKind::PosHolder
: // by ParseNodeKind::NewTarget
1369 case ParseNodeKind::SuperBase
: // by ParseNodeKind::Elem and others
1370 case ParseNodeKind::PropertyNameExpr
: // by ParseNodeKind::Dot
1371 MOZ_CRASH("handled by parent nodes");
1373 case ParseNodeKind::LastUnused
:
1374 case ParseNodeKind::Limit
:
1375 MOZ_CRASH("invalid node kind");
1379 "invalid, unenumerated ParseNodeKind value encountered in "
1380 "BytecodeEmitter::checkSideEffects");
1383 bool BytecodeEmitter::isInLoop() {
1384 return findInnermostNestableControl
<LoopControl
>();
1387 bool BytecodeEmitter::checkSingletonContext() {
1388 MOZ_ASSERT_IF(sc
->treatAsRunOnce(), sc
->isTopLevelContext());
1389 return sc
->treatAsRunOnce() && !isInLoop();
1392 bool BytecodeEmitter::needsImplicitThis() {
1393 // Short-circuit if there is an enclosing 'with' scope.
1398 // Otherwise see if the current point is under a 'with'.
1399 for (EmitterScope
* es
= innermostEmitterScope(); es
;
1400 es
= es
->enclosingInFrame()) {
1401 if (es
->scope(this).kind() == ScopeKind::With
) {
1409 size_t BytecodeEmitter::countThisEnvironmentHops() {
1410 unsigned numHops
= 0;
1412 for (BytecodeEmitter
* current
= this; current
; current
= current
->parent
) {
1413 for (EmitterScope
* es
= current
->innermostEmitterScope(); es
;
1414 es
= es
->enclosingInFrame()) {
1415 if (es
->scope(current
).is
<FunctionScope
>()) {
1416 if (!es
->scope(current
).isArrow()) {
1417 // The Parser is responsible for marking the environment as either
1418 // closed-over or used-by-eval which ensure that is must exist.
1419 MOZ_ASSERT(es
->scope(current
).hasEnvironment());
1423 if (es
->scope(current
).hasEnvironment()) {
1429 // The "this" environment exists outside of the compilation, but the
1430 // `ScopeContext` recorded the number of additional hops needed, so add
1432 MOZ_ASSERT(sc
->allowSuperProperty());
1433 numHops
+= compilationState
.scopeContext
.enclosingThisEnvironmentHops
;
1437 bool BytecodeEmitter::emitThisEnvironmentCallee() {
1438 // Get the innermost enclosing function that has a |this| binding.
1440 // Directly load callee from the frame if possible.
1441 if (sc
->isFunctionBox() && !sc
->asFunctionBox()->isArrow()) {
1442 return emit1(JSOp::Callee
);
1445 // We have to load the callee from the environment chain.
1446 size_t numHops
= countThisEnvironmentHops();
1449 ENVCOORD_HOPS_LIMIT
- 1 <= UINT8_MAX
,
1450 "JSOp::EnvCallee operand size should match ENVCOORD_HOPS_LIMIT");
1452 MOZ_ASSERT(numHops
< ENVCOORD_HOPS_LIMIT
- 1);
1454 return emit2(JSOp::EnvCallee
, numHops
);
1457 bool BytecodeEmitter::emitSuperBase() {
1458 if (!emitThisEnvironmentCallee()) {
1462 return emit1(JSOp::SuperBase
);
1465 void BytecodeEmitter::reportError(ParseNode
* pn
, unsigned errorNumber
, ...) {
1466 uint32_t offset
= pn
? pn
->pn_pos
.begin
: *scriptStartOffset
;
1469 va_start(args
, errorNumber
);
1471 errorReporter().errorWithNotesAtVA(nullptr, AsVariant(offset
), errorNumber
,
1477 void BytecodeEmitter::reportError(uint32_t offset
, unsigned errorNumber
, ...) {
1479 va_start(args
, errorNumber
);
1481 errorReporter().errorWithNotesAtVA(nullptr, AsVariant(offset
), errorNumber
,
1487 bool BytecodeEmitter::addObjLiteralData(ObjLiteralWriter
& writer
,
1488 GCThingIndex
* outIndex
) {
1489 if (!writer
.checkForDuplicatedNames(fc
)) {
1493 size_t len
= writer
.getCode().size();
1494 auto* code
= compilationState
.alloc
.newArrayUninitialized
<uint8_t>(len
);
1496 js::ReportOutOfMemory(fc
);
1499 memcpy(code
, writer
.getCode().data(), len
);
1501 ObjLiteralIndex
objIndex(compilationState
.objLiteralData
.length());
1502 if (uint32_t(objIndex
) >= TaggedScriptThingIndex::IndexLimit
) {
1503 ReportAllocationOverflow(fc
);
1506 if (!compilationState
.objLiteralData
.emplaceBack(code
, len
, writer
.getKind(),
1508 writer
.getPropertyCount())) {
1509 js::ReportOutOfMemory(fc
);
1513 return perScriptData().gcThingList().append(objIndex
, outIndex
);
1516 bool BytecodeEmitter::emitPrepareIteratorResult() {
1517 constexpr JSOp op
= JSOp::NewObject
;
1519 ObjLiteralWriter writer
;
1520 writer
.beginShape(op
);
1522 writer
.setPropNameNoDuplicateCheck(parserAtoms(),
1523 TaggedParserAtomIndex::WellKnown::value());
1524 if (!writer
.propWithUndefinedValue(fc
)) {
1527 writer
.setPropNameNoDuplicateCheck(parserAtoms(),
1528 TaggedParserAtomIndex::WellKnown::done());
1529 if (!writer
.propWithUndefinedValue(fc
)) {
1534 if (!addObjLiteralData(writer
, &shape
)) {
1538 return emitGCIndexOp(op
, shape
);
1541 bool BytecodeEmitter::emitFinishIteratorResult(bool done
) {
1542 if (!emitAtomOp(JSOp::InitProp
, TaggedParserAtomIndex::WellKnown::value())) {
1545 if (!emit1(done
? JSOp::True
: JSOp::False
)) {
1548 if (!emitAtomOp(JSOp::InitProp
, TaggedParserAtomIndex::WellKnown::done())) {
1554 bool BytecodeEmitter::emitGetNameAtLocation(TaggedParserAtomIndex name
,
1555 const NameLocation
& loc
) {
1556 NameOpEmitter
noe(this, name
, loc
, NameOpEmitter::Kind::Get
);
1557 if (!noe
.emitGet()) {
1564 bool BytecodeEmitter::emitGetName(NameNode
* name
) {
1565 MOZ_ASSERT(name
->isKind(ParseNodeKind::Name
));
1567 return emitGetName(name
->name());
1570 bool BytecodeEmitter::emitGetPrivateName(NameNode
* name
) {
1571 MOZ_ASSERT(name
->isKind(ParseNodeKind::PrivateName
));
1572 return emitGetPrivateName(name
->name());
1575 bool BytecodeEmitter::emitGetPrivateName(TaggedParserAtomIndex nameAtom
) {
1576 // The parser ensures the private name is present on the environment chain,
1577 // but its location can be Dynamic or Global when emitting debugger
1578 // eval-in-frame code.
1579 NameLocation location
= lookupName(nameAtom
);
1580 MOZ_ASSERT(location
.kind() == NameLocation::Kind::FrameSlot
||
1581 location
.kind() == NameLocation::Kind::EnvironmentCoordinate
||
1582 location
.kind() == NameLocation::Kind::Dynamic
||
1583 location
.kind() == NameLocation::Kind::Global
);
1585 return emitGetNameAtLocation(nameAtom
, location
);
1588 bool BytecodeEmitter::emitTDZCheckIfNeeded(TaggedParserAtomIndex name
,
1589 const NameLocation
& loc
,
1590 ValueIsOnStack isOnStack
) {
1591 // Dynamic accesses have TDZ checks built into their VM code and should
1592 // never emit explicit TDZ checks.
1593 MOZ_ASSERT(loc
.hasKnownSlot());
1594 MOZ_ASSERT(loc
.isLexical() || loc
.isPrivateMethod() || loc
.isSynthetic());
1596 // Private names are implemented as lexical bindings, but it's just an
1597 // implementation detail. Per spec there's no TDZ check when using them.
1598 if (parserAtoms().isPrivateName(name
)) {
1602 Maybe
<MaybeCheckTDZ
> check
=
1603 innermostTDZCheckCache
->needsTDZCheck(this, name
);
1608 // We've already emitted a check in this basic block.
1609 if (*check
== DontCheckTDZ
) {
1613 // If the value is not on the stack, we have to load it first.
1614 if (isOnStack
== ValueIsOnStack::No
) {
1615 if (loc
.kind() == NameLocation::Kind::FrameSlot
) {
1616 if (!emitLocalOp(JSOp::GetLocal
, loc
.frameSlot())) {
1620 if (!emitEnvCoordOp(JSOp::GetAliasedVar
, loc
.environmentCoordinate())) {
1626 // Emit the lexical check.
1627 if (loc
.kind() == NameLocation::Kind::FrameSlot
) {
1628 if (!emitLocalOp(JSOp::CheckLexical
, loc
.frameSlot())) {
1632 if (!emitEnvCoordOp(JSOp::CheckAliasedLexical
,
1633 loc
.environmentCoordinate())) {
1638 // Pop the value if needed.
1639 if (isOnStack
== ValueIsOnStack::No
) {
1640 if (!emit1(JSOp::Pop
)) {
1645 return innermostTDZCheckCache
->noteTDZCheck(this, name
, DontCheckTDZ
);
1648 bool BytecodeEmitter::emitPropLHS(PropertyAccess
* prop
) {
1649 MOZ_ASSERT(!prop
->isSuper());
1651 ParseNode
* expr
= &prop
->expression();
1653 if (!expr
->is
<PropertyAccess
>() || expr
->as
<PropertyAccess
>().isSuper()) {
1654 // The non-optimized case.
1655 return emitTree(expr
);
1658 // If the object operand is also a dotted property reference, reverse the
1659 // list linked via expression() temporarily so we can iterate over it from
1660 // the bottom up (reversing again as we go), to avoid excessive recursion.
1661 PropertyAccess
* pndot
= &expr
->as
<PropertyAccess
>();
1662 ParseNode
* pnup
= nullptr;
1665 // Reverse pndot->expression() to point up, not down.
1666 pndown
= &pndot
->expression();
1667 pndot
->setExpression(pnup
);
1668 if (!pndown
->is
<PropertyAccess
>() ||
1669 pndown
->as
<PropertyAccess
>().isSuper()) {
1673 pndot
= &pndown
->as
<PropertyAccess
>();
1676 // pndown is a primary expression, not a dotted property reference.
1677 if (!emitTree(pndown
)) {
1682 // Walk back up the list, emitting annotated name ops.
1683 if (!emitAtomOp(JSOp::GetProp
, pndot
->key().atom())) {
1687 // Reverse the pndot->expression() link again.
1688 pnup
= pndot
->maybeExpression();
1689 pndot
->setExpression(pndown
);
1694 pndot
= &pnup
->as
<PropertyAccess
>();
1699 bool BytecodeEmitter::emitPropIncDec(UnaryNode
* incDec
, ValueUsage valueUsage
) {
1700 PropertyAccess
* prop
= &incDec
->kid()->as
<PropertyAccess
>();
1701 bool isSuper
= prop
->isSuper();
1702 ParseNodeKind kind
= incDec
->getKind();
1705 kind
== ParseNodeKind::PostIncrementExpr
1706 ? PropOpEmitter::Kind::PostIncrement
1707 : kind
== ParseNodeKind::PreIncrementExpr
1708 ? PropOpEmitter::Kind::PreIncrement
1709 : kind
== ParseNodeKind::PostDecrementExpr
1710 ? PropOpEmitter::Kind::PostDecrement
1711 : PropOpEmitter::Kind::PreDecrement
,
1712 isSuper
? PropOpEmitter::ObjKind::Super
: PropOpEmitter::ObjKind::Other
);
1713 if (!poe
.prepareForObj()) {
1717 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
1718 if (!emitGetThisForSuperBase(base
)) {
1723 if (!emitPropLHS(prop
)) {
1728 if (!poe
.emitIncDec(prop
->key().atom(), valueUsage
)) {
1736 bool BytecodeEmitter::emitNameIncDec(UnaryNode
* incDec
, ValueUsage valueUsage
) {
1737 MOZ_ASSERT(incDec
->kid()->isKind(ParseNodeKind::Name
));
1739 ParseNodeKind kind
= incDec
->getKind();
1740 NameNode
* name
= &incDec
->kid()->as
<NameNode
>();
1741 NameOpEmitter
noe(this, name
->atom(),
1742 kind
== ParseNodeKind::PostIncrementExpr
1743 ? NameOpEmitter::Kind::PostIncrement
1744 : kind
== ParseNodeKind::PreIncrementExpr
1745 ? NameOpEmitter::Kind::PreIncrement
1746 : kind
== ParseNodeKind::PostDecrementExpr
1747 ? NameOpEmitter::Kind::PostDecrement
1748 : NameOpEmitter::Kind::PreDecrement
);
1749 if (!noe
.emitIncDec(valueUsage
)) {
1756 bool BytecodeEmitter::emitObjAndKey(ParseNode
* exprOrSuper
, ParseNode
* key
,
1757 ElemOpEmitter
& eoe
) {
1758 if (exprOrSuper
->isKind(ParseNodeKind::SuperBase
)) {
1759 if (!eoe
.prepareForObj()) {
1763 UnaryNode
* base
= &exprOrSuper
->as
<UnaryNode
>();
1764 if (!emitGetThisForSuperBase(base
)) {
1768 if (!eoe
.prepareForKey()) {
1772 if (!emitTree(key
)) {
1780 if (!eoe
.prepareForObj()) {
1784 if (!emitTree(exprOrSuper
)) {
1788 if (!eoe
.prepareForKey()) {
1792 if (!emitTree(key
)) {
1793 // [stack] OBJ? OBJ KEY
1800 bool BytecodeEmitter::emitElemOpBase(JSOp op
) {
1808 bool BytecodeEmitter::emitElemObjAndKey(PropertyByValue
* elem
, bool isSuper
,
1809 ElemOpEmitter
& eoe
) {
1810 MOZ_ASSERT(isSuper
== elem
->expression().isKind(ParseNodeKind::SuperBase
));
1811 return emitObjAndKey(&elem
->expression(), &elem
->key(), eoe
);
1814 static ElemOpEmitter::Kind
ConvertIncDecKind(ParseNodeKind kind
) {
1816 case ParseNodeKind::PostIncrementExpr
:
1817 return ElemOpEmitter::Kind::PostIncrement
;
1818 case ParseNodeKind::PreIncrementExpr
:
1819 return ElemOpEmitter::Kind::PreIncrement
;
1820 case ParseNodeKind::PostDecrementExpr
:
1821 return ElemOpEmitter::Kind::PostDecrement
;
1822 case ParseNodeKind::PreDecrementExpr
:
1823 return ElemOpEmitter::Kind::PreDecrement
;
1825 MOZ_CRASH("unexpected inc/dec node kind");
1829 static PrivateOpEmitter::Kind
PrivateConvertIncDecKind(ParseNodeKind kind
) {
1831 case ParseNodeKind::PostIncrementExpr
:
1832 return PrivateOpEmitter::Kind::PostIncrement
;
1833 case ParseNodeKind::PreIncrementExpr
:
1834 return PrivateOpEmitter::Kind::PreIncrement
;
1835 case ParseNodeKind::PostDecrementExpr
:
1836 return PrivateOpEmitter::Kind::PostDecrement
;
1837 case ParseNodeKind::PreDecrementExpr
:
1838 return PrivateOpEmitter::Kind::PreDecrement
;
1840 MOZ_CRASH("unexpected inc/dec node kind");
1844 bool BytecodeEmitter::emitElemIncDec(UnaryNode
* incDec
, ValueUsage valueUsage
) {
1845 PropertyByValue
* elemExpr
= &incDec
->kid()->as
<PropertyByValue
>();
1846 bool isSuper
= elemExpr
->isSuper();
1847 MOZ_ASSERT(!elemExpr
->key().isKind(ParseNodeKind::PrivateName
));
1848 ParseNodeKind kind
= incDec
->getKind();
1850 this, ConvertIncDecKind(kind
),
1851 isSuper
? ElemOpEmitter::ObjKind::Super
: ElemOpEmitter::ObjKind::Other
);
1852 if (!emitElemObjAndKey(elemExpr
, isSuper
, eoe
)) {
1853 // [stack] # if Super
1855 // [stack] # otherwise
1859 if (!eoe
.emitIncDec(valueUsage
)) {
1867 bool BytecodeEmitter::emitCallIncDec(UnaryNode
* incDec
) {
1868 MOZ_ASSERT(incDec
->isKind(ParseNodeKind::PreIncrementExpr
) ||
1869 incDec
->isKind(ParseNodeKind::PostIncrementExpr
) ||
1870 incDec
->isKind(ParseNodeKind::PreDecrementExpr
) ||
1871 incDec
->isKind(ParseNodeKind::PostDecrementExpr
));
1873 ParseNode
* call
= incDec
->kid();
1874 MOZ_ASSERT(call
->isKind(ParseNodeKind::CallExpr
));
1875 if (!emitTree(call
)) {
1876 // [stack] CALLRESULT
1879 if (!emit1(JSOp::ToNumeric
)) {
1884 // The increment/decrement has no side effects, so proceed to throw for
1885 // invalid assignment target.
1886 return emit2(JSOp::ThrowMsg
, uint8_t(ThrowMsgKind::AssignToCall
));
1889 bool BytecodeEmitter::emitPrivateIncDec(UnaryNode
* incDec
,
1890 ValueUsage valueUsage
) {
1891 PrivateMemberAccess
* privateExpr
= &incDec
->kid()->as
<PrivateMemberAccess
>();
1892 ParseNodeKind kind
= incDec
->getKind();
1893 PrivateOpEmitter
xoe(this, PrivateConvertIncDecKind(kind
),
1894 privateExpr
->privateName().name());
1895 if (!emitTree(&privateExpr
->expression())) {
1899 if (!xoe
.emitReference()) {
1903 if (!xoe
.emitIncDec(valueUsage
)) {
1911 bool BytecodeEmitter::emitDouble(double d
) {
1912 BytecodeOffset offset
;
1913 if (!emitCheck(JSOp::Double
, 9, &offset
)) {
1917 jsbytecode
* code
= bytecodeSection().code(offset
);
1918 code
[0] = jsbytecode(JSOp::Double
);
1919 SET_INLINE_VALUE(code
, DoubleValue(d
));
1920 bytecodeSection().updateDepth(JSOp::Double
, offset
);
1924 bool BytecodeEmitter::emitNumberOp(double dval
) {
1926 if (NumberIsInt32(dval
, &ival
)) {
1928 return emit1(JSOp::Zero
);
1931 return emit1(JSOp::One
);
1933 if ((int)(int8_t)ival
== ival
) {
1934 return emit2(JSOp::Int8
, uint8_t(int8_t(ival
)));
1937 uint32_t u
= uint32_t(ival
);
1939 if (!emitUint16Operand(JSOp::Uint16
, u
)) {
1942 } else if (u
< Bit(24)) {
1944 if (!emitN(JSOp::Uint24
, 3, &off
)) {
1947 SET_UINT24(bytecodeSection().code(off
), u
);
1950 if (!emitN(JSOp::Int32
, 4, &off
)) {
1953 SET_INT32(bytecodeSection().code(off
), ival
);
1958 return emitDouble(dval
);
1962 * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047.
1963 * LLVM is deciding to inline this function which uses a lot of stack space
1964 * into emitTree which is recursive and uses relatively little stack space.
1966 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitSwitch(SwitchStatement
* switchStmt
) {
1967 LexicalScopeNode
& lexical
= switchStmt
->lexicalForCaseList();
1968 MOZ_ASSERT(lexical
.isKind(ParseNodeKind::LexicalScope
));
1969 ListNode
* cases
= &lexical
.scopeBody()->as
<ListNode
>();
1970 MOZ_ASSERT(cases
->isKind(ParseNodeKind::StatementList
));
1972 SwitchEmitter
se(this);
1973 if (!se
.emitDiscriminant(switchStmt
->discriminant().pn_pos
.begin
)) {
1977 if (!markStepBreakpoint()) {
1980 if (!emitTree(&switchStmt
->discriminant())) {
1984 // Enter the scope before pushing the switch BreakableControl since all
1985 // breaks are under this scope.
1987 if (!lexical
.isEmptyScope()) {
1988 if (!se
.emitLexical(lexical
.scopeBindings())) {
1992 // A switch statement may contain hoisted functions inside its
1993 // cases. The hasTopLevelFunctionDeclarations flag is propagated from the
1994 // StatementList bodies of the cases to the case list.
1995 if (cases
->hasTopLevelFunctionDeclarations()) {
1996 for (ParseNode
* item
: cases
->contents()) {
1997 CaseClause
* caseClause
= &item
->as
<CaseClause
>();
1998 ListNode
* statements
= caseClause
->statementList();
1999 if (statements
->hasTopLevelFunctionDeclarations()) {
2000 if (!emitHoistedFunctionsInList(statements
)) {
2007 MOZ_ASSERT(!cases
->hasTopLevelFunctionDeclarations());
2010 SwitchEmitter::TableGenerator
tableGen(this);
2011 uint32_t caseCount
= cases
->count() - (switchStmt
->hasDefault() ? 1 : 0);
2012 if (caseCount
== 0) {
2015 for (ParseNode
* item
: cases
->contents()) {
2016 CaseClause
* caseClause
= &item
->as
<CaseClause
>();
2017 if (caseClause
->isDefault()) {
2021 ParseNode
* caseValue
= caseClause
->caseExpression();
2023 if (caseValue
->getKind() != ParseNodeKind::NumberExpr
) {
2024 tableGen
.setInvalid();
2029 if (!NumberEqualsInt32(caseValue
->as
<NumericLiteral
>().value(), &i
)) {
2030 tableGen
.setInvalid();
2034 if (!tableGen
.addNumber(i
)) {
2039 tableGen
.finish(caseCount
);
2042 if (!se
.validateCaseCount(caseCount
)) {
2046 bool isTableSwitch
= tableGen
.isValid();
2047 if (isTableSwitch
) {
2048 if (!se
.emitTable(tableGen
)) {
2052 if (!se
.emitCond()) {
2056 // Emit code for evaluating cases and jumping to case statements.
2057 for (ParseNode
* item
: cases
->contents()) {
2058 CaseClause
* caseClause
= &item
->as
<CaseClause
>();
2059 if (caseClause
->isDefault()) {
2063 if (!se
.prepareForCaseValue()) {
2067 ParseNode
* caseValue
= caseClause
->caseExpression();
2068 // If the expression is a literal, suppress line number emission so
2069 // that debugging works more naturally.
2071 caseValue
, ValueUsage::WantValue
,
2072 caseValue
->isLiteral() ? SUPPRESS_LINENOTE
: EMIT_LINENOTE
)) {
2076 if (!se
.emitCaseJump()) {
2082 // Emit code for each case's statements.
2083 for (ParseNode
* item
: cases
->contents()) {
2084 CaseClause
* caseClause
= &item
->as
<CaseClause
>();
2085 if (caseClause
->isDefault()) {
2086 if (!se
.emitDefaultBody()) {
2090 if (isTableSwitch
) {
2091 ParseNode
* caseValue
= caseClause
->caseExpression();
2092 MOZ_ASSERT(caseValue
->isKind(ParseNodeKind::NumberExpr
));
2094 NumericLiteral
* literal
= &caseValue
->as
<NumericLiteral
>();
2096 // Use NumberEqualsInt32 here because switches compare using
2097 // strict equality, which will equate -0 and +0. In contrast
2098 // NumberIsInt32 would return false for -0.
2100 MOZ_ASSERT(mozilla::NumberEqualsInt32(literal
->value(), &v
));
2102 int32_t i
= int32_t(literal
->value());
2104 if (!se
.emitCaseBody(i
, tableGen
)) {
2108 if (!se
.emitCaseBody()) {
2114 if (!emitTree(caseClause
->statementList())) {
2119 if (!se
.emitEnd()) {
2126 bool BytecodeEmitter::allocateResumeIndex(BytecodeOffset offset
,
2127 uint32_t* resumeIndex
) {
2128 static constexpr uint32_t MaxResumeIndex
= BitMask(24);
2131 MaxResumeIndex
< uint32_t(AbstractGeneratorObject::RESUME_INDEX_RUNNING
),
2132 "resumeIndex should not include magic AbstractGeneratorObject "
2133 "resumeIndex values");
2135 MaxResumeIndex
<= INT32_MAX
/ sizeof(uintptr_t),
2136 "resumeIndex * sizeof(uintptr_t) must fit in an int32. JIT code relies "
2137 "on this when loading resume entries from BaselineScript");
2139 *resumeIndex
= bytecodeSection().resumeOffsetList().length();
2140 if (*resumeIndex
> MaxResumeIndex
) {
2141 reportError(nullptr, JSMSG_TOO_MANY_RESUME_INDEXES
);
2145 return bytecodeSection().resumeOffsetList().append(offset
.value());
2148 bool BytecodeEmitter::allocateResumeIndexRange(
2149 mozilla::Span
<BytecodeOffset
> offsets
, uint32_t* firstResumeIndex
) {
2150 *firstResumeIndex
= 0;
2152 for (size_t i
= 0, len
= offsets
.size(); i
< len
; i
++) {
2153 uint32_t resumeIndex
;
2154 if (!allocateResumeIndex(offsets
[i
], &resumeIndex
)) {
2158 *firstResumeIndex
= resumeIndex
;
2165 bool BytecodeEmitter::emitYieldOp(JSOp op
) {
2166 if (op
== JSOp::FinalYieldRval
) {
2167 return emit1(JSOp::FinalYieldRval
);
2170 MOZ_ASSERT(op
== JSOp::InitialYield
|| op
== JSOp::Yield
||
2174 if (!emitN(op
, 3, &off
)) {
2178 if (op
== JSOp::InitialYield
|| op
== JSOp::Yield
) {
2179 bytecodeSection().addNumYields();
2182 uint32_t resumeIndex
;
2183 if (!allocateResumeIndex(bytecodeSection().offset(), &resumeIndex
)) {
2187 SET_RESUMEINDEX(bytecodeSection().code(off
), resumeIndex
);
2189 BytecodeOffset unusedOffset
;
2190 return emitJumpTargetOp(JSOp::AfterYield
, &unusedOffset
);
2193 bool BytecodeEmitter::emitPushResumeKind(GeneratorResumeKind kind
) {
2194 return emit2(JSOp::ResumeKind
, uint8_t(kind
));
2197 bool BytecodeEmitter::emitSetThis(BinaryNode
* setThisNode
) {
2198 // ParseNodeKind::SetThis is used to update |this| after a super() call
2199 // in a derived class constructor.
2201 MOZ_ASSERT(setThisNode
->isKind(ParseNodeKind::SetThis
));
2202 MOZ_ASSERT(setThisNode
->left()->isKind(ParseNodeKind::Name
));
2204 auto name
= setThisNode
->left()->as
<NameNode
>().name();
2206 // The 'this' binding is not lexical, but due to super() semantics this
2207 // initialization needs to be treated as a lexical one.
2208 NameLocation loc
= lookupName(name
);
2209 NameLocation lexicalLoc
;
2210 if (loc
.kind() == NameLocation::Kind::FrameSlot
) {
2211 lexicalLoc
= NameLocation::FrameSlot(BindingKind::Let
, loc
.frameSlot());
2212 } else if (loc
.kind() == NameLocation::Kind::EnvironmentCoordinate
) {
2213 EnvironmentCoordinate coord
= loc
.environmentCoordinate();
2214 uint8_t hops
= AssertedCast
<uint8_t>(coord
.hops());
2215 lexicalLoc
= NameLocation::EnvironmentCoordinate(BindingKind::Let
, hops
,
2218 MOZ_ASSERT(loc
.kind() == NameLocation::Kind::Dynamic
);
2222 NameOpEmitter
noe(this, name
, lexicalLoc
, NameOpEmitter::Kind::Initialize
);
2223 if (!noe
.prepareForRhs()) {
2228 // Emit the new |this| value.
2229 if (!emitTree(setThisNode
->right())) {
2234 // Get the original |this| and throw if we already initialized
2235 // it. Do *not* use the NameLocation argument, as that's the special
2236 // lexical location below to deal with super() semantics.
2237 if (!emitGetName(name
)) {
2238 // [stack] NEWTHIS THIS
2241 if (!emit1(JSOp::CheckThisReinit
)) {
2242 // [stack] NEWTHIS THIS
2245 if (!emit1(JSOp::Pop
)) {
2249 if (!noe
.emitAssignment()) {
2254 if (!emitInitializeInstanceMembers(true)) {
2261 bool BytecodeEmitter::defineHoistedTopLevelFunctions(ParseNode
* body
) {
2262 MOZ_ASSERT(inPrologue());
2263 MOZ_ASSERT(sc
->isGlobalContext() || (sc
->isEvalContext() && !sc
->strict()));
2264 MOZ_ASSERT(body
->is
<LexicalScopeNode
>() || body
->is
<ListNode
>());
2266 if (body
->is
<LexicalScopeNode
>()) {
2267 body
= body
->as
<LexicalScopeNode
>().scopeBody();
2268 MOZ_ASSERT(body
->is
<ListNode
>());
2271 if (!body
->as
<ListNode
>().hasTopLevelFunctionDeclarations()) {
2275 return emitHoistedFunctionsInList(&body
->as
<ListNode
>());
2278 // For Global and sloppy-Eval scripts, this performs most of the steps of the
2279 // spec's [GlobalDeclarationInstantiation] and [EvalDeclarationInstantiation]
2282 // Note that while strict-Eval is handled in the same part of the spec, it never
2283 // fails for global-redeclaration checks so those scripts initialize directly in
2285 bool BytecodeEmitter::emitDeclarationInstantiation(ParseNode
* body
) {
2286 if (sc
->isModuleContext()) {
2287 // ES Modules have dedicated variable and lexial environments and therefore
2288 // do not have to perform redeclaration checks. We initialize their bindings
2289 // elsewhere in bytecode.
2293 if (sc
->isEvalContext() && sc
->strict()) {
2294 // Strict Eval has a dedicated variables (and lexical) environment and
2295 // therefore does not have to perform redeclaration checks. We initialize
2296 // their bindings elsewhere in the bytecode.
2300 // If we have no variables bindings, then we are done!
2301 if (sc
->isGlobalContext()) {
2302 if (!sc
->asGlobalContext()->bindings
) {
2306 MOZ_ASSERT(sc
->isEvalContext());
2308 if (!sc
->asEvalContext()->bindings
) {
2314 // There should be no emitted functions yet.
2315 for (const auto& thing
: perScriptData().gcThingList().objects()) {
2316 MOZ_ASSERT(thing
.isEmptyGlobalScope() || thing
.isScope());
2320 // Emit the hoisted functions to gc-things list. There is no bytecode
2321 // generated yet to bind them.
2322 if (!defineHoistedTopLevelFunctions(body
)) {
2326 // Save the last GCThingIndex emitted. The hoisted functions are contained in
2327 // the gc-things list up until this point. This set of gc-things also contain
2328 // initial scopes (of which there must be at least one).
2329 MOZ_ASSERT(perScriptData().gcThingList().length() > 0);
2330 GCThingIndex lastFun
=
2331 GCThingIndex(perScriptData().gcThingList().length() - 1);
2334 for (const auto& thing
: perScriptData().gcThingList().objects()) {
2335 MOZ_ASSERT(thing
.isEmptyGlobalScope() || thing
.isScope() ||
2336 thing
.isFunction());
2340 // Check for declaration conflicts and initialize the bindings.
2341 // NOTE: The self-hosting top-level script should not populate the builtins
2342 // directly on the GlobalObject (and instead uses JSOp::GetIntrinsic for
2344 if (emitterMode
== BytecodeEmitter::EmitterMode::Normal
) {
2345 if (!emitGCIndexOp(JSOp::GlobalOrEvalDeclInstantiation
, lastFun
)) {
2353 bool BytecodeEmitter::emitScript(ParseNode
* body
) {
2354 setScriptStartOffsetIfUnset(body
->pn_pos
.begin
);
2356 MOZ_ASSERT(inPrologue());
2358 TDZCheckCache
tdzCache(this);
2359 EmitterScope
emitterScope(this);
2360 Maybe
<AsyncEmitter
> topLevelAwait
;
2361 if (sc
->isGlobalContext()) {
2362 if (!emitterScope
.enterGlobal(this, sc
->asGlobalContext())) {
2365 } else if (sc
->isEvalContext()) {
2366 if (!emitterScope
.enterEval(this, sc
->asEvalContext())) {
2370 MOZ_ASSERT(sc
->isModuleContext());
2371 if (!emitterScope
.enterModule(this, sc
->asModuleContext())) {
2374 if (sc
->asModuleContext()->isAsync()) {
2375 topLevelAwait
.emplace(this);
2379 setFunctionBodyEndPos(body
->pn_pos
.end
);
2381 bool isSloppyEval
= sc
->isEvalContext() && !sc
->strict();
2382 if (isSloppyEval
&& body
->is
<LexicalScopeNode
>() &&
2383 !body
->as
<LexicalScopeNode
>().isEmptyScope()) {
2384 // Sloppy eval scripts may emit hoisted functions bindings with a
2385 // `JSOp::GlobalOrEvalDeclInstantiation` opcode below. If this eval needs a
2386 // top-level lexical environment, we must ensure that environment is created
2387 // before those functions are created and bound.
2389 // This differs from the global-script case below because the global-lexical
2390 // environment exists outside the script itself. In the case of strict eval
2391 // scripts, the `emitterScope` above is already sufficient.
2392 EmitterScope
lexicalEmitterScope(this);
2393 LexicalScopeNode
* scope
= &body
->as
<LexicalScopeNode
>();
2395 if (!lexicalEmitterScope
.enterLexical(this, ScopeKind::Lexical
,
2396 scope
->scopeBindings())) {
2400 if (!emitDeclarationInstantiation(scope
->scopeBody())) {
2406 ParseNode
* scopeBody
= scope
->scopeBody();
2407 if (!emitLexicalScopeBody(scopeBody
)) {
2411 if (!updateSourceCoordNotes(scopeBody
->pn_pos
.end
)) {
2415 if (!lexicalEmitterScope
.leave(this)) {
2419 if (!emitDeclarationInstantiation(body
)) {
2422 if (topLevelAwait
) {
2423 if (!topLevelAwait
->prepareForModule()) {
2430 if (topLevelAwait
) {
2431 if (!topLevelAwait
->prepareForBody()) {
2436 if (!emitTree(body
)) {
2441 if (!updateSourceCoordNotes(body
->pn_pos
.end
)) {
2446 if (topLevelAwait
) {
2447 if (!topLevelAwait
->emitEndModule()) {
2452 if (!markSimpleBreakpoint()) {
2456 if (!emitReturnRval()) {
2460 if (!emitterScope
.leave(this)) {
2464 if (!NameFunctions(fc
, parserAtoms(), body
)) {
2468 // Create a Stencil and convert it into a JSScript.
2469 return intoScriptStencil(CompilationStencil::TopLevelIndex
);
2472 js::UniquePtr
<ImmutableScriptData
>
2473 BytecodeEmitter::createImmutableScriptData() {
2475 if (!getNslots(&nslots
)) {
2479 bool isFunction
= sc
->isFunctionBox();
2480 uint16_t funLength
= isFunction
? sc
->asFunctionBox()->length() : 0;
2482 mozilla::SaturateUint8 propertyCountEstimate
= propertyAdditionEstimate
;
2484 // Add fields to the property count estimate.
2485 if (isFunction
&& sc
->asFunctionBox()->useMemberInitializers()) {
2486 propertyCountEstimate
+=
2487 sc
->asFunctionBox()->memberInitializers().numMemberInitializers
;
2490 return ImmutableScriptData::new_(
2491 fc
, mainOffset(), maxFixedSlots
, nslots
, bodyScopeIndex
,
2492 bytecodeSection().numICEntries(), isFunction
, funLength
,
2493 propertyCountEstimate
.value(), bytecodeSection().code(),
2494 bytecodeSection().notes(), bytecodeSection().resumeOffsetList().span(),
2495 bytecodeSection().scopeNoteList().span(),
2496 bytecodeSection().tryNoteList().span());
2499 bool BytecodeEmitter::getNslots(uint32_t* nslots
) {
2501 maxFixedSlots
+ static_cast<uint64_t>(bytecodeSection().maxStackDepth());
2502 if (nslots64
> UINT32_MAX
) {
2503 reportError(nullptr, JSMSG_NEED_DIET
, "script");
2510 bool BytecodeEmitter::emitFunctionScript(FunctionNode
* funNode
) {
2511 MOZ_ASSERT(inPrologue());
2512 ParamsBodyNode
* paramsBody
= funNode
->body();
2513 FunctionBox
* funbox
= sc
->asFunctionBox();
2515 setScriptStartOffsetIfUnset(paramsBody
->pn_pos
.begin
);
2519 FunctionScriptEmitter
fse(this, funbox
, Some(paramsBody
->pn_pos
.begin
),
2520 Some(paramsBody
->pn_pos
.end
));
2521 if (!fse
.prepareForParameters()) {
2526 if (!emitFunctionFormalParameters(paramsBody
)) {
2531 if (!fse
.prepareForBody()) {
2536 if (!emitTree(paramsBody
->body())) {
2541 if (!fse
.emitEndBody()) {
2546 if (funbox
->index() == CompilationStencil::TopLevelIndex
) {
2547 if (!NameFunctions(fc
, parserAtoms(), funNode
)) {
2552 return fse
.intoStencil();
2555 bool BytecodeEmitter::emitDestructuringLHSRef(ParseNode
* target
,
2558 int depth
= bytecodeSection().stackDepth();
2561 switch (target
->getKind()) {
2562 case ParseNodeKind::Name
:
2563 case ParseNodeKind::ArrayExpr
:
2564 case ParseNodeKind::ObjectExpr
:
2565 // No need to recurse into ParseNodeKind::Array and ParseNodeKind::Object
2566 // subpatterns here, since emitSetOrInitializeDestructuring does the
2567 // recursion when setting or initializing the value. Getting reference
2572 case ParseNodeKind::DotExpr
: {
2573 PropertyAccess
* prop
= &target
->as
<PropertyAccess
>();
2574 bool isSuper
= prop
->isSuper();
2575 PropOpEmitter
poe(this, PropOpEmitter::Kind::SimpleAssignment
,
2576 isSuper
? PropOpEmitter::ObjKind::Super
2577 : PropOpEmitter::ObjKind::Other
);
2578 if (!poe
.prepareForObj()) {
2582 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
2583 if (!emitGetThisForSuperBase(base
)) {
2584 // [stack] THIS SUPERBASE
2588 if (!emitTree(&prop
->expression())) {
2593 if (!poe
.prepareForRhs()) {
2594 // [stack] # if Super
2595 // [stack] THIS SUPERBASE
2596 // [stack] # otherwise
2601 // SUPERBASE was pushed onto THIS in poe.prepareForRhs above.
2602 *emitted
= 1 + isSuper
;
2606 case ParseNodeKind::ElemExpr
: {
2607 PropertyByValue
* elem
= &target
->as
<PropertyByValue
>();
2608 bool isSuper
= elem
->isSuper();
2609 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
2610 ElemOpEmitter
eoe(this, ElemOpEmitter::Kind::SimpleAssignment
,
2611 isSuper
? ElemOpEmitter::ObjKind::Super
2612 : ElemOpEmitter::ObjKind::Other
);
2613 if (!emitElemObjAndKey(elem
, isSuper
, eoe
)) {
2614 // [stack] # if Super
2616 // [stack] # otherwise
2620 if (!eoe
.prepareForRhs()) {
2621 // [stack] # if Super
2622 // [stack] THIS KEY SUPERBASE
2623 // [stack] # otherwise
2628 // SUPERBASE was pushed onto KEY in eoe.prepareForRhs above.
2629 *emitted
= 2 + isSuper
;
2633 case ParseNodeKind::PrivateMemberExpr
: {
2634 PrivateMemberAccess
* privateExpr
= &target
->as
<PrivateMemberAccess
>();
2635 PrivateOpEmitter
xoe(this, PrivateOpEmitter::Kind::SimpleAssignment
,
2636 privateExpr
->privateName().name());
2637 if (!emitTree(&privateExpr
->expression())) {
2641 if (!xoe
.emitReference()) {
2645 *emitted
= xoe
.numReferenceSlots();
2649 case ParseNodeKind::CallExpr
:
2650 MOZ_ASSERT_UNREACHABLE(
2651 "Parser::reportIfNotValidSimpleAssignmentTarget "
2652 "rejects function calls as assignment "
2653 "targets in destructuring assignments");
2657 MOZ_CRASH("emitDestructuringLHSRef: bad lhs kind");
2660 MOZ_ASSERT(bytecodeSection().stackDepth() == depth
+ int(*emitted
));
2665 bool BytecodeEmitter::emitSetOrInitializeDestructuring(
2666 ParseNode
* target
, DestructuringFlavor flav
) {
2667 // Now emit the lvalue opcode sequence. If the lvalue is a nested
2668 // destructuring initialiser-form, call ourselves to handle it, then pop
2669 // the matched value. Otherwise emit an lvalue bytecode sequence followed
2670 // by an assignment op.
2672 switch (target
->getKind()) {
2673 case ParseNodeKind::ArrayExpr
:
2674 case ParseNodeKind::ObjectExpr
:
2675 if (!emitDestructuringOps(&target
->as
<ListNode
>(), flav
)) {
2678 // emitDestructuringOps leaves the assigned (to-be-destructured) value on
2679 // top of the stack.
2682 case ParseNodeKind::Name
: {
2683 auto name
= target
->as
<NameNode
>().name();
2684 NameLocation loc
= lookupName(name
);
2685 NameOpEmitter::Kind kind
;
2687 case DestructuringFlavor::Declaration
:
2688 kind
= NameOpEmitter::Kind::Initialize
;
2691 case DestructuringFlavor::Assignment
:
2692 kind
= NameOpEmitter::Kind::SimpleAssignment
;
2696 NameOpEmitter
noe(this, name
, loc
, kind
);
2697 if (!noe
.prepareForRhs()) {
2701 if (noe
.emittedBindOp()) {
2702 // This is like ordinary assignment, but with one difference.
2704 // In `a = b`, we first determine a binding for `a` (using
2705 // JSOp::BindName or JSOp::BindGName), then we evaluate `b`, then
2706 // a JSOp::SetName instruction.
2708 // In `[a] = [b]`, per spec, `b` is evaluated first, then we
2709 // determine a binding for `a`. Then we need to do assignment--
2710 // but the operands are on the stack in the wrong order for
2711 // JSOp::SetProp, so we have to add a JSOp::Swap.
2713 // In the cases where we are emitting a name op, emit a swap
2715 if (!emit1(JSOp::Swap
)) {
2720 // In cases of emitting a frame slot or environment slot,
2721 // nothing needs be done.
2723 if (!noe
.emitAssignment()) {
2731 case ParseNodeKind::DotExpr
: {
2732 // The reference is already pushed by emitDestructuringLHSRef.
2733 // [stack] # if Super
2734 // [stack] THIS SUPERBASE VAL
2735 // [stack] # otherwise
2737 PropertyAccess
* prop
= &target
->as
<PropertyAccess
>();
2738 bool isSuper
= prop
->isSuper();
2739 PropOpEmitter
poe(this, PropOpEmitter::Kind::SimpleAssignment
,
2740 isSuper
? PropOpEmitter::ObjKind::Super
2741 : PropOpEmitter::ObjKind::Other
);
2742 if (!poe
.skipObjAndRhs()) {
2746 if (!poe
.emitAssignment(prop
->key().atom())) {
2752 case ParseNodeKind::ElemExpr
: {
2753 // The reference is already pushed by emitDestructuringLHSRef.
2754 // [stack] # if Super
2755 // [stack] THIS KEY SUPERBASE VAL
2756 // [stack] # otherwise
2757 // [stack] OBJ KEY VAL
2758 PropertyByValue
* elem
= &target
->as
<PropertyByValue
>();
2759 bool isSuper
= elem
->isSuper();
2760 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
2761 ElemOpEmitter
eoe(this, ElemOpEmitter::Kind::SimpleAssignment
,
2762 isSuper
? ElemOpEmitter::ObjKind::Super
2763 : ElemOpEmitter::ObjKind::Other
);
2764 if (!eoe
.skipObjAndKeyAndRhs()) {
2767 if (!eoe
.emitAssignment()) {
2774 case ParseNodeKind::PrivateMemberExpr
: {
2775 // The reference is already pushed by emitDestructuringLHSRef.
2776 // [stack] OBJ NAME VAL
2777 PrivateMemberAccess
* privateExpr
= &target
->as
<PrivateMemberAccess
>();
2778 PrivateOpEmitter
xoe(this, PrivateOpEmitter::Kind::SimpleAssignment
,
2779 privateExpr
->privateName().name());
2780 if (!xoe
.skipReference()) {
2783 if (!xoe
.emitAssignment()) {
2790 case ParseNodeKind::CallExpr
:
2791 MOZ_ASSERT_UNREACHABLE(
2792 "Parser::reportIfNotValidSimpleAssignmentTarget "
2793 "rejects function calls as assignment "
2794 "targets in destructuring assignments");
2798 MOZ_CRASH("emitSetOrInitializeDestructuring: bad lhs kind");
2801 // Pop the assigned value.
2802 if (!emit1(JSOp::Pop
)) {
2810 JSOp
BytecodeEmitter::getIterCallOp(JSOp callOp
,
2811 SelfHostedIter selfHostedIter
) {
2812 if (emitterMode
== BytecodeEmitter::SelfHosting
) {
2813 MOZ_ASSERT(selfHostedIter
!= SelfHostedIter::Deny
);
2817 return JSOp::CallContent
;
2818 case JSOp::CallIter
:
2819 return JSOp::CallContentIter
;
2821 MOZ_CRASH("Unknown iterator call op");
2828 bool BytecodeEmitter::emitIteratorNext(
2829 const Maybe
<uint32_t>& callSourceCoordOffset
,
2830 IteratorKind iterKind
/* = IteratorKind::Sync */,
2831 SelfHostedIter selfHostedIter
/* = SelfHostedIter::Deny */) {
2832 MOZ_ASSERT(selfHostedIter
!= SelfHostedIter::Deny
||
2833 emitterMode
!= BytecodeEmitter::SelfHosting
,
2834 ".next() iteration is prohibited in self-hosted code because it"
2835 "can run user-modifiable iteration code");
2837 // [stack] ... NEXT ITER
2838 MOZ_ASSERT(bytecodeSection().stackDepth() >= 2);
2840 if (!emitCall(getIterCallOp(JSOp::Call
, selfHostedIter
), 0,
2841 callSourceCoordOffset
)) {
2842 // [stack] ... RESULT
2846 if (iterKind
== IteratorKind::Async
) {
2847 if (!emitAwaitInInnermostScope()) {
2848 // [stack] ... RESULT
2853 if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext
)) {
2854 // [stack] ... RESULT
2860 bool BytecodeEmitter::emitIteratorCloseInScope(
2861 EmitterScope
& currentScope
,
2862 IteratorKind iterKind
/* = IteratorKind::Sync */,
2863 CompletionKind completionKind
/* = CompletionKind::Normal */,
2864 SelfHostedIter selfHostedIter
/* = SelfHostedIter::Deny */) {
2865 MOZ_ASSERT(selfHostedIter
!= SelfHostedIter::Deny
||
2866 emitterMode
!= BytecodeEmitter::SelfHosting
,
2867 ".close() on iterators is prohibited in self-hosted code because "
2868 "it can run user-modifiable iteration code");
2870 if (iterKind
== IteratorKind::Sync
) {
2871 return emit2(JSOp::CloseIter
, uint8_t(completionKind
));
2874 // Generate inline logic corresponding to IteratorClose (ES2021 7.4.6) and
2875 // AsyncIteratorClose (ES2021 7.4.7). Steps numbers apply to both operations.
2877 // Callers need to ensure that the iterator object is at the top of the
2880 // For non-Throw completions, we emit the equivalent of:
2882 // var returnMethod = GetMethod(iterator, "return");
2883 // if (returnMethod !== undefined) {
2884 // var innerResult = [Await] Call(returnMethod, iterator);
2885 // CheckIsObj(innerResult);
2888 // Whereas for Throw completions, we emit:
2891 // var returnMethod = GetMethod(iterator, "return");
2892 // if (returnMethod !== undefined) {
2893 // [Await] Call(returnMethod, iterator);
2897 Maybe
<TryEmitter
> tryCatch
;
2899 if (completionKind
== CompletionKind::Throw
) {
2900 tryCatch
.emplace(this, TryEmitter::Kind::TryCatch
,
2901 TryEmitter::ControlKind::NonSyntactic
);
2903 if (!tryCatch
->emitTry()) {
2909 if (!emit1(JSOp::Dup
)) {
2910 // [stack] ... ITER ITER
2914 // Steps 1-2 are assertions, step 3 is implicit.
2918 // Get the "return" method.
2919 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::return_())) {
2920 // [stack] ... ITER RET
2926 // Do nothing if "return" is undefined or null.
2927 InternalIfEmitter
ifReturnMethodIsDefined(this);
2928 if (!emit1(JSOp::IsNullOrUndefined
)) {
2929 // [stack] ... ITER RET NULL-OR-UNDEF
2933 if (!ifReturnMethodIsDefined
.emitThenElse(
2934 IfEmitter::ConditionKind::Negative
)) {
2935 // [stack] ... ITER RET
2941 // Call the "return" method.
2942 if (!emit1(JSOp::Swap
)) {
2943 // [stack] ... RET ITER
2947 if (!emitCall(getIterCallOp(JSOp::Call
, selfHostedIter
), 0)) {
2948 // [stack] ... RESULT
2952 // 7.4.7 AsyncIteratorClose, step 5.d.
2953 if (iterKind
== IteratorKind::Async
) {
2954 if (completionKind
!= CompletionKind::Throw
) {
2955 // Await clobbers rval, so save the current rval.
2956 if (!emit1(JSOp::GetRval
)) {
2957 // [stack] ... RESULT RVAL
2960 if (!emit1(JSOp::Swap
)) {
2961 // [stack] ... RVAL RESULT
2966 if (!emitAwaitInScope(currentScope
)) {
2967 // [stack] ... RVAL? RESULT
2971 if (completionKind
!= CompletionKind::Throw
) {
2972 if (!emit1(JSOp::Swap
)) {
2973 // [stack] ... RESULT RVAL
2976 if (!emit1(JSOp::SetRval
)) {
2977 // [stack] ... RESULT
2983 // Step 6 (Handled in caller).
2986 if (completionKind
!= CompletionKind::Throw
) {
2987 // Check that the "return" result is an object.
2988 if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn
)) {
2989 // [stack] ... RESULT
2994 if (!ifReturnMethodIsDefined
.emitElse()) {
2995 // [stack] ... ITER RET
2999 if (!emit1(JSOp::Pop
)) {
3004 if (!ifReturnMethodIsDefined
.emitEnd()) {
3008 if (completionKind
== CompletionKind::Throw
) {
3009 if (!tryCatch
->emitCatch()) {
3010 // [stack] ... ITER EXC
3014 // Just ignore the exception thrown by call and await.
3015 if (!emit1(JSOp::Pop
)) {
3020 if (!tryCatch
->emitEnd()) {
3026 // Step 9 (Handled in caller).
3028 return emit1(JSOp::Pop
);
3032 template <typename InnerEmitter
>
3033 bool BytecodeEmitter::wrapWithDestructuringTryNote(int32_t iterDepth
,
3034 InnerEmitter emitter
) {
3035 MOZ_ASSERT(bytecodeSection().stackDepth() >= iterDepth
);
3037 // Pad a nop at the beginning of the bytecode covered by the trynote so
3038 // that when unwinding environments, we may unwind to the scope
3039 // corresponding to the pc *before* the start, in case the first bytecode
3040 // emitted by |emitter| is the start of an inner scope. See comment above
3041 // UnwindEnvironmentToTryPc.
3042 if (!emit1(JSOp::TryDestructuring
)) {
3046 BytecodeOffset start
= bytecodeSection().offset();
3047 if (!emitter(this)) {
3050 BytecodeOffset end
= bytecodeSection().offset();
3052 return addTryNote(TryNoteKind::Destructuring
, iterDepth
, start
, end
);
3057 bool BytecodeEmitter::emitDefault(ParseNode
* defaultExpr
, ParseNode
* pattern
) {
3060 DefaultEmitter
de(this);
3061 if (!de
.prepareForDefault()) {
3065 if (!emitInitializer(defaultExpr
, pattern
)) {
3066 // [stack] DEFAULTVALUE
3069 if (!de
.emitEnd()) {
3070 // [stack] VALUE/DEFAULTVALUE
3076 bool BytecodeEmitter::emitAnonymousFunctionWithName(
3077 ParseNode
* node
, TaggedParserAtomIndex name
) {
3078 MOZ_ASSERT(node
->isDirectRHSAnonFunction());
3080 if (node
->is
<FunctionNode
>()) {
3081 // Function doesn't have 'name' property at this point.
3082 // Set function's name at compile time.
3083 if (!setFunName(node
->as
<FunctionNode
>().funbox(), name
)) {
3087 return emitTree(node
);
3090 MOZ_ASSERT(node
->is
<ClassNode
>());
3092 return emitClass(&node
->as
<ClassNode
>(), ClassNameKind::InferredName
, name
);
3095 bool BytecodeEmitter::emitAnonymousFunctionWithComputedName(
3096 ParseNode
* node
, FunctionPrefixKind prefixKind
) {
3097 MOZ_ASSERT(node
->isDirectRHSAnonFunction());
3099 if (node
->is
<FunctionNode
>()) {
3100 if (!emitTree(node
)) {
3104 if (!emitDupAt(1)) {
3105 // [stack] NAME FUN NAME
3108 if (!emit2(JSOp::SetFunName
, uint8_t(prefixKind
))) {
3115 MOZ_ASSERT(node
->is
<ClassNode
>());
3116 MOZ_ASSERT(prefixKind
== FunctionPrefixKind::None
);
3118 return emitClass(&node
->as
<ClassNode
>(), ClassNameKind::ComputedName
);
3121 bool BytecodeEmitter::setFunName(FunctionBox
* funbox
,
3122 TaggedParserAtomIndex name
) {
3123 // The inferred name may already be set if this function is an interpreted
3124 // lazy function and we OOM'ed after we set the inferred name the first
3126 if (funbox
->hasInferredName()) {
3127 MOZ_ASSERT(!funbox
->emitBytecode
);
3128 MOZ_ASSERT(funbox
->displayAtom() == name
);
3133 funbox
->setInferredName(name
);
3137 bool BytecodeEmitter::emitInitializer(ParseNode
* initializer
,
3138 ParseNode
* pattern
) {
3139 if (initializer
->isDirectRHSAnonFunction()) {
3140 MOZ_ASSERT(!pattern
->isInParens());
3141 auto name
= pattern
->as
<NameNode
>().name();
3142 if (!emitAnonymousFunctionWithName(initializer
, name
)) {
3146 if (!emitTree(initializer
)) {
3154 bool BytecodeEmitter::emitDestructuringOpsArray(ListNode
* pattern
,
3155 DestructuringFlavor flav
) {
3156 MOZ_ASSERT(getSelfHostedIterFor(pattern
) == SelfHostedIter::Deny
,
3157 "array destructuring is prohibited in self-hosted code because it"
3158 "can run user-modifiable iteration code");
3159 MOZ_ASSERT(pattern
->isKind(ParseNodeKind::ArrayExpr
));
3160 MOZ_ASSERT(bytecodeSection().stackDepth() != 0);
3162 // Here's pseudo code for |let [a, b, , c=y, ...d] = x;|
3164 // Lines that are annotated "covered by trynote" mean that upon throwing
3165 // an exception, IteratorClose is called on iter only if done is false.
3169 // let iter, next, lref, result, done, value; // stack values
3171 // // NOTE: the fast path for this example is not applicable, because of
3172 // // the spread and the assignment |c=y|, but it is documented here for a
3173 // // simpler example, |let [a,b] = x;|
3175 // // if (IsOptimizableArray(x)) {
3178 // // goto end: // (skip everything below)
3181 // iter = x[Symbol.iterator]();
3182 // next = iter.next;
3184 // // ==== emitted by loop for a ====
3185 // lref = GetReference(a); // covered by trynote
3187 // result = Call(next, iter);
3188 // done = result.done;
3191 // value = undefined;
3193 // value = result.value;
3195 // SetOrInitialize(lref, value); // covered by trynote
3197 // // ==== emitted by loop for b ====
3198 // lref = GetReference(b); // covered by trynote
3201 // value = undefined;
3203 // result = Call(next, iter);
3204 // done = result.done;
3206 // value = undefined;
3208 // value = result.value;
3211 // SetOrInitialize(lref, value); // covered by trynote
3213 // // ==== emitted by loop for elision ====
3215 // value = undefined;
3217 // result = Call(next, iter);
3218 // done = result.done;
3220 // value = undefined;
3222 // value = result.value;
3225 // // ==== emitted by loop for c ====
3226 // lref = GetReference(c); // covered by trynote
3229 // value = undefined;
3231 // result = Call(next, iter);
3232 // done = result.done;
3234 // value = undefined;
3236 // value = result.value;
3239 // if (value === undefined)
3240 // value = y; // covered by trynote
3242 // SetOrInitialize(lref, value); // covered by trynote
3244 // // ==== emitted by loop for d ====
3245 // lref = GetReference(d); // covered by trynote
3250 // value = [...iter];
3252 // SetOrInitialize(lref, value); // covered by trynote
3254 // // === emitted after loop ===
3256 // IteratorClose(iter);
3260 bool isEligibleForArrayOptimizations
= true;
3261 for (ParseNode
* member
: pattern
->contents()) {
3262 switch (member
->getKind()) {
3263 case ParseNodeKind::Elision
:
3265 case ParseNodeKind::Name
: {
3266 auto name
= member
->as
<NameNode
>().name();
3267 NameLocation loc
= lookupName(name
);
3268 if (loc
.kind() != NameLocation::Kind::ArgumentSlot
&&
3269 loc
.kind() != NameLocation::Kind::FrameSlot
&&
3270 loc
.kind() != NameLocation::Kind::EnvironmentCoordinate
) {
3271 isEligibleForArrayOptimizations
= false;
3276 // Unfortunately we can't handle any recursive destructuring,
3277 // because we can't guarantee that the recursed-into parts
3278 // won't run code which invalidates our constraints. We also
3279 // cannot handle ParseNodeKind::AssignExpr for similar reasons.
3280 isEligibleForArrayOptimizations
= false;
3283 if (!isEligibleForArrayOptimizations
) {
3288 // Use an iterator to destructure the RHS, instead of index lookup. We
3289 // must leave the *original* value on the stack.
3290 if (!emit1(JSOp::Dup
)) {
3291 // [stack] ... OBJ OBJ
3295 Maybe
<InternalIfEmitter
> ifArrayOptimizable
;
3297 if (isEligibleForArrayOptimizations
) {
3298 ifArrayOptimizable
.emplace(
3299 this, BranchEmitterBase::LexicalKind::MayContainLexicalAccessInBranch
);
3301 if (!emit1(JSOp::Dup
)) {
3306 if (!emit1(JSOp::OptimizeGetIterator
)) {
3307 // [stack] OBJ OBJ IS_OPTIMIZABLE
3311 if (!ifArrayOptimizable
->emitThenElse()) {
3316 if (!emitAtomOp(JSOp::GetProp
,
3317 TaggedParserAtomIndex::WellKnown::length())) {
3318 // [stack] OBJ LENGTH
3322 if (!emit1(JSOp::Swap
)) {
3323 // [stack] LENGTH OBJ
3328 for (ParseNode
* member
: pattern
->contents()) {
3329 if (member
->isKind(ParseNodeKind::Elision
)) {
3334 if (!emit1(JSOp::Dup
)) {
3335 // [stack] LENGTH OBJ OBJ
3339 if (!emitNumberOp(idx
)) {
3340 // [stack] LENGTH OBJ OBJ IDX
3344 if (!emit1(JSOp::Dup
)) {
3345 // [stack] LENGTH OBJ OBJ IDX IDX
3349 if (!emitDupAt(4)) {
3350 // [stack] LENGTH OBJ OBJ IDX IDX LENGTH
3354 if (!emit1(JSOp::Lt
)) {
3355 // [stack] LENGTH OBJ OBJ IDX IS_IN_DENSE_BOUNDS
3359 InternalIfEmitter
isInDenseBounds(this);
3360 if (!isInDenseBounds
.emitThenElse()) {
3361 // [stack] LENGTH OBJ OBJ IDX
3365 if (!emit1(JSOp::GetElem
)) {
3366 // [stack] LENGTH OBJ VALUE
3370 if (!isInDenseBounds
.emitElse()) {
3371 // [stack] LENGTH OBJ OBJ IDX
3376 // [stack] LENGTH OBJ
3380 if (!emit1(JSOp::Undefined
)) {
3381 // [stack] LENGTH OBJ UNDEFINED
3385 if (!isInDenseBounds
.emitEnd()) {
3386 // [stack] LENGTH OBJ VALUE|UNDEFINED
3390 if (!emitSetOrInitializeDestructuring(member
, flav
)) {
3391 // [stack] LENGTH OBJ
3398 if (!emit1(JSOp::Swap
)) {
3399 // [stack] OBJ LENGTH
3403 if (!emit1(JSOp::Pop
)) {
3408 if (!ifArrayOptimizable
->emitElse()) {
3414 if (!emitIterator(SelfHostedIter::Deny
)) {
3415 // [stack] ... OBJ NEXT ITER
3419 // For an empty pattern [], call IteratorClose unconditionally. Nothing
3420 // else needs to be done.
3421 if (!pattern
->head()) {
3422 if (!emit1(JSOp::Swap
)) {
3423 // [stack] ... OBJ ITER NEXT
3426 if (!emit1(JSOp::Pop
)) {
3427 // [stack] ... OBJ ITER
3431 if (!emitIteratorCloseInInnermostScope()) {
3436 if (ifArrayOptimizable
.isSome()) {
3437 if (!ifArrayOptimizable
->emitEnd()) {
3446 // Push an initial FALSE value for DONE.
3447 if (!emit1(JSOp::False
)) {
3448 // [stack] ... OBJ NEXT ITER FALSE
3452 // TryNoteKind::Destructuring expects the iterator and the done value
3453 // to be the second to top and the top of the stack, respectively.
3454 // IteratorClose is called upon exception only if done is false.
3455 int32_t tryNoteDepth
= bytecodeSection().stackDepth();
3457 for (ParseNode
* member
: pattern
->contents()) {
3458 bool isFirst
= member
== pattern
->head();
3459 DebugOnly
<bool> hasNext
= !!member
->pn_next
;
3461 ParseNode
* subpattern
;
3462 if (member
->isKind(ParseNodeKind::Spread
)) {
3463 subpattern
= member
->as
<UnaryNode
>().kid();
3465 MOZ_ASSERT(!subpattern
->isKind(ParseNodeKind::AssignExpr
));
3467 subpattern
= member
;
3470 ParseNode
* lhsPattern
= subpattern
;
3471 ParseNode
* pndefault
= nullptr;
3472 if (subpattern
->isKind(ParseNodeKind::AssignExpr
)) {
3473 lhsPattern
= subpattern
->as
<AssignmentNode
>().left();
3474 pndefault
= subpattern
->as
<AssignmentNode
>().right();
3477 // Number of stack slots emitted for the LHS reference.
3480 // Spec requires LHS reference to be evaluated first.
3481 bool isElision
= lhsPattern
->isKind(ParseNodeKind::Elision
);
3483 auto emitLHSRef
= [lhsPattern
, &emitted
](BytecodeEmitter
* bce
) {
3484 return bce
->emitDestructuringLHSRef(lhsPattern
, &emitted
);
3485 // [stack] ... OBJ NEXT ITER DONE LREF*
3487 if (!wrapWithDestructuringTryNote(tryNoteDepth
, emitLHSRef
)) {
3492 // Pick the DONE value to the top of the stack.
3494 if (!emitPickN(emitted
)) {
3495 // [stack] ... OBJ NEXT ITER LREF* DONE
3501 // If this element is the first, DONE is always FALSE, so pop it.
3503 // Non-first elements should emit if-else depending on the
3504 // member pattern, below.
3505 if (!emit1(JSOp::Pop
)) {
3506 // [stack] ... OBJ NEXT ITER LREF*
3511 if (member
->isKind(ParseNodeKind::Spread
)) {
3512 InternalIfEmitter
ifThenElse(this);
3514 // If spread is not the first element of the pattern,
3515 // iterator can already be completed.
3516 // [stack] ... OBJ NEXT ITER LREF* DONE
3518 if (!ifThenElse
.emitThenElse()) {
3519 // [stack] ... OBJ NEXT ITER LREF*
3523 if (!emitUint32Operand(JSOp::NewArray
, 0)) {
3524 // [stack] ... OBJ NEXT ITER LREF* ARRAY
3527 if (!ifThenElse
.emitElse()) {
3528 // [stack] ... OBJ NEXT ITER LREF*
3533 // If iterator is not completed, create a new array with the rest
3535 if (!emitDupAt(emitted
+ 1, 2)) {
3536 // [stack] ... OBJ NEXT ITER LREF* NEXT ITER
3539 if (!emitUint32Operand(JSOp::NewArray
, 0)) {
3540 // [stack] ... OBJ NEXT ITER LREF* NEXT ITER ARRAY
3543 if (!emitNumberOp(0)) {
3544 // [stack] ... OBJ NEXT ITER LREF* NEXT ITER ARRAY INDEX
3547 if (!emitSpread(SelfHostedIter::Deny
)) {
3548 // [stack] ... OBJ NEXT ITER LREF* ARRAY INDEX
3551 if (!emit1(JSOp::Pop
)) {
3552 // [stack] ... OBJ NEXT ITER LREF* ARRAY
3557 if (!ifThenElse
.emitEnd()) {
3560 MOZ_ASSERT(ifThenElse
.pushed() == 1);
3563 // At this point the iterator is done. Unpick a TRUE value for DONE above
3565 if (!emit1(JSOp::True
)) {
3566 // [stack] ... OBJ NEXT ITER LREF* ARRAY TRUE
3569 if (!emitUnpickN(emitted
+ 1)) {
3570 // [stack] ... OBJ NEXT ITER TRUE LREF* ARRAY
3574 auto emitAssignment
= [lhsPattern
, flav
](BytecodeEmitter
* bce
) {
3575 return bce
->emitSetOrInitializeDestructuring(lhsPattern
, flav
);
3576 // [stack] ... OBJ NEXT ITER TRUE
3578 if (!wrapWithDestructuringTryNote(tryNoteDepth
, emitAssignment
)) {
3582 MOZ_ASSERT(!hasNext
);
3586 InternalIfEmitter
ifAlreadyDone(this);
3588 // [stack] ... OBJ NEXT ITER LREF* DONE
3590 if (!ifAlreadyDone
.emitThenElse()) {
3591 // [stack] ... OBJ NEXT ITER LREF*
3595 if (!emit1(JSOp::Undefined
)) {
3596 // [stack] ... OBJ NEXT ITER LREF* UNDEF
3599 if (!emit1(JSOp::NopDestructuring
)) {
3600 // [stack] ... OBJ NEXT ITER LREF* UNDEF
3604 // The iterator is done. Unpick a TRUE value for DONE above ITER.
3605 if (!emit1(JSOp::True
)) {
3606 // [stack] ... OBJ NEXT ITER LREF* UNDEF TRUE
3609 if (!emitUnpickN(emitted
+ 1)) {
3610 // [stack] ... OBJ NEXT ITER TRUE LREF* UNDEF
3614 if (!ifAlreadyDone
.emitElse()) {
3615 // [stack] ... OBJ NEXT ITER LREF*
3620 if (!emitDupAt(emitted
+ 1, 2)) {
3621 // [stack] ... OBJ NEXT ITER LREF* NEXT
3624 if (!emitIteratorNext(Some(pattern
->pn_pos
.begin
))) {
3625 // [stack] ... OBJ NEXT ITER LREF* RESULT
3628 if (!emit1(JSOp::Dup
)) {
3629 // [stack] ... OBJ NEXT ITER LREF* RESULT RESULT
3632 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::done())) {
3633 // [stack] ... OBJ NEXT ITER LREF* RESULT DONE
3637 if (!emit1(JSOp::Dup
)) {
3638 // [stack] ... OBJ NEXT ITER LREF* RESULT DONE DONE
3641 if (!emitUnpickN(emitted
+ 2)) {
3642 // [stack] ... OBJ NEXT ITER DONE LREF* RESULT DONE
3646 InternalIfEmitter
ifDone(this);
3647 if (!ifDone
.emitThenElse()) {
3648 // [stack] ... OBJ NEXT ITER DONE LREF* RESULT
3652 if (!emit1(JSOp::Pop
)) {
3653 // [stack] ... OBJ NEXT ITER DONE LREF*
3656 if (!emit1(JSOp::Undefined
)) {
3657 // [stack] ... OBJ NEXT ITER DONE LREF* UNDEF
3660 if (!emit1(JSOp::NopDestructuring
)) {
3661 // [stack] ... OBJ NEXT ITER DONE LREF* UNDEF
3665 if (!ifDone
.emitElse()) {
3666 // [stack] ... OBJ NEXT ITER DONE LREF* RESULT
3670 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::value())) {
3671 // [stack] ... OBJ NEXT ITER DONE LREF* VALUE
3675 if (!ifDone
.emitEnd()) {
3678 MOZ_ASSERT(ifDone
.pushed() == 0);
3681 if (!ifAlreadyDone
.emitEnd()) {
3684 MOZ_ASSERT(ifAlreadyDone
.pushed() == 2);
3688 auto emitDefault
= [pndefault
, lhsPattern
](BytecodeEmitter
* bce
) {
3689 return bce
->emitDefault(pndefault
, lhsPattern
);
3690 // [stack] ... OBJ NEXT ITER DONE LREF* VALUE
3693 if (!wrapWithDestructuringTryNote(tryNoteDepth
, emitDefault
)) {
3699 auto emitAssignment
= [lhsPattern
, flav
](BytecodeEmitter
* bce
) {
3700 return bce
->emitSetOrInitializeDestructuring(lhsPattern
, flav
);
3701 // [stack] ... OBJ NEXT ITER DONE
3704 if (!wrapWithDestructuringTryNote(tryNoteDepth
, emitAssignment
)) {
3708 if (!emit1(JSOp::Pop
)) {
3709 // [stack] ... OBJ NEXT ITER DONE
3715 // The last DONE value is on top of the stack. If not DONE, call
3717 // [stack] ... OBJ NEXT ITER DONE
3719 InternalIfEmitter
ifDone(this);
3720 if (!ifDone
.emitThenElse()) {
3721 // [stack] ... OBJ NEXT ITER
3728 if (!ifDone
.emitElse()) {
3729 // [stack] ... OBJ NEXT ITER
3732 if (!emit1(JSOp::Swap
)) {
3733 // [stack] ... OBJ ITER NEXT
3736 if (!emit1(JSOp::Pop
)) {
3737 // [stack] ... OBJ ITER
3740 if (!emitIteratorCloseInInnermostScope()) {
3744 if (!ifDone
.emitEnd()) {
3748 if (ifArrayOptimizable
.isSome()) {
3749 if (!ifArrayOptimizable
->emitEnd()) {
3758 bool BytecodeEmitter::emitComputedPropertyName(UnaryNode
* computedPropName
) {
3759 MOZ_ASSERT(computedPropName
->isKind(ParseNodeKind::ComputedName
));
3760 return emitTree(computedPropName
->kid()) && emit1(JSOp::ToPropertyKey
);
3763 bool BytecodeEmitter::emitDestructuringOpsObject(ListNode
* pattern
,
3764 DestructuringFlavor flav
) {
3765 MOZ_ASSERT(pattern
->isKind(ParseNodeKind::ObjectExpr
));
3768 MOZ_ASSERT(bytecodeSection().stackDepth() > 0);
3770 if (!emit1(JSOp::CheckObjCoercible
)) {
3775 bool needsRestPropertyExcludedSet
=
3776 pattern
->count() > 1 && pattern
->last()->isKind(ParseNodeKind::Spread
);
3777 if (needsRestPropertyExcludedSet
) {
3778 if (!emitDestructuringObjRestExclusionSet(pattern
)) {
3779 // [stack] ... RHS SET
3783 if (!emit1(JSOp::Swap
)) {
3784 // [stack] ... SET RHS
3789 for (ParseNode
* member
: pattern
->contents()) {
3790 ParseNode
* subpattern
;
3791 if (member
->isKind(ParseNodeKind::MutateProto
) ||
3792 member
->isKind(ParseNodeKind::Spread
)) {
3793 subpattern
= member
->as
<UnaryNode
>().kid();
3795 MOZ_ASSERT_IF(member
->isKind(ParseNodeKind::Spread
),
3796 !subpattern
->isKind(ParseNodeKind::AssignExpr
));
3798 MOZ_ASSERT(member
->isKind(ParseNodeKind::PropertyDefinition
) ||
3799 member
->isKind(ParseNodeKind::Shorthand
));
3800 subpattern
= member
->as
<BinaryNode
>().right();
3803 ParseNode
* lhs
= subpattern
;
3804 ParseNode
* pndefault
= nullptr;
3805 if (subpattern
->isKind(ParseNodeKind::AssignExpr
)) {
3806 lhs
= subpattern
->as
<AssignmentNode
>().left();
3807 pndefault
= subpattern
->as
<AssignmentNode
>().right();
3810 // Number of stack slots emitted for the LHS reference.
3813 // Spec requires LHS reference to be evaluated first.
3814 if (!emitDestructuringLHSRef(lhs
, &emitted
)) {
3815 // [stack] ... SET? RHS LREF*
3819 // Duplicate the value being destructured to use as a reference base.
3820 if (!emitDupAt(emitted
)) {
3821 // [stack] ... SET? RHS LREF* RHS
3825 if (member
->isKind(ParseNodeKind::Spread
)) {
3826 if (!updateSourceCoordNotes(member
->pn_pos
.begin
)) {
3830 if (!emit1(JSOp::NewInit
)) {
3831 // [stack] ... SET? RHS LREF* RHS TARGET
3834 if (!emit1(JSOp::Dup
)) {
3835 // [stack] ... SET? RHS LREF* RHS TARGET TARGET
3838 if (!emit2(JSOp::Pick
, 2)) {
3839 // [stack] ... SET? RHS LREF* TARGET TARGET RHS
3843 if (needsRestPropertyExcludedSet
) {
3844 if (!emit2(JSOp::Pick
, emitted
+ 4)) {
3845 // [stack] ... RHS LREF* TARGET TARGET RHS SET
3850 CopyOption option
= needsRestPropertyExcludedSet
? CopyOption::Filtered
3851 : CopyOption::Unfiltered
;
3852 if (!emitCopyDataProperties(option
)) {
3853 // [stack] ... RHS LREF* TARGET
3857 // Destructure TARGET per this member's lhs.
3858 if (!emitSetOrInitializeDestructuring(lhs
, flav
)) {
3863 MOZ_ASSERT(member
== pattern
->last(), "Rest property is always last");
3867 // Now push the property value currently being matched, which is the value
3868 // of the current property name "label" on the left of a colon in the object
3870 if (member
->isKind(ParseNodeKind::MutateProto
)) {
3871 if (!emitAtomOp(JSOp::GetProp
,
3872 TaggedParserAtomIndex::WellKnown::proto_())) {
3873 // [stack] ... SET? RHS LREF* PROP
3877 MOZ_ASSERT(member
->isKind(ParseNodeKind::PropertyDefinition
) ||
3878 member
->isKind(ParseNodeKind::Shorthand
));
3880 ParseNode
* key
= member
->as
<BinaryNode
>().left();
3881 if (key
->isKind(ParseNodeKind::ObjectPropertyName
) ||
3882 key
->isKind(ParseNodeKind::StringExpr
)) {
3883 if (!emitAtomOp(JSOp::GetProp
, key
->as
<NameNode
>().atom())) {
3884 // [stack] ... SET? RHS LREF* PROP
3888 if (key
->isKind(ParseNodeKind::NumberExpr
)) {
3889 if (!emitNumberOp(key
->as
<NumericLiteral
>().value())) {
3890 // [stack]... SET? RHS LREF* RHS KEY
3894 // Otherwise this is a computed property name. BigInt keys are parsed
3895 // as (synthetic) computed property names, too.
3896 MOZ_ASSERT(key
->isKind(ParseNodeKind::ComputedName
));
3898 if (!emitComputedPropertyName(&key
->as
<UnaryNode
>())) {
3899 // [stack] ... SET? RHS LREF* RHS KEY
3903 // Add the computed property key to the exclusion set.
3904 if (needsRestPropertyExcludedSet
) {
3905 if (!emitDupAt(emitted
+ 3)) {
3906 // [stack] ... SET RHS LREF* RHS KEY SET
3909 if (!emitDupAt(1)) {
3910 // [stack] ... SET RHS LREF* RHS KEY SET KEY
3913 if (!emit1(JSOp::Undefined
)) {
3914 // [stack] ... SET RHS LREF* RHS KEY SET KEY UNDEFINED
3917 if (!emit1(JSOp::InitElem
)) {
3918 // [stack] ... SET RHS LREF* RHS KEY SET
3921 if (!emit1(JSOp::Pop
)) {
3922 // [stack] ... SET RHS LREF* RHS KEY
3928 // Get the property value.
3929 if (!emitElemOpBase(JSOp::GetElem
)) {
3930 // [stack] ... SET? RHS LREF* PROP
3937 if (!emitDefault(pndefault
, lhs
)) {
3938 // [stack] ... SET? RHS LREF* VALUE
3943 // Destructure PROP per this member's lhs.
3944 if (!emitSetOrInitializeDestructuring(lhs
, flav
)) {
3945 // [stack] ... SET? RHS
3953 static bool IsDestructuringRestExclusionSetObjLiteralCompatible(
3954 ListNode
* pattern
) {
3955 uint32_t propCount
= 0;
3956 for (ParseNode
* member
: pattern
->contents()) {
3957 if (member
->isKind(ParseNodeKind::Spread
)) {
3958 MOZ_ASSERT(!member
->pn_next
, "unexpected trailing element after spread");
3964 if (member
->isKind(ParseNodeKind::MutateProto
)) {
3968 ParseNode
* key
= member
->as
<BinaryNode
>().left();
3969 if (key
->isKind(ParseNodeKind::ObjectPropertyName
) ||
3970 key
->isKind(ParseNodeKind::StringExpr
)) {
3974 // Number and BigInt keys aren't yet supported. Computed property names need
3975 // to be added dynamically.
3976 MOZ_ASSERT(key
->isKind(ParseNodeKind::NumberExpr
) ||
3977 key
->isKind(ParseNodeKind::BigIntExpr
) ||
3978 key
->isKind(ParseNodeKind::ComputedName
));
3982 if (propCount
> SharedPropMap::MaxPropsForNonDictionary
) {
3983 // JSOp::NewObject cannot accept dictionary-mode objects.
3990 bool BytecodeEmitter::emitDestructuringObjRestExclusionSet(ListNode
* pattern
) {
3991 MOZ_ASSERT(pattern
->isKind(ParseNodeKind::ObjectExpr
));
3992 MOZ_ASSERT(pattern
->last()->isKind(ParseNodeKind::Spread
));
3994 // See if we can use ObjLiteral to construct the exclusion set object.
3995 if (IsDestructuringRestExclusionSetObjLiteralCompatible(pattern
)) {
3996 if (!emitDestructuringRestExclusionSetObjLiteral(pattern
)) {
4001 // Take the slow but sure way and start off with a blank object.
4002 if (!emit1(JSOp::NewInit
)) {
4008 for (ParseNode
* member
: pattern
->contents()) {
4009 if (member
->isKind(ParseNodeKind::Spread
)) {
4010 MOZ_ASSERT(!member
->pn_next
, "unexpected trailing element after spread");
4014 TaggedParserAtomIndex pnatom
;
4015 if (member
->isKind(ParseNodeKind::MutateProto
)) {
4016 pnatom
= TaggedParserAtomIndex::WellKnown::proto_();
4018 ParseNode
* key
= member
->as
<BinaryNode
>().left();
4019 if (key
->isKind(ParseNodeKind::ObjectPropertyName
) ||
4020 key
->isKind(ParseNodeKind::StringExpr
)) {
4021 pnatom
= key
->as
<NameNode
>().atom();
4022 } else if (key
->isKind(ParseNodeKind::NumberExpr
)) {
4023 if (!emitNumberOp(key
->as
<NumericLiteral
>().value())) {
4027 // Otherwise this is a computed property name which needs to be added
4028 // dynamically. BigInt keys are parsed as (synthetic) computed property
4030 MOZ_ASSERT(key
->isKind(ParseNodeKind::ComputedName
));
4035 // Initialize elements with |undefined|.
4036 if (!emit1(JSOp::Undefined
)) {
4041 if (!emit1(JSOp::InitElem
)) {
4045 if (!emitAtomOp(JSOp::InitProp
, pnatom
)) {
4054 bool BytecodeEmitter::emitDestructuringOps(ListNode
* pattern
,
4055 DestructuringFlavor flav
) {
4056 if (pattern
->isKind(ParseNodeKind::ArrayExpr
)) {
4057 return emitDestructuringOpsArray(pattern
, flav
);
4059 return emitDestructuringOpsObject(pattern
, flav
);
4062 bool BytecodeEmitter::emitTemplateString(ListNode
* templateString
) {
4063 bool pushedString
= false;
4065 for (ParseNode
* item
: templateString
->contents()) {
4066 bool isString
= (item
->getKind() == ParseNodeKind::StringExpr
||
4067 item
->getKind() == ParseNodeKind::TemplateStringExpr
);
4069 // Skip empty strings. These are very common: a template string like
4070 // `${a}${b}` has three empty strings and without this optimization
4071 // we'd emit four JSOp::Add operations instead of just one.
4072 if (isString
&& item
->as
<NameNode
>().atom() ==
4073 TaggedParserAtomIndex::WellKnown::empty()) {
4078 // We update source notes before emitting the expression
4079 if (!updateSourceCoordNotes(item
->pn_pos
.begin
)) {
4084 if (!emitTree(item
)) {
4089 // We need to convert the expression to a string
4090 if (!emit1(JSOp::ToString
)) {
4096 // We've pushed two strings onto the stack. Add them together, leaving
4098 if (!emit1(JSOp::Add
)) {
4102 pushedString
= true;
4106 if (!pushedString
) {
4107 // All strings were empty, this can happen for something like `${""}`.
4108 // Just push an empty string.
4109 if (!emitStringOp(JSOp::String
,
4110 TaggedParserAtomIndex::WellKnown::empty())) {
4118 bool BytecodeEmitter::emitDeclarationList(ListNode
* declList
) {
4119 for (ParseNode
* decl
: declList
->contents()) {
4121 ParseNode
* initializer
;
4122 if (decl
->isKind(ParseNodeKind::Name
)) {
4124 initializer
= nullptr;
4126 AssignmentNode
* assignNode
= &decl
->as
<AssignmentNode
>();
4127 pattern
= assignNode
->left();
4128 initializer
= assignNode
->right();
4131 if (pattern
->isKind(ParseNodeKind::Name
)) {
4132 // initializer can be null here.
4133 if (!emitSingleDeclaration(declList
, &pattern
->as
<NameNode
>(),
4138 MOZ_ASSERT(pattern
->isKind(ParseNodeKind::ArrayExpr
) ||
4139 pattern
->isKind(ParseNodeKind::ObjectExpr
));
4140 MOZ_ASSERT(initializer
!= nullptr);
4142 if (!updateSourceCoordNotes(initializer
->pn_pos
.begin
)) {
4145 if (!markStepBreakpoint()) {
4148 if (!emitTree(initializer
)) {
4152 if (!emitDestructuringOps(&pattern
->as
<ListNode
>(),
4153 DestructuringFlavor::Declaration
)) {
4157 if (!emit1(JSOp::Pop
)) {
4165 bool BytecodeEmitter::emitSingleDeclaration(ListNode
* declList
, NameNode
* decl
,
4166 ParseNode
* initializer
) {
4167 MOZ_ASSERT(decl
->isKind(ParseNodeKind::Name
));
4169 // Nothing to do for initializer-less 'var' declarations, as there's no TDZ.
4170 if (!initializer
&& declList
->isKind(ParseNodeKind::VarStmt
)) {
4174 auto nameAtom
= decl
->name();
4175 NameOpEmitter
noe(this, nameAtom
, NameOpEmitter::Kind::Initialize
);
4176 if (!noe
.prepareForRhs()) {
4181 // Lexical declarations are initialized to undefined without an
4183 MOZ_ASSERT(declList
->isKind(ParseNodeKind::LetDecl
),
4184 "var declarations without initializers handled above, "
4185 "and const declarations must have initializers");
4186 if (!emit1(JSOp::Undefined
)) {
4187 // [stack] ENV? UNDEF
4191 MOZ_ASSERT(initializer
);
4193 if (!updateSourceCoordNotes(initializer
->pn_pos
.begin
)) {
4196 if (!markStepBreakpoint()) {
4199 if (!emitInitializer(initializer
, decl
)) {
4204 if (!noe
.emitAssignment()) {
4208 if (!emit1(JSOp::Pop
)) {
4216 bool BytecodeEmitter::emitAssignmentRhs(
4217 ParseNode
* rhs
, TaggedParserAtomIndex anonFunctionName
) {
4218 if (rhs
->isDirectRHSAnonFunction()) {
4219 if (anonFunctionName
) {
4220 return emitAnonymousFunctionWithName(rhs
, anonFunctionName
);
4222 return emitAnonymousFunctionWithComputedName(rhs
, FunctionPrefixKind::None
);
4224 return emitTree(rhs
);
4227 // The RHS value to assign is already on the stack, i.e., the next enumeration
4228 // value in a for-in or for-of loop. Offset is the location in the stack of the
4229 // already-emitted rhs. If we emitted a JSOp::BindName or JSOp::BindGName, then
4230 // the scope is on the top of the stack and we need to dig one deeper to get
4231 // the right RHS value.
4232 bool BytecodeEmitter::emitAssignmentRhs(uint8_t offset
) {
4234 return emitPickN(offset
- 1);
4240 static inline JSOp
CompoundAssignmentParseNodeKindToJSOp(ParseNodeKind pnk
) {
4242 case ParseNodeKind::InitExpr
:
4244 case ParseNodeKind::AssignExpr
:
4246 case ParseNodeKind::AddAssignExpr
:
4248 case ParseNodeKind::SubAssignExpr
:
4250 case ParseNodeKind::BitOrAssignExpr
:
4252 case ParseNodeKind::BitXorAssignExpr
:
4253 return JSOp::BitXor
;
4254 case ParseNodeKind::BitAndAssignExpr
:
4255 return JSOp::BitAnd
;
4256 case ParseNodeKind::LshAssignExpr
:
4258 case ParseNodeKind::RshAssignExpr
:
4260 case ParseNodeKind::UrshAssignExpr
:
4262 case ParseNodeKind::MulAssignExpr
:
4264 case ParseNodeKind::DivAssignExpr
:
4266 case ParseNodeKind::ModAssignExpr
:
4268 case ParseNodeKind::PowAssignExpr
:
4270 case ParseNodeKind::CoalesceAssignExpr
:
4271 case ParseNodeKind::OrAssignExpr
:
4272 case ParseNodeKind::AndAssignExpr
:
4273 // Short-circuit assignment operators are handled elsewhere.
4276 MOZ_CRASH("unexpected compound assignment op");
4280 bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind
, ParseNode
* lhs
,
4282 JSOp compoundOp
= CompoundAssignmentParseNodeKindToJSOp(kind
);
4283 bool isCompound
= compoundOp
!= JSOp::Nop
;
4284 bool isInit
= kind
== ParseNodeKind::InitExpr
;
4286 // We estimate the number of properties this could create
4287 // if used as constructor merely by counting this.foo = assignment
4288 // or init expressions;
4290 // This currently doesn't handle this[x] = foo;
4291 if (isInit
|| kind
== ParseNodeKind::AssignExpr
) {
4292 if (lhs
->isKind(ParseNodeKind::DotExpr
)) {
4293 if (lhs
->as
<PropertyAccess
>().expression().isKind(
4294 ParseNodeKind::ThisExpr
)) {
4295 propertyAdditionEstimate
++;
4300 MOZ_ASSERT_IF(isInit
, lhs
->isKind(ParseNodeKind::DotExpr
) ||
4301 lhs
->isKind(ParseNodeKind::ElemExpr
) ||
4302 lhs
->isKind(ParseNodeKind::PrivateMemberExpr
));
4304 // |name| is used within NameOpEmitter, so its lifetime must surpass |noe|.
4305 TaggedParserAtomIndex name
;
4307 Maybe
<NameOpEmitter
> noe
;
4308 Maybe
<PropOpEmitter
> poe
;
4309 Maybe
<ElemOpEmitter
> eoe
;
4310 Maybe
<PrivateOpEmitter
> xoe
;
4312 // Deal with non-name assignments.
4315 // Purpose of anonFunctionName:
4317 // In normal name assignments (`f = function(){}`), an anonymous function gets
4318 // an inferred name based on the left-hand side name node.
4320 // In normal property assignments (`obj.x = function(){}`), the anonymous
4321 // function does not have a computed name, and rhs->isDirectRHSAnonFunction()
4322 // will be false (and anonFunctionName will not be used). However, in field
4323 // initializers (`class C { x = function(){} }`), field initialization is
4324 // implemented via a property or elem assignment (where we are now), and
4325 // rhs->isDirectRHSAnonFunction() is set - so we'll assign the name of the
4327 TaggedParserAtomIndex anonFunctionName
;
4329 switch (lhs
->getKind()) {
4330 case ParseNodeKind::Name
: {
4331 name
= lhs
->as
<NameNode
>().name();
4332 anonFunctionName
= name
;
4333 noe
.emplace(this, name
,
4334 isCompound
? NameOpEmitter::Kind::CompoundAssignment
4335 : NameOpEmitter::Kind::SimpleAssignment
);
4338 case ParseNodeKind::DotExpr
: {
4339 PropertyAccess
* prop
= &lhs
->as
<PropertyAccess
>();
4340 bool isSuper
= prop
->isSuper();
4342 isCompound
? PropOpEmitter::Kind::CompoundAssignment
4343 : isInit
? PropOpEmitter::Kind::PropInit
4344 : PropOpEmitter::Kind::SimpleAssignment
,
4345 isSuper
? PropOpEmitter::ObjKind::Super
4346 : PropOpEmitter::ObjKind::Other
);
4347 if (!poe
->prepareForObj()) {
4350 anonFunctionName
= prop
->name();
4352 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
4353 if (!emitGetThisForSuperBase(base
)) {
4354 // [stack] THIS SUPERBASE
4357 // SUPERBASE is pushed onto THIS later in poe->emitGet below.
4360 if (!emitTree(&prop
->expression())) {
4368 case ParseNodeKind::ElemExpr
: {
4369 PropertyByValue
* elem
= &lhs
->as
<PropertyByValue
>();
4370 bool isSuper
= elem
->isSuper();
4371 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
4373 isCompound
? ElemOpEmitter::Kind::CompoundAssignment
4374 : isInit
? ElemOpEmitter::Kind::PropInit
4375 : ElemOpEmitter::Kind::SimpleAssignment
,
4376 isSuper
? ElemOpEmitter::ObjKind::Super
4377 : ElemOpEmitter::ObjKind::Other
);
4378 if (!emitElemObjAndKey(elem
, isSuper
, *eoe
)) {
4379 // [stack] # if Super
4381 // [stack] # otherwise
4386 // SUPERBASE is pushed onto KEY in eoe->emitGet below.
4393 case ParseNodeKind::PrivateMemberExpr
: {
4394 PrivateMemberAccess
* privateExpr
= &lhs
->as
<PrivateMemberAccess
>();
4396 isCompound
? PrivateOpEmitter::Kind::CompoundAssignment
4397 : isInit
? PrivateOpEmitter::Kind::PropInit
4398 : PrivateOpEmitter::Kind::SimpleAssignment
,
4399 privateExpr
->privateName().name());
4400 if (!emitTree(&privateExpr
->expression())) {
4404 if (!xoe
->emitReference()) {
4408 offset
+= xoe
->numReferenceSlots();
4411 case ParseNodeKind::ArrayExpr
:
4412 case ParseNodeKind::ObjectExpr
:
4414 case ParseNodeKind::CallExpr
:
4415 if (!emitTree(lhs
)) {
4419 // Assignment to function calls is forbidden, but we have to make the
4420 // call first. Now we can throw.
4421 if (!emit2(JSOp::ThrowMsg
, uint8_t(ThrowMsgKind::AssignToCall
))) {
4425 // Rebalance the stack to placate stack-depth assertions.
4426 if (!emit1(JSOp::Pop
)) {
4436 switch (lhs
->getKind()) {
4437 case ParseNodeKind::DotExpr
: {
4438 PropertyAccess
* prop
= &lhs
->as
<PropertyAccess
>();
4439 if (!poe
->emitGet(prop
->key().atom())) {
4440 // [stack] # if Super
4441 // [stack] THIS SUPERBASE PROP
4442 // [stack] # otherwise
4448 case ParseNodeKind::ElemExpr
: {
4449 if (!eoe
->emitGet()) {
4450 // [stack] KEY THIS OBJ ELEM
4455 case ParseNodeKind::PrivateMemberExpr
: {
4456 if (!xoe
->emitGet()) {
4457 // [stack] OBJ KEY VALUE
4462 case ParseNodeKind::CallExpr
:
4463 // We just emitted a JSOp::ThrowMsg and popped the call's return
4464 // value. Push a random value to make sure the stack depth is
4466 if (!emit1(JSOp::Null
)) {
4475 switch (lhs
->getKind()) {
4476 case ParseNodeKind::Name
:
4477 if (!noe
->prepareForRhs()) {
4478 // [stack] ENV? VAL?
4481 offset
+= noe
->emittedBindOp();
4483 case ParseNodeKind::DotExpr
:
4484 if (!poe
->prepareForRhs()) {
4485 // [stack] # if Simple Assignment with Super
4486 // [stack] THIS SUPERBASE
4487 // [stack] # if Simple Assignment with other
4489 // [stack] # if Compound Assignment with Super
4490 // [stack] THIS SUPERBASE PROP
4491 // [stack] # if Compound Assignment with other
4496 case ParseNodeKind::ElemExpr
:
4497 if (!eoe
->prepareForRhs()) {
4498 // [stack] # if Simple Assignment with Super
4499 // [stack] THIS KEY SUPERBASE
4500 // [stack] # if Simple Assignment with other
4502 // [stack] # if Compound Assignment with Super
4503 // [stack] THIS KEY SUPERBASE ELEM
4504 // [stack] # if Compound Assignment with other
4505 // [stack] OBJ KEY ELEM
4509 case ParseNodeKind::PrivateMemberExpr
:
4510 // no stack adjustment needed
4517 if (!emitAssignmentRhs(rhs
, anonFunctionName
)) {
4518 // [stack] ... VAL? RHS
4522 // Assumption: Things with pre-emitted RHS values never need to be named.
4523 if (!emitAssignmentRhs(offset
)) {
4524 // [stack] ... VAL? RHS
4529 /* If += etc., emit the binary operator with a hint for the decompiler. */
4531 if (!emit1(compoundOp
)) {
4535 if (!emit1(JSOp::NopIsAssignOp
)) {
4541 /* Finally, emit the specialized assignment bytecode. */
4542 switch (lhs
->getKind()) {
4543 case ParseNodeKind::Name
: {
4544 if (!noe
->emitAssignment()) {
4550 case ParseNodeKind::DotExpr
: {
4551 PropertyAccess
* prop
= &lhs
->as
<PropertyAccess
>();
4552 if (!poe
->emitAssignment(prop
->key().atom())) {
4558 case ParseNodeKind::CallExpr
:
4559 // We threw above, so nothing to do here.
4561 case ParseNodeKind::ElemExpr
: {
4562 if (!eoe
->emitAssignment()) {
4568 case ParseNodeKind::PrivateMemberExpr
:
4569 if (!xoe
->emitAssignment()) {
4574 case ParseNodeKind::ArrayExpr
:
4575 case ParseNodeKind::ObjectExpr
:
4576 if (!emitDestructuringOps(&lhs
->as
<ListNode
>(),
4577 DestructuringFlavor::Assignment
)) {
4587 bool BytecodeEmitter::emitShortCircuitAssignment(AssignmentNode
* node
) {
4588 TDZCheckCache
tdzCache(this);
4591 switch (node
->getKind()) {
4592 case ParseNodeKind::CoalesceAssignExpr
:
4593 op
= JSOp::Coalesce
;
4595 case ParseNodeKind::OrAssignExpr
:
4598 case ParseNodeKind::AndAssignExpr
:
4602 MOZ_CRASH("Unexpected ParseNodeKind");
4605 ParseNode
* lhs
= node
->left();
4606 ParseNode
* rhs
= node
->right();
4608 // |name| is used within NameOpEmitter, so its lifetime must surpass |noe|.
4609 TaggedParserAtomIndex name
;
4611 // Select the appropriate emitter based on the left-hand side.
4612 Maybe
<NameOpEmitter
> noe
;
4613 Maybe
<PropOpEmitter
> poe
;
4614 Maybe
<ElemOpEmitter
> eoe
;
4615 Maybe
<PrivateOpEmitter
> xoe
;
4617 int32_t depth
= bytecodeSection().stackDepth();
4619 // Number of values pushed onto the stack in addition to the lhs value.
4622 // Evaluate the left-hand side expression and compute any stack values needed
4623 // for the assignment.
4624 switch (lhs
->getKind()) {
4625 case ParseNodeKind::Name
: {
4626 name
= lhs
->as
<NameNode
>().name();
4627 noe
.emplace(this, name
, NameOpEmitter::Kind::CompoundAssignment
);
4629 if (!noe
->prepareForRhs()) {
4634 numPushed
= noe
->emittedBindOp();
4638 case ParseNodeKind::DotExpr
: {
4639 PropertyAccess
* prop
= &lhs
->as
<PropertyAccess
>();
4640 bool isSuper
= prop
->isSuper();
4642 poe
.emplace(this, PropOpEmitter::Kind::CompoundAssignment
,
4643 isSuper
? PropOpEmitter::ObjKind::Super
4644 : PropOpEmitter::ObjKind::Other
);
4646 if (!poe
->prepareForObj()) {
4651 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
4652 if (!emitGetThisForSuperBase(base
)) {
4653 // [stack] THIS SUPERBASE
4657 if (!emitTree(&prop
->expression())) {
4663 if (!poe
->emitGet(prop
->key().atom())) {
4664 // [stack] # if Super
4665 // [stack] THIS SUPERBASE LHS
4666 // [stack] # otherwise
4671 if (!poe
->prepareForRhs()) {
4672 // [stack] # if Super
4673 // [stack] THIS SUPERBASE LHS
4674 // [stack] # otherwise
4679 numPushed
= 1 + isSuper
;
4683 case ParseNodeKind::ElemExpr
: {
4684 PropertyByValue
* elem
= &lhs
->as
<PropertyByValue
>();
4685 bool isSuper
= elem
->isSuper();
4686 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
4687 eoe
.emplace(this, ElemOpEmitter::Kind::CompoundAssignment
,
4688 isSuper
? ElemOpEmitter::ObjKind::Super
4689 : ElemOpEmitter::ObjKind::Other
);
4691 if (!emitElemObjAndKey(elem
, isSuper
, *eoe
)) {
4692 // [stack] # if Super
4694 // [stack] # otherwise
4699 if (!eoe
->emitGet()) {
4700 // [stack] # if Super
4701 // [stack] THIS KEY SUPERBASE LHS
4702 // [stack] # otherwise
4703 // [stack] OBJ KEY LHS
4707 if (!eoe
->prepareForRhs()) {
4708 // [stack] # if Super
4709 // [stack] THIS KEY SUPERBASE LHS
4710 // [stack] # otherwise
4711 // [stack] OBJ KEY LHS
4715 numPushed
= 2 + isSuper
;
4719 case ParseNodeKind::PrivateMemberExpr
: {
4720 PrivateMemberAccess
* privateExpr
= &lhs
->as
<PrivateMemberAccess
>();
4721 xoe
.emplace(this, PrivateOpEmitter::Kind::CompoundAssignment
,
4722 privateExpr
->privateName().name());
4723 if (!emitTree(&privateExpr
->expression())) {
4727 if (!xoe
->emitReference()) {
4731 if (!xoe
->emitGet()) {
4732 // [stack] OBJ NAME LHS
4735 numPushed
= xoe
->numReferenceSlots();
4743 MOZ_ASSERT(bytecodeSection().stackDepth() == depth
+ numPushed
+ 1);
4745 // Test for the short-circuit condition.
4747 if (!emitJump(op
, &jump
)) {
4752 // The short-circuit condition wasn't fulfilled, pop the left-hand side value
4753 // which was kept on the stack.
4754 if (!emit1(JSOp::Pop
)) {
4759 if (!emitAssignmentRhs(rhs
, name
)) {
4764 // Perform the actual assignment.
4765 switch (lhs
->getKind()) {
4766 case ParseNodeKind::Name
: {
4767 if (!noe
->emitAssignment()) {
4774 case ParseNodeKind::DotExpr
: {
4775 PropertyAccess
* prop
= &lhs
->as
<PropertyAccess
>();
4777 if (!poe
->emitAssignment(prop
->key().atom())) {
4784 case ParseNodeKind::ElemExpr
: {
4785 if (!eoe
->emitAssignment()) {
4792 case ParseNodeKind::PrivateMemberExpr
:
4793 if (!xoe
->emitAssignment()) {
4803 MOZ_ASSERT(bytecodeSection().stackDepth() == depth
+ 1);
4805 // Join with the short-circuit jump and pop anything left on the stack.
4806 if (numPushed
> 0) {
4807 JumpList jumpAroundPop
;
4808 if (!emitJump(JSOp::Goto
, &jumpAroundPop
)) {
4813 if (!emitJumpTargetAndPatch(jump
)) {
4818 // Reconstruct the stack depth after the jump.
4819 bytecodeSection().setStackDepth(depth
+ 1 + numPushed
);
4821 // Move the left-hand side value to the bottom and pop the rest.
4822 if (!emitUnpickN(numPushed
)) {
4826 if (!emitPopN(numPushed
)) {
4831 if (!emitJumpTargetAndPatch(jumpAroundPop
)) {
4832 // [stack] LHS | RHS
4836 if (!emitJumpTargetAndPatch(jump
)) {
4837 // [stack] LHS | RHS
4842 MOZ_ASSERT(bytecodeSection().stackDepth() == depth
+ 1);
4847 bool BytecodeEmitter::emitCallSiteObjectArray(ObjLiteralWriter
& writer
,
4848 ListNode
* cookedOrRaw
,
4849 ParseNode
* head
, uint32_t count
) {
4850 DebugOnly
<size_t> idx
= 0;
4851 for (ParseNode
* pn
: cookedOrRaw
->contentsFrom(head
)) {
4852 MOZ_ASSERT(pn
->isKind(ParseNodeKind::TemplateStringExpr
) ||
4853 pn
->isKind(ParseNodeKind::RawUndefinedExpr
));
4855 if (!emitObjLiteralValue(writer
, pn
)) {
4860 MOZ_ASSERT(idx
== count
);
4865 bool BytecodeEmitter::emitCallSiteObject(CallSiteNode
* callSiteObj
) {
4866 constexpr JSOp op
= JSOp::CallSiteObj
;
4868 // The first element of a call-site node is the raw-values list. Skip over it.
4869 ListNode
* raw
= callSiteObj
->rawNodes();
4870 MOZ_ASSERT(raw
->isKind(ParseNodeKind::ArrayExpr
));
4871 ParseNode
* head
= callSiteObj
->head()->pn_next
;
4873 uint32_t count
= callSiteObj
->count() - 1;
4874 MOZ_ASSERT(count
== raw
->count());
4876 ObjLiteralWriter writer
;
4877 writer
.beginCallSiteObj(op
);
4878 writer
.beginDenseArrayElements();
4880 // Write elements of the two arrays: the 'cooked' values followed by the
4882 MOZ_RELEASE_ASSERT(count
< UINT32_MAX
/ 2,
4883 "Number of elements for both arrays must fit in uint32_t");
4884 if (!emitCallSiteObjectArray(writer
, callSiteObj
, head
, count
)) {
4887 if (!emitCallSiteObjectArray(writer
, raw
, raw
->head(), count
)) {
4891 GCThingIndex cookedIndex
;
4892 if (!addObjLiteralData(writer
, &cookedIndex
)) {
4896 MOZ_ASSERT(sc
->hasCallSiteObj());
4898 return emitInternedObjectOp(cookedIndex
, op
);
4901 bool BytecodeEmitter::emitCatch(BinaryNode
* catchClause
) {
4902 // We must be nested under a try-finally statement.
4903 MOZ_ASSERT(innermostNestableControl
->is
<TryFinallyControl
>());
4905 ParseNode
* param
= catchClause
->left();
4907 // Catch parameter was omitted; just discard the exception.
4908 if (!emit1(JSOp::Pop
)) {
4912 switch (param
->getKind()) {
4913 case ParseNodeKind::ArrayExpr
:
4914 case ParseNodeKind::ObjectExpr
:
4915 if (!emitDestructuringOps(¶m
->as
<ListNode
>(),
4916 DestructuringFlavor::Declaration
)) {
4919 if (!emit1(JSOp::Pop
)) {
4924 case ParseNodeKind::Name
:
4925 if (!emitLexicalInitialization(¶m
->as
<NameNode
>())) {
4928 if (!emit1(JSOp::Pop
)) {
4938 /* Emit the catch body. */
4939 return emitTree(catchClause
->right());
4942 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See the
4943 // comment on EmitSwitch.
4944 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitTry(TryNode
* tryNode
) {
4945 LexicalScopeNode
* catchScope
= tryNode
->catchScope();
4946 ParseNode
* finallyNode
= tryNode
->finallyBlock();
4948 TryEmitter::Kind kind
;
4951 kind
= TryEmitter::Kind::TryCatchFinally
;
4953 kind
= TryEmitter::Kind::TryCatch
;
4956 MOZ_ASSERT(finallyNode
);
4957 kind
= TryEmitter::Kind::TryFinally
;
4959 TryEmitter
tryCatch(this, kind
, TryEmitter::ControlKind::Syntactic
);
4961 if (!tryCatch
.emitTry()) {
4965 if (!emitTree(tryNode
->body())) {
4969 // If this try has a catch block, emit it.
4971 // The emitted code for a catch block looks like:
4973 // [pushlexicalenv] only if any local aliased
4975 // setlocal 0; pop assign or possibly destructure exception
4976 // < catch block contents >
4978 // [poplexicalenv] only if any local aliased
4979 // if there is a finally block:
4981 // [jump target for returning from finally]
4982 // goto <after finally>
4983 if (!tryCatch
.emitCatch()) {
4987 // Emit the lexical scope and catch body.
4988 if (!emitTree(catchScope
)) {
4993 // Emit the finally handler, if there is one.
4995 if (!tryCatch
.emitFinally(Some(finallyNode
->pn_pos
.begin
))) {
4999 if (!emitTree(finallyNode
)) {
5004 if (!tryCatch
.emitEnd()) {
5011 [[nodiscard
]] bool BytecodeEmitter::emitJumpToFinally(JumpList
* jump
,
5013 // Push the continuation index.
5014 if (!emitNumberOp(idx
)) {
5019 if (!emit1(JSOp::False
)) {
5023 // Jump to the finally block.
5024 if (!emitJumpNoFallthrough(JSOp::Goto
, jump
)) {
5031 bool BytecodeEmitter::emitIf(TernaryNode
* ifNode
) {
5032 IfEmitter
ifThenElse(this);
5034 if (!ifThenElse
.emitIf(Some(ifNode
->kid1()->pn_pos
.begin
))) {
5039 ParseNode
* testNode
= ifNode
->kid1();
5040 auto conditionKind
= IfEmitter::ConditionKind::Positive
;
5041 if (testNode
->isKind(ParseNodeKind::NotExpr
)) {
5042 testNode
= testNode
->as
<UnaryNode
>().kid();
5043 conditionKind
= IfEmitter::ConditionKind::Negative
;
5046 if (!markStepBreakpoint()) {
5050 // Emit code for the condition before pushing stmtInfo.
5051 // NOTE: NotExpr of testNode may be unwrapped, and in that case the negation
5052 // is handled by conditionKind.
5053 if (!emitTree(testNode
)) {
5057 ParseNode
* elseNode
= ifNode
->kid3();
5059 if (!ifThenElse
.emitThenElse(conditionKind
)) {
5063 if (!ifThenElse
.emitThen(conditionKind
)) {
5068 /* Emit code for the then part. */
5069 if (!emitTree(ifNode
->kid2())) {
5074 if (elseNode
->isKind(ParseNodeKind::IfStmt
)) {
5075 ifNode
= &elseNode
->as
<TernaryNode
>();
5077 if (!ifThenElse
.emitElseIf(Some(ifNode
->kid1()->pn_pos
.begin
))) {
5084 if (!ifThenElse
.emitElse()) {
5088 /* Emit code for the else part. */
5089 if (!emitTree(elseNode
)) {
5094 if (!ifThenElse
.emitEnd()) {
5101 bool BytecodeEmitter::emitHoistedFunctionsInList(ListNode
* stmtList
) {
5102 MOZ_ASSERT(stmtList
->hasTopLevelFunctionDeclarations());
5104 // We can call this multiple times for sloppy eval scopes.
5105 if (stmtList
->emittedTopLevelFunctionDeclarations()) {
5109 stmtList
->setEmittedTopLevelFunctionDeclarations();
5111 for (ParseNode
* stmt
: stmtList
->contents()) {
5112 ParseNode
* maybeFun
= stmt
;
5114 if (!sc
->strict()) {
5115 while (maybeFun
->isKind(ParseNodeKind::LabelStmt
)) {
5116 maybeFun
= maybeFun
->as
<LabeledStatement
>().statement();
5120 if (maybeFun
->is
<FunctionNode
>() &&
5121 maybeFun
->as
<FunctionNode
>().functionIsHoisted()) {
5122 if (!emitTree(maybeFun
)) {
5131 bool BytecodeEmitter::emitLexicalScopeBody(
5132 ParseNode
* body
, EmitLineNumberNote emitLineNote
/* = EMIT_LINENOTE */) {
5133 if (body
->isKind(ParseNodeKind::StatementList
) &&
5134 body
->as
<ListNode
>().hasTopLevelFunctionDeclarations()) {
5135 // This block contains function statements whose definitions are
5136 // hoisted to the top of the block. Emit these as a separate pass
5137 // before the rest of the block.
5138 if (!emitHoistedFunctionsInList(&body
->as
<ListNode
>())) {
5143 // Line notes were updated by emitLexicalScope or emitScript.
5144 return emitTree(body
, ValueUsage::WantValue
, emitLineNote
);
5147 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
5148 // the comment on emitSwitch.
5149 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitLexicalScope(
5150 LexicalScopeNode
* lexicalScope
) {
5151 LexicalScopeEmitter
lse(this);
5153 ParseNode
* body
= lexicalScope
->scopeBody();
5154 if (lexicalScope
->isEmptyScope()) {
5155 if (!lse
.emitEmptyScope()) {
5159 if (!emitLexicalScopeBody(body
)) {
5163 if (!lse
.emitEnd()) {
5170 // We are about to emit some bytecode for what the spec calls "declaration
5171 // instantiation". Assign these instructions to the opening `{` of the
5172 // block. (Using the location of each declaration we're instantiating is
5173 // too weird when stepping in the debugger.)
5174 if (!ParseNodeRequiresSpecialLineNumberNotes(body
)) {
5175 if (!updateSourceCoordNotes(lexicalScope
->pn_pos
.begin
)) {
5181 if (body
->isKind(ParseNodeKind::Catch
)) {
5182 BinaryNode
* catchNode
= &body
->as
<BinaryNode
>();
5184 (!catchNode
->left() || catchNode
->left()->isKind(ParseNodeKind::Name
))
5185 ? ScopeKind::SimpleCatch
5188 kind
= lexicalScope
->kind();
5191 if (!lse
.emitScope(kind
, lexicalScope
->scopeBindings())) {
5195 if (body
->isKind(ParseNodeKind::ForStmt
)) {
5196 // for loops need to emit JSOp::FreshenLexicalEnv/JSOp::RecreateLexicalEnv
5197 // if there are lexical declarations in the head. Signal this by passing a
5198 // non-nullptr lexical scope.
5199 if (!emitFor(&body
->as
<ForNode
>(), &lse
.emitterScope())) {
5203 if (!emitLexicalScopeBody(body
, SUPPRESS_LINENOTE
)) {
5208 if (!lse
.emitEnd()) {
5214 bool BytecodeEmitter::emitWith(BinaryNode
* withNode
) {
5215 // Ensure that the column of the 'with' is set properly.
5216 if (!updateSourceCoordNotes(withNode
->left()->pn_pos
.begin
)) {
5220 if (!markStepBreakpoint()) {
5224 if (!emitTree(withNode
->left())) {
5228 EmitterScope
emitterScope(this);
5229 if (!emitterScope
.enterWith(this)) {
5233 if (!emitTree(withNode
->right())) {
5237 return emitterScope
.leave(this);
5240 bool BytecodeEmitter::emitCopyDataProperties(CopyOption option
) {
5241 DebugOnly
<int32_t> depth
= bytecodeSection().stackDepth();
5244 if (option
== CopyOption::Filtered
) {
5245 MOZ_ASSERT(depth
> 2);
5246 // [stack] TARGET SOURCE SET
5249 if (!emitAtomOp(JSOp::GetIntrinsic
,
5250 TaggedParserAtomIndex::WellKnown::CopyDataProperties())) {
5251 // [stack] TARGET SOURCE SET COPYDATAPROPERTIES
5255 MOZ_ASSERT(depth
> 1);
5256 // [stack] TARGET SOURCE
5261 TaggedParserAtomIndex::WellKnown::CopyDataPropertiesUnfiltered())) {
5262 // [stack] TARGET SOURCE COPYDATAPROPERTIES
5267 if (!emit1(JSOp::Undefined
)) {
5268 // [stack] TARGET SOURCE SET? COPYDATAPROPERTIES
5272 if (!emit2(JSOp::Pick
, argc
+ 1)) {
5273 // [stack] SOURCE SET? COPYDATAPROPERTIES UNDEFINED
5277 if (!emit2(JSOp::Pick
, argc
+ 1)) {
5278 // [stack] SET? COPYDATAPROPERTIES UNDEFINED TARGET
5282 if (option
== CopyOption::Filtered
) {
5283 if (!emit2(JSOp::Pick
, argc
+ 1)) {
5284 // [stack] COPYDATAPROPERTIES UNDEFINED TARGET SOURCE SET
5288 // Callee is always self-hosted instrinsic, and cannot be content function.
5289 if (!emitCall(JSOp::CallIgnoresRv
, argc
)) {
5294 if (!emit1(JSOp::Pop
)) {
5299 MOZ_ASSERT(depth
- int(argc
) == bytecodeSection().stackDepth());
5303 bool BytecodeEmitter::emitBigIntOp(BigIntLiteral
* bigint
) {
5305 if (!perScriptData().gcThingList().append(bigint
, &index
)) {
5308 return emitGCIndexOp(JSOp::BigInt
, index
);
5311 bool BytecodeEmitter::emitIterable(ParseNode
* value
,
5312 SelfHostedIter selfHostedIter
,
5313 IteratorKind iterKind
) {
5314 MOZ_ASSERT(getSelfHostedIterFor(value
) == selfHostedIter
);
5316 if (!emitTree(value
)) {
5321 switch (selfHostedIter
) {
5322 case SelfHostedIter::Deny
:
5323 case SelfHostedIter::AllowContent
:
5327 case SelfHostedIter::AllowContentWith
: {
5328 // This is the following case:
5330 // for (const nextValue of allowContentIterWith(items, usingIterator)) {
5332 // `items` is emitted by `emitTree(value)` above, and the result is on the
5333 // stack as ITERABLE.
5334 // `usingIterator` is the value of `items[Symbol.iterator]`, that's
5335 // already retrieved.
5336 ListNode
* argsList
= value
->as
<CallNode
>().args();
5337 MOZ_ASSERT_IF(iterKind
== IteratorKind::Sync
, argsList
->count() == 2);
5338 MOZ_ASSERT_IF(iterKind
== IteratorKind::Async
, argsList
->count() == 3);
5340 if (!emitTree(argsList
->head()->pn_next
)) {
5341 // [stack] ITERABLE ITERFN
5345 // Async iterator has two possible iterators: An async iterator and a sync
5347 if (iterKind
== IteratorKind::Async
) {
5348 if (!emitTree(argsList
->head()->pn_next
->pn_next
)) {
5349 // [stack] ITERABLE ASYNC_ITERFN SYNC_ITERFN
5354 // [stack] ITERABLE ASYNC_ITERFN? SYNC_ITERFN
5358 case SelfHostedIter::AllowContentWithNext
: {
5359 // This is the following case:
5361 // for (const nextValue of allowContentIterWithNext(iterator, next)) {
5363 // `iterator` is emitted by `emitTree(value)` above, and the result is on
5364 // the stack as ITER.
5365 // `next` is the value of `iterator.next`, that's already retrieved.
5366 ListNode
* argsList
= value
->as
<CallNode
>().args();
5367 MOZ_ASSERT(argsList
->count() == 2);
5369 if (!emitTree(argsList
->head()->pn_next
)) {
5370 // [stack] ITER NEXT
5374 if (!emit1(JSOp::Swap
)) {
5375 // [stack] NEXT ITER
5379 // [stack] NEXT ITER
5384 MOZ_CRASH("invalid self-hosted iteration kind");
5387 bool BytecodeEmitter::emitIterator(SelfHostedIter selfHostedIter
) {
5388 MOZ_ASSERT(selfHostedIter
!= SelfHostedIter::Deny
||
5389 emitterMode
!= BytecodeEmitter::SelfHosting
,
5390 "[Symbol.iterator]() call is prohibited in self-hosted code "
5391 "because it can run user-modifiable iteration code");
5393 if (selfHostedIter
== SelfHostedIter::AllowContentWithNext
) {
5394 // [stack] NEXT ITER
5396 // Nothing to do, stack already contains the iterator and its `next` method.
5400 if (selfHostedIter
!= SelfHostedIter::AllowContentWith
) {
5403 // Convert iterable to iterator.
5404 if (!emit1(JSOp::Dup
)) {
5408 if (!emit2(JSOp::Symbol
, uint8_t(JS::SymbolCode::iterator
))) {
5409 // [stack] OBJ OBJ @@ITERATOR
5412 if (!emitElemOpBase(JSOp::GetElem
)) {
5413 // [stack] OBJ ITERFN
5418 if (!emit1(JSOp::Swap
)) {
5419 // [stack] ITERFN OBJ
5422 if (!emitCall(getIterCallOp(JSOp::CallIter
, selfHostedIter
), 0)) {
5426 if (!emitCheckIsObj(CheckIsObjectKind::GetIterator
)) {
5430 if (!emit1(JSOp::Dup
)) {
5431 // [stack] ITER ITER
5434 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::next())) {
5435 // [stack] ITER NEXT
5438 if (!emit1(JSOp::Swap
)) {
5439 // [stack] NEXT ITER
5445 bool BytecodeEmitter::emitAsyncIterator(SelfHostedIter selfHostedIter
) {
5446 MOZ_ASSERT(selfHostedIter
!= SelfHostedIter::AllowContentWithNext
);
5447 MOZ_ASSERT(selfHostedIter
!= SelfHostedIter::Deny
||
5448 emitterMode
!= BytecodeEmitter::SelfHosting
,
5449 "[Symbol.asyncIterator]() call is prohibited in self-hosted code "
5450 "because it can run user-modifiable iteration code");
5452 if (selfHostedIter
!= SelfHostedIter::AllowContentWith
) {
5455 // Convert iterable to iterator.
5456 if (!emit1(JSOp::Dup
)) {
5460 if (!emit2(JSOp::Symbol
, uint8_t(JS::SymbolCode::asyncIterator
))) {
5461 // [stack] OBJ OBJ @@ASYNCITERATOR
5464 if (!emitElemOpBase(JSOp::GetElem
)) {
5465 // [stack] OBJ ASYNC_ITERFN
5469 // [stack] OBJ ASYNC_ITERFN SYNC_ITERFN
5471 if (!emitElemOpBase(JSOp::Swap
)) {
5472 // [stack] OBJ SYNC_ITERFN ASYNC_ITERFN
5477 InternalIfEmitter
ifAsyncIterIsUndefined(this);
5478 if (!emit1(JSOp::IsNullOrUndefined
)) {
5479 // [stack] OBJ SYNC_ITERFN? ASYNC_ITERFN NULL-OR-UNDEF
5482 if (!ifAsyncIterIsUndefined
.emitThenElse()) {
5483 // [stack] OBJ SYNC_ITERFN? ASYNC_ITERFN
5487 if (!emit1(JSOp::Pop
)) {
5488 // [stack] OBJ SYNC_ITERFN?
5492 if (selfHostedIter
!= SelfHostedIter::AllowContentWith
) {
5493 if (!emit1(JSOp::Dup
)) {
5497 if (!emit2(JSOp::Symbol
, uint8_t(JS::SymbolCode::iterator
))) {
5498 // [stack] OBJ OBJ @@ITERATOR
5501 if (!emitElemOpBase(JSOp::GetElem
)) {
5502 // [stack] OBJ SYNC_ITERFN
5506 // [stack] OBJ SYNC_ITERFN
5509 if (!emit1(JSOp::Swap
)) {
5510 // [stack] SYNC_ITERFN OBJ
5513 if (!emitCall(getIterCallOp(JSOp::CallIter
, selfHostedIter
), 0)) {
5517 if (!emitCheckIsObj(CheckIsObjectKind::GetIterator
)) {
5522 if (!emit1(JSOp::Dup
)) {
5523 // [stack] ITER ITER
5526 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::next())) {
5527 // [stack] ITER SYNCNEXT
5531 if (!emit1(JSOp::ToAsyncIter
)) {
5536 if (!ifAsyncIterIsUndefined
.emitElse()) {
5537 // [stack] OBJ SYNC_ITERFN? ASYNC_ITERFN
5541 if (selfHostedIter
== SelfHostedIter::AllowContentWith
) {
5542 if (!emit1(JSOp::Swap
)) {
5543 // [stack] OBJ ASYNC_ITERFN SYNC_ITERFN
5546 if (!emit1(JSOp::Pop
)) {
5547 // [stack] OBJ ASYNC_ITERFN
5552 if (!emit1(JSOp::Swap
)) {
5553 // [stack] ASYNC_ITERFN OBJ
5556 if (!emitCall(getIterCallOp(JSOp::CallIter
, selfHostedIter
), 0)) {
5560 if (!emitCheckIsObj(CheckIsObjectKind::GetAsyncIterator
)) {
5565 if (!ifAsyncIterIsUndefined
.emitEnd()) {
5570 if (!emit1(JSOp::Dup
)) {
5571 // [stack] ITER ITER
5574 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::next())) {
5575 // [stack] ITER NEXT
5578 if (!emit1(JSOp::Swap
)) {
5579 // [stack] NEXT ITER
5586 bool BytecodeEmitter::emitSpread(SelfHostedIter selfHostedIter
) {
5587 // [stack] NEXT ITER ARR I
5588 return emitSpread(selfHostedIter
, 2, JSOp::InitElemInc
);
5589 // [stack] ARR FINAL_INDEX
5592 bool BytecodeEmitter::emitSpread(SelfHostedIter selfHostedIter
,
5593 int spreadeeStackItems
, JSOp storeElementOp
) {
5594 LoopControl
loopInfo(this, StatementKind::Spread
);
5595 // In the [stack] annotations, (spreadee) can be "ARR I" (when spreading
5596 // into an array or into call parameters, or "TUPLE" (when spreading into a
5599 if (!loopInfo
.emitLoopHead(this, Nothing())) {
5600 // [stack] NEXT ITER (spreadee)
5606 auto loopDepth
= bytecodeSection().stackDepth();
5609 // Spread operations can't contain |continue|, so don't bother setting loop
5610 // and enclosing "update" offsets, as we do with for-loops.
5612 if (!emitDupAt(spreadeeStackItems
+ 1, 2)) {
5613 // [stack] NEXT ITER (spreadee) NEXT ITER
5616 if (!emitIteratorNext(Nothing(), IteratorKind::Sync
, selfHostedIter
)) {
5617 // [stack] NEXT ITER (spreadee) RESULT
5620 if (!emit1(JSOp::Dup
)) {
5621 // [stack] NEXT ITER (spreadee) RESULT RESULT
5624 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::done())) {
5625 // [stack] NEXT ITER (spreadee) RESULT DONE
5628 if (!emitJump(JSOp::JumpIfTrue
, &loopInfo
.breaks
)) {
5629 // [stack] NEXT ITER (spreadee) RESULT
5633 // Emit code to assign result.value to the iteration variable.
5634 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::value())) {
5635 // [stack] NEXT ITER (spreadee) VALUE
5638 if (!emit1(storeElementOp
)) {
5639 // [stack] NEXT ITER (spreadee)
5643 if (!loopInfo
.emitLoopEnd(this, JSOp::Goto
, TryNoteKind::ForOf
)) {
5644 // [stack] NEXT ITER (spreadee)
5648 MOZ_ASSERT(bytecodeSection().stackDepth() == loopDepth
);
5651 // When we leave the loop body and jump to this point, the result value is
5652 // still on the stack. Account for that by updating the stack depth
5654 bytecodeSection().setStackDepth(bytecodeSection().stackDepth() + 1);
5656 // No continues should occur in spreads.
5657 MOZ_ASSERT(!loopInfo
.continues
.offset
.valid());
5659 if (!emit2(JSOp::Pick
, spreadeeStackItems
+ 2)) {
5660 // [stack] ITER (spreadee) RESULT NEXT
5663 if (!emit2(JSOp::Pick
, spreadeeStackItems
+ 2)) {
5664 // [stack] (spreadee) RESULT NEXT ITER
5669 // [stack] (spreadee)
5672 bool BytecodeEmitter::emitInitializeForInOrOfTarget(TernaryNode
* forHead
) {
5673 MOZ_ASSERT(forHead
->isKind(ParseNodeKind::ForIn
) ||
5674 forHead
->isKind(ParseNodeKind::ForOf
));
5676 MOZ_ASSERT(bytecodeSection().stackDepth() >= 1,
5677 "must have a per-iteration value for initializing");
5679 ParseNode
* target
= forHead
->kid1();
5680 MOZ_ASSERT(!forHead
->kid2());
5682 // If the for-in/of loop didn't have a variable declaration, per-loop
5683 // initialization is just assigning the iteration value to a target
5685 if (!target
->is
<DeclarationListNode
>()) {
5686 return emitAssignmentOrInit(ParseNodeKind::AssignExpr
, target
, nullptr);
5687 // [stack] ... ITERVAL
5690 // Otherwise, per-loop initialization is (possibly) declaration
5691 // initialization. If the declaration is a lexical declaration, it must be
5692 // initialized. If the declaration is a variable declaration, an
5693 // assignment to that name (which does *not* necessarily assign to the
5694 // variable!) must be generated.
5696 auto* declarationList
= &target
->as
<DeclarationListNode
>();
5697 if (!updateSourceCoordNotes(declarationList
->pn_pos
.begin
)) {
5701 target
= declarationList
->singleBinding();
5703 NameNode
* nameNode
= nullptr;
5704 if (target
->isKind(ParseNodeKind::Name
)) {
5705 nameNode
= &target
->as
<NameNode
>();
5706 } else if (target
->isKind(ParseNodeKind::AssignExpr
)) {
5707 BinaryNode
* assignNode
= &target
->as
<BinaryNode
>();
5708 if (assignNode
->left()->is
<NameNode
>()) {
5709 nameNode
= &assignNode
->left()->as
<NameNode
>();
5714 auto nameAtom
= nameNode
->name();
5715 NameOpEmitter
noe(this, nameAtom
, NameOpEmitter::Kind::Initialize
);
5716 if (!noe
.prepareForRhs()) {
5719 if (noe
.emittedBindOp()) {
5720 // Per-iteration initialization in for-in/of loops computes the
5721 // iteration value *before* initializing. Thus the initializing
5722 // value may be buried under a bind-specific value on the stack.
5723 // Swap it to the top of the stack.
5724 MOZ_ASSERT(bytecodeSection().stackDepth() >= 2);
5725 if (!emit1(JSOp::Swap
)) {
5729 // In cases of emitting a frame slot or environment slot,
5730 // nothing needs be done.
5731 MOZ_ASSERT(bytecodeSection().stackDepth() >= 1);
5733 if (!noe
.emitAssignment()) {
5737 // The caller handles removing the iteration value from the stack.
5742 !target
->isKind(ParseNodeKind::AssignExpr
),
5743 "for-in/of loop destructuring declarations can't have initializers");
5745 MOZ_ASSERT(target
->isKind(ParseNodeKind::ArrayExpr
) ||
5746 target
->isKind(ParseNodeKind::ObjectExpr
));
5747 return emitDestructuringOps(&target
->as
<ListNode
>(),
5748 DestructuringFlavor::Declaration
);
5751 bool BytecodeEmitter::emitForOf(ForNode
* forOfLoop
,
5752 const EmitterScope
* headLexicalEmitterScope
) {
5753 MOZ_ASSERT(forOfLoop
->isKind(ParseNodeKind::ForStmt
));
5755 TernaryNode
* forOfHead
= forOfLoop
->head();
5756 MOZ_ASSERT(forOfHead
->isKind(ParseNodeKind::ForOf
));
5758 unsigned iflags
= forOfLoop
->iflags();
5759 IteratorKind iterKind
=
5760 (iflags
& JSITER_FORAWAITOF
) ? IteratorKind::Async
: IteratorKind::Sync
;
5761 MOZ_ASSERT_IF(iterKind
== IteratorKind::Async
, sc
->isSuspendableContext());
5762 MOZ_ASSERT_IF(iterKind
== IteratorKind::Async
,
5763 sc
->asSuspendableContext()->isAsync());
5765 ParseNode
* forHeadExpr
= forOfHead
->kid3();
5767 // Certain builtins (e.g. Array.from) are implemented in self-hosting
5769 auto selfHostedIter
= getSelfHostedIterFor(forHeadExpr
);
5770 ForOfEmitter
forOf(this, headLexicalEmitterScope
, selfHostedIter
, iterKind
);
5772 if (!forOf
.emitIterated()) {
5777 if (!updateSourceCoordNotes(forHeadExpr
->pn_pos
.begin
)) {
5780 if (!markStepBreakpoint()) {
5783 if (!emitIterable(forHeadExpr
, selfHostedIter
, iterKind
)) {
5788 if (headLexicalEmitterScope
) {
5789 DebugOnly
<ParseNode
*> forOfTarget
= forOfHead
->kid1();
5790 MOZ_ASSERT(forOfTarget
->isKind(ParseNodeKind::LetDecl
) ||
5791 forOfTarget
->isKind(ParseNodeKind::ConstDecl
));
5794 if (!forOf
.emitInitialize(forOfHead
->pn_pos
.begin
)) {
5795 // [stack] NEXT ITER VALUE
5799 if (!emitInitializeForInOrOfTarget(forOfHead
)) {
5800 // [stack] NEXT ITER VALUE
5804 if (!forOf
.emitBody()) {
5805 // [stack] NEXT ITER UNDEF
5809 // Perform the loop body.
5810 ParseNode
* forBody
= forOfLoop
->body();
5811 if (!emitTree(forBody
)) {
5812 // [stack] NEXT ITER UNDEF
5816 if (!forOf
.emitEnd(forHeadExpr
->pn_pos
.begin
)) {
5824 bool BytecodeEmitter::emitForIn(ForNode
* forInLoop
,
5825 const EmitterScope
* headLexicalEmitterScope
) {
5826 TernaryNode
* forInHead
= forInLoop
->head();
5827 MOZ_ASSERT(forInHead
->isKind(ParseNodeKind::ForIn
));
5829 ForInEmitter
forIn(this, headLexicalEmitterScope
);
5831 // Annex B: Evaluate the var-initializer expression if present.
5832 // |for (var i = initializer in expr) { ... }|
5833 ParseNode
* forInTarget
= forInHead
->kid1();
5834 if (forInTarget
->is
<DeclarationListNode
>()) {
5835 auto* declarationList
= &forInTarget
->as
<DeclarationListNode
>();
5837 ParseNode
* decl
= declarationList
->singleBinding();
5838 if (decl
->isKind(ParseNodeKind::AssignExpr
)) {
5839 BinaryNode
* assignNode
= &decl
->as
<BinaryNode
>();
5840 if (assignNode
->left()->is
<NameNode
>()) {
5841 NameNode
* nameNode
= &assignNode
->left()->as
<NameNode
>();
5842 ParseNode
* initializer
= assignNode
->right();
5844 forInTarget
->isKind(ParseNodeKind::VarStmt
),
5845 "for-in initializers are only permitted for |var| declarations");
5847 if (!updateSourceCoordNotes(decl
->pn_pos
.begin
)) {
5851 auto nameAtom
= nameNode
->name();
5852 NameOpEmitter
noe(this, nameAtom
, NameOpEmitter::Kind::Initialize
);
5853 if (!noe
.prepareForRhs()) {
5856 if (!emitInitializer(initializer
, nameNode
)) {
5859 if (!noe
.emitAssignment()) {
5863 // Pop the initializer.
5864 if (!emit1(JSOp::Pop
)) {
5871 if (!forIn
.emitIterated()) {
5876 // Evaluate the expression being iterated.
5877 ParseNode
* expr
= forInHead
->kid3();
5879 if (!updateSourceCoordNotes(expr
->pn_pos
.begin
)) {
5882 if (!markStepBreakpoint()) {
5885 if (!emitTree(expr
)) {
5890 MOZ_ASSERT(forInLoop
->iflags() == 0);
5892 MOZ_ASSERT_IF(headLexicalEmitterScope
,
5893 forInTarget
->isKind(ParseNodeKind::LetDecl
) ||
5894 forInTarget
->isKind(ParseNodeKind::ConstDecl
));
5896 if (!forIn
.emitInitialize()) {
5897 // [stack] ITER ITERVAL
5901 if (!emitInitializeForInOrOfTarget(forInHead
)) {
5902 // [stack] ITER ITERVAL
5906 if (!forIn
.emitBody()) {
5907 // [stack] ITER ITERVAL
5911 // Perform the loop body.
5912 ParseNode
* forBody
= forInLoop
->body();
5913 if (!emitTree(forBody
)) {
5914 // [stack] ITER ITERVAL
5918 if (!forIn
.emitEnd(forInHead
->pn_pos
.begin
)) {
5926 /* C-style `for (init; cond; update) ...` loop. */
5927 bool BytecodeEmitter::emitCStyleFor(
5928 ForNode
* forNode
, const EmitterScope
* headLexicalEmitterScope
) {
5929 TernaryNode
* forHead
= forNode
->head();
5930 ParseNode
* forBody
= forNode
->body();
5931 ParseNode
* init
= forHead
->kid1();
5932 ParseNode
* cond
= forHead
->kid2();
5933 ParseNode
* update
= forHead
->kid3();
5934 bool isLet
= init
&& init
->isKind(ParseNodeKind::LetDecl
);
5936 CForEmitter
cfor(this, isLet
? headLexicalEmitterScope
: nullptr);
5938 if (!cfor
.emitInit(init
? Some(init
->pn_pos
.begin
) : Nothing())) {
5943 // If the head of this for-loop declared any lexical variables, the parser
5944 // wrapped this ParseNodeKind::For node in a ParseNodeKind::LexicalScope
5945 // representing the implicit scope of those variables. By the time we get
5946 // here, we have already entered that scope. So far, so good.
5948 // Emit the `init` clause, whether it's an expression or a variable
5949 // declaration. (The loop variables were hoisted into an enclosing
5950 // scope, but we still need to emit code for the initializers.)
5951 if (init
->is
<DeclarationListNode
>()) {
5952 MOZ_ASSERT(!init
->as
<DeclarationListNode
>().empty());
5954 if (!emitTree(init
)) {
5959 if (!updateSourceCoordNotes(init
->pn_pos
.begin
)) {
5962 if (!markStepBreakpoint()) {
5966 // 'init' is an expression, not a declaration. emitTree left its
5967 // value on the stack.
5968 if (!emitTree(init
, ValueUsage::IgnoreValue
)) {
5972 if (!emit1(JSOp::Pop
)) {
5979 if (!cfor
.emitCond(cond
? Some(cond
->pn_pos
.begin
) : Nothing())) {
5985 if (!updateSourceCoordNotes(cond
->pn_pos
.begin
)) {
5988 if (!markStepBreakpoint()) {
5991 if (!emitTree(cond
)) {
5997 if (!cfor
.emitBody(cond
? CForEmitter::Cond::Present
5998 : CForEmitter::Cond::Missing
)) {
6003 if (!emitTree(forBody
)) {
6008 if (!cfor
.emitUpdate(
6009 update
? CForEmitter::Update::Present
: CForEmitter::Update::Missing
,
6010 update
? Some(update
->pn_pos
.begin
) : Nothing())) {
6015 // Check for update code to do before the condition (if any).
6017 if (!updateSourceCoordNotes(update
->pn_pos
.begin
)) {
6020 if (!markStepBreakpoint()) {
6023 if (!emitTree(update
, ValueUsage::IgnoreValue
)) {
6029 if (!cfor
.emitEnd(forNode
->pn_pos
.begin
)) {
6037 bool BytecodeEmitter::emitFor(ForNode
* forNode
,
6038 const EmitterScope
* headLexicalEmitterScope
) {
6039 if (forNode
->head()->isKind(ParseNodeKind::ForHead
)) {
6040 return emitCStyleFor(forNode
, headLexicalEmitterScope
);
6043 if (!updateLineNumberNotes(forNode
->pn_pos
.begin
)) {
6047 if (forNode
->head()->isKind(ParseNodeKind::ForIn
)) {
6048 return emitForIn(forNode
, headLexicalEmitterScope
);
6051 MOZ_ASSERT(forNode
->head()->isKind(ParseNodeKind::ForOf
));
6052 return emitForOf(forNode
, headLexicalEmitterScope
);
6055 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitFunction(
6056 FunctionNode
* funNode
, bool needsProto
/* = false */) {
6057 FunctionBox
* funbox
= funNode
->funbox();
6061 FunctionEmitter
fe(this, funbox
, funNode
->syntaxKind(),
6062 funNode
->functionIsHoisted()
6063 ? FunctionEmitter::IsHoisted::Yes
6064 : FunctionEmitter::IsHoisted::No
);
6066 // |wasEmittedByEnclosingScript| flag is set to true once the function has
6067 // been emitted. Function definitions that need hoisting to the top of the
6068 // function will be seen by emitFunction in two places.
6069 if (funbox
->wasEmittedByEnclosingScript()) {
6070 if (!fe
.emitAgain()) {
6074 MOZ_ASSERT(funNode
->functionIsHoisted());
6075 } else if (funbox
->isInterpreted()) {
6076 if (!funbox
->emitBytecode
) {
6077 return fe
.emitLazy();
6081 if (!fe
.prepareForNonLazy()) {
6086 BytecodeEmitter
bce2(this, funbox
);
6087 if (!bce2
.init(funNode
->pn_pos
)) {
6091 /* We measured the max scope depth when we parsed the function. */
6092 if (!bce2
.emitFunctionScript(funNode
)) {
6096 if (!fe
.emitNonLazyEnd()) {
6101 if (!fe
.emitAsmJSModule()) {
6107 // Track the last emitted top-level self-hosted function, so that intrinsics
6108 // can adjust attributes at parse time.
6110 // NOTE: We also disallow lambda functions in the top-level body. This is done
6111 // to simplify handling of the self-hosted stencil. Within normal function
6112 // declarations there are no such restrictions.
6113 if (emitterMode
== EmitterMode::SelfHosting
) {
6114 if (sc
->isTopLevelContext()) {
6115 MOZ_ASSERT(!funbox
->isLambda());
6116 MOZ_ASSERT(funbox
->explicitName());
6117 prevSelfHostedTopLevelFunction
= funbox
;
6124 bool BytecodeEmitter::emitDo(BinaryNode
* doNode
) {
6125 ParseNode
* bodyNode
= doNode
->left();
6127 DoWhileEmitter
doWhile(this);
6128 if (!doWhile
.emitBody(doNode
->pn_pos
.begin
, getOffsetForLoop(bodyNode
))) {
6132 if (!emitTree(bodyNode
)) {
6136 if (!doWhile
.emitCond()) {
6140 ParseNode
* condNode
= doNode
->right();
6141 if (!updateSourceCoordNotes(condNode
->pn_pos
.begin
)) {
6144 if (!markStepBreakpoint()) {
6147 if (!emitTree(condNode
)) {
6151 if (!doWhile
.emitEnd()) {
6158 bool BytecodeEmitter::emitWhile(BinaryNode
* whileNode
) {
6159 ParseNode
* bodyNode
= whileNode
->right();
6161 WhileEmitter
wh(this);
6163 ParseNode
* condNode
= whileNode
->left();
6164 if (!wh
.emitCond(whileNode
->pn_pos
.begin
, getOffsetForLoop(condNode
),
6165 whileNode
->pn_pos
.end
)) {
6169 if (!updateSourceCoordNotes(condNode
->pn_pos
.begin
)) {
6172 if (!markStepBreakpoint()) {
6175 if (!emitTree(condNode
)) {
6179 if (!wh
.emitBody()) {
6182 if (!emitTree(bodyNode
)) {
6186 if (!wh
.emitEnd()) {
6193 bool BytecodeEmitter::emitBreak(TaggedParserAtomIndex label
) {
6194 BreakableControl
* target
;
6196 // Any statement with the matching label may be the break target.
6197 auto hasSameLabel
= [label
](LabelControl
* labelControl
) {
6198 return labelControl
->label() == label
;
6200 target
= findInnermostNestableControl
<LabelControl
>(hasSameLabel
);
6202 auto isNotLabel
= [](BreakableControl
* control
) {
6203 return !control
->is
<LabelControl
>();
6205 target
= findInnermostNestableControl
<BreakableControl
>(isNotLabel
);
6208 return emitGoto(target
, GotoKind::Break
);
6211 bool BytecodeEmitter::emitContinue(TaggedParserAtomIndex label
) {
6212 LoopControl
* target
= nullptr;
6214 // Find the loop statement enclosed by the matching label.
6215 NestableControl
* control
= innermostNestableControl
;
6216 while (!control
->is
<LabelControl
>() ||
6217 control
->as
<LabelControl
>().label() != label
) {
6218 if (control
->is
<LoopControl
>()) {
6219 target
= &control
->as
<LoopControl
>();
6221 control
= control
->enclosing();
6224 target
= findInnermostNestableControl
<LoopControl
>();
6226 return emitGoto(target
, GotoKind::Continue
);
6229 bool BytecodeEmitter::emitGetFunctionThis(NameNode
* thisName
) {
6230 MOZ_ASSERT(sc
->hasFunctionThisBinding());
6231 MOZ_ASSERT(thisName
->isName(TaggedParserAtomIndex::WellKnown::dot_this_()));
6233 if (!updateLineNumberNotes(thisName
->pn_pos
.begin
)) {
6237 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
6241 if (sc
->needsThisTDZChecks()) {
6242 if (!emit1(JSOp::CheckThis
)) {
6251 bool BytecodeEmitter::emitGetThisForSuperBase(UnaryNode
* superBase
) {
6252 MOZ_ASSERT(superBase
->isKind(ParseNodeKind::SuperBase
));
6253 NameNode
* nameNode
= &superBase
->kid()->as
<NameNode
>();
6254 return emitGetFunctionThis(nameNode
);
6258 bool BytecodeEmitter::emitThisLiteral(ThisLiteral
* pn
) {
6259 if (ParseNode
* kid
= pn
->kid()) {
6260 NameNode
* thisName
= &kid
->as
<NameNode
>();
6261 return emitGetFunctionThis(thisName
);
6265 if (sc
->thisBinding() == ThisBinding::Module
) {
6266 return emit1(JSOp::Undefined
);
6270 MOZ_ASSERT(sc
->thisBinding() == ThisBinding::Global
);
6272 MOZ_ASSERT(outermostScope().hasNonSyntacticScopeOnChain() ==
6273 sc
->hasNonSyntacticScope());
6274 if (sc
->hasNonSyntacticScope()) {
6275 return emit1(JSOp::NonSyntacticGlobalThis
);
6279 return emit1(JSOp::GlobalThis
);
6283 bool BytecodeEmitter::emitCheckDerivedClassConstructorReturn() {
6285 lookupName(TaggedParserAtomIndex::WellKnown::dot_this_()).hasKnownSlot());
6286 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
6289 if (!emit1(JSOp::CheckReturn
)) {
6292 if (!emit1(JSOp::SetRval
)) {
6298 bool BytecodeEmitter::emitNewTarget() {
6299 MOZ_ASSERT(sc
->allowNewTarget());
6301 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_newTarget_())) {
6302 // [stack] NEW.TARGET
6308 bool BytecodeEmitter::emitNewTarget(NewTargetNode
* pn
) {
6309 MOZ_ASSERT(pn
->newTargetName()->isName(
6310 TaggedParserAtomIndex::WellKnown::dot_newTarget_()));
6312 return emitNewTarget();
6315 bool BytecodeEmitter::emitNewTarget(CallNode
* pn
) {
6316 MOZ_ASSERT(pn
->callOp() == JSOp::SuperCall
||
6317 pn
->callOp() == JSOp::SpreadSuperCall
);
6319 // The parser is responsible for marking the "new.target" binding as being
6320 // implicitly used in super() calls.
6321 return emitNewTarget();
6324 bool BytecodeEmitter::emitReturn(UnaryNode
* returnNode
) {
6325 if (!updateSourceCoordNotes(returnNode
->pn_pos
.begin
)) {
6329 if (!markStepBreakpoint()) {
6333 /* Push a return value */
6334 if (ParseNode
* expr
= returnNode
->kid()) {
6335 if (!emitTree(expr
)) {
6339 if (sc
->asSuspendableContext()->isAsync() &&
6340 sc
->asSuspendableContext()->isGenerator()) {
6341 if (!emitAwaitInInnermostScope()) {
6346 /* No explicit return value provided */
6347 if (!emit1(JSOp::Undefined
)) {
6352 // We know functionBodyEndPos is set because "return" is only
6353 // valid in a function, and so we've passed through
6354 // emitFunctionScript.
6355 if (!updateSourceCoordNotes(*functionBodyEndPos
)) {
6360 * The return value is currently on the stack. We would like to
6361 * generate JSOp::Return, but if we have work to do before returning,
6362 * we will instead generate JSOp::SetRval / JSOp::RetRval.
6364 * We don't know whether we will need fixup code until after calling
6365 * prepareForNonLocalJumpToOutermost, so we start by generating
6366 * JSOp::SetRval, then mutate it to JSOp::Return in finishReturn if it
6369 BytecodeOffset setRvalOffset
= bytecodeSection().offset();
6370 if (!emit1(JSOp::SetRval
)) {
6374 NonLocalExitControl
nle(this, NonLocalExitKind::Return
);
6375 return nle
.emitReturn(setRvalOffset
);
6378 bool BytecodeEmitter::finishReturn(BytecodeOffset setRvalOffset
) {
6379 // The return value is currently in rval. Depending on the current function,
6380 // we may have to do additional work before returning:
6381 // - Derived class constructors must check if the return value is an object.
6382 // - Generators and async functions must do a final yield.
6383 // - Non-async generators must return the value as an iterator result:
6384 // { value: <rval>, done: true }
6385 // - Non-generator async functions must resolve the function's result promise
6388 // If we have not generated any code since the SetRval that stored the return
6389 // value, we can also optimize the bytecode by rewriting that SetRval as a
6390 // JSOp::Return. See |emitReturn| above.
6392 bool isDerivedClassConstructor
=
6393 sc
->isFunctionBox() && sc
->asFunctionBox()->isDerivedClassConstructor();
6394 bool needsFinalYield
=
6395 sc
->isFunctionBox() && sc
->asFunctionBox()->needsFinalYield();
6396 bool isSimpleReturn
=
6397 setRvalOffset
.valid() &&
6398 setRvalOffset
+ BytecodeOffsetDiff(JSOpLength_SetRval
) ==
6399 bytecodeSection().offset();
6401 if (isDerivedClassConstructor
) {
6402 MOZ_ASSERT(!needsFinalYield
);
6403 if (!emitJump(JSOp::Goto
, &endOfDerivedClassConstructorBody
)) {
6409 if (needsFinalYield
) {
6410 if (!emitJump(JSOp::Goto
, &finalYields
)) {
6416 if (isSimpleReturn
) {
6417 MOZ_ASSERT(JSOp(bytecodeSection().code()[setRvalOffset
.value()]) ==
6419 bytecodeSection().code()[setRvalOffset
.value()] = jsbytecode(JSOp::Return
);
6423 // Nothing special needs to be done.
6424 return emitReturnRval();
6427 bool BytecodeEmitter::emitGetDotGeneratorInScope(EmitterScope
& currentScope
) {
6428 if (!sc
->isFunction() && sc
->isModuleContext() &&
6429 sc
->asModuleContext()->isAsync()) {
6430 NameLocation loc
= *locationOfNameBoundInScopeType
<ModuleScope
>(
6431 TaggedParserAtomIndex::WellKnown::dot_generator_(), ¤tScope
);
6432 return emitGetNameAtLocation(
6433 TaggedParserAtomIndex::WellKnown::dot_generator_(), loc
);
6435 NameLocation loc
= *locationOfNameBoundInScopeType
<FunctionScope
>(
6436 TaggedParserAtomIndex::WellKnown::dot_generator_(), ¤tScope
);
6437 return emitGetNameAtLocation(
6438 TaggedParserAtomIndex::WellKnown::dot_generator_(), loc
);
6441 bool BytecodeEmitter::emitInitialYield(UnaryNode
* yieldNode
) {
6442 if (!emitTree(yieldNode
->kid())) {
6446 if (!emitYieldOp(JSOp::InitialYield
)) {
6447 // [stack] RVAL GENERATOR RESUMEKIND
6450 if (!emit1(JSOp::CheckResumeKind
)) {
6454 if (!emit1(JSOp::Pop
)) {
6462 bool BytecodeEmitter::emitYield(UnaryNode
* yieldNode
) {
6463 MOZ_ASSERT(sc
->isFunctionBox());
6464 MOZ_ASSERT(sc
->asFunctionBox()->isGenerator());
6465 MOZ_ASSERT(yieldNode
->isKind(ParseNodeKind::YieldExpr
));
6467 bool needsIteratorResult
= sc
->asFunctionBox()->needsIteratorResult();
6468 if (needsIteratorResult
) {
6469 if (!emitPrepareIteratorResult()) {
6474 if (ParseNode
* expr
= yieldNode
->kid()) {
6475 if (!emitTree(expr
)) {
6476 // [stack] ITEROBJ? VAL
6480 if (!emit1(JSOp::Undefined
)) {
6481 // [stack] ITEROBJ? UNDEFINED
6486 if (sc
->asSuspendableContext()->isAsync()) {
6487 MOZ_ASSERT(!needsIteratorResult
);
6488 if (!emitAwaitInInnermostScope()) {
6494 if (needsIteratorResult
) {
6495 if (!emitFinishIteratorResult(false)) {
6501 if (!emitGetDotGeneratorInInnermostScope()) {
6502 // [stack] # if needsIteratorResult
6503 // [stack] ITEROBJ .GENERATOR
6505 // [stack] RESULT .GENERATOR
6509 if (!emitYieldOp(JSOp::Yield
)) {
6510 // [stack] YIELDRESULT GENERATOR RESUMEKIND
6514 if (!emit1(JSOp::CheckResumeKind
)) {
6515 // [stack] YIELDRESULT
6522 bool BytecodeEmitter::emitAwaitInInnermostScope(UnaryNode
* awaitNode
) {
6523 MOZ_ASSERT(sc
->isSuspendableContext());
6524 MOZ_ASSERT(awaitNode
->isKind(ParseNodeKind::AwaitExpr
));
6526 if (!emitTree(awaitNode
->kid())) {
6529 return emitAwaitInInnermostScope();
6532 bool BytecodeEmitter::emitAwaitInScope(EmitterScope
& currentScope
) {
6533 if (!emit1(JSOp::CanSkipAwait
)) {
6534 // [stack] VALUE CANSKIP
6538 if (!emit1(JSOp::MaybeExtractAwaitValue
)) {
6539 // [stack] VALUE_OR_RESOLVED CANSKIP
6543 InternalIfEmitter
ifCanSkip(this);
6544 if (!ifCanSkip
.emitThen(IfEmitter::ConditionKind::Negative
)) {
6545 // [stack] VALUE_OR_RESOLVED
6549 if (sc
->asSuspendableContext()->needsPromiseResult()) {
6550 if (!emitGetDotGeneratorInScope(currentScope
)) {
6551 // [stack] VALUE GENERATOR
6554 if (!emit1(JSOp::AsyncAwait
)) {
6560 if (!emitGetDotGeneratorInScope(currentScope
)) {
6561 // [stack] VALUE|PROMISE GENERATOR
6564 if (!emitYieldOp(JSOp::Await
)) {
6565 // [stack] RESOLVED GENERATOR RESUMEKIND
6568 if (!emit1(JSOp::CheckResumeKind
)) {
6573 if (!ifCanSkip
.emitEnd()) {
6577 MOZ_ASSERT(ifCanSkip
.popped() == 0);
6582 // ES2019 draft rev 49b781ec80117b60f73327ef3054703a3111e40c
6583 // 14.4.14 Runtime Semantics: Evaluation
6584 // YieldExpression : yield* AssignmentExpression
6585 bool BytecodeEmitter::emitYieldStar(ParseNode
* iter
) {
6586 MOZ_ASSERT(getSelfHostedIterFor(iter
) == SelfHostedIter::Deny
,
6587 "yield* is prohibited in self-hosted code because it can run "
6588 "user-modifiable iteration code");
6590 MOZ_ASSERT(sc
->isSuspendableContext());
6591 MOZ_ASSERT(sc
->asSuspendableContext()->isGenerator());
6594 IteratorKind iterKind
= sc
->asSuspendableContext()->isAsync()
6595 ? IteratorKind::Async
6596 : IteratorKind::Sync
;
6597 bool needsIteratorResult
= sc
->asSuspendableContext()->needsIteratorResult();
6600 if (!emitTree(iter
)) {
6604 if (iterKind
== IteratorKind::Async
) {
6605 if (!emitAsyncIterator(SelfHostedIter::Deny
)) {
6606 // [stack] NEXT ITER
6610 if (!emitIterator(SelfHostedIter::Deny
)) {
6611 // [stack] NEXT ITER
6617 // Start with NormalCompletion(undefined).
6618 if (!emit1(JSOp::Undefined
)) {
6619 // [stack] NEXT ITER RECEIVED
6622 if (!emitPushResumeKind(GeneratorResumeKind::Next
)) {
6623 // [stack] NEXT ITER RECEIVED RESUMEKIND
6627 const int32_t startDepth
= bytecodeSection().stackDepth();
6628 MOZ_ASSERT(startDepth
>= 4);
6630 // Step 7 is a loop.
6631 LoopControl
loopInfo(this, StatementKind::YieldStar
);
6632 if (!loopInfo
.emitLoopHead(this, Nothing())) {
6633 // [stack] NEXT ITER RECEIVED RESUMEKIND
6637 // Step 7.a. Check for Normal completion.
6638 if (!emit1(JSOp::Dup
)) {
6639 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND
6642 if (!emitPushResumeKind(GeneratorResumeKind::Next
)) {
6643 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND NORMAL
6646 if (!emit1(JSOp::StrictEq
)) {
6647 // [stack] NEXT ITER RECEIVED RESUMEKIND IS_NORMAL
6651 InternalIfEmitter
ifKind(this);
6652 if (!ifKind
.emitThenElse()) {
6653 // [stack] NEXT ITER RECEIVED RESUMEKIND
6657 if (!emit1(JSOp::Pop
)) {
6658 // [stack] NEXT ITER RECEIVED
6663 // result = iter.next(received)
6664 if (!emit2(JSOp::Unpick
, 2)) {
6665 // [stack] RECEIVED NEXT ITER
6668 if (!emit1(JSOp::Dup2
)) {
6669 // [stack] RECEIVED NEXT ITER NEXT ITER
6672 if (!emit2(JSOp::Pick
, 4)) {
6673 // [stack] NEXT ITER NEXT ITER RECEIVED
6676 if (!emitCall(JSOp::Call
, 1, iter
)) {
6677 // [stack] NEXT ITER RESULT
6682 if (iterKind
== IteratorKind::Async
) {
6683 if (!emitAwaitInInnermostScope()) {
6684 // [stack] NEXT ITER RESULT
6690 if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext
)) {
6691 // [stack] NEXT ITER RESULT
6695 // Bytecode for steps 7.a.iv-vii is emitted after the ifKind if-else because
6696 // it's shared with other branches.
6699 // Step 7.b. Check for Throw completion.
6700 if (!ifKind
.emitElseIf(Nothing())) {
6701 // [stack] NEXT ITER RECEIVED RESUMEKIND
6704 if (!emit1(JSOp::Dup
)) {
6705 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND
6708 if (!emitPushResumeKind(GeneratorResumeKind::Throw
)) {
6709 // [stack] NEXT ITER RECEIVED RESUMEKIND RESUMEKIND THROW
6712 if (!emit1(JSOp::StrictEq
)) {
6713 // [stack] NEXT ITER RECEIVED RESUMEKIND IS_THROW
6716 if (!ifKind
.emitThenElse()) {
6717 // [stack] NEXT ITER RECEIVED RESUMEKIND
6721 if (!emit1(JSOp::Pop
)) {
6722 // [stack] NEXT ITER RECEIVED
6726 if (!emitDupAt(1)) {
6727 // [stack] NEXT ITER RECEIVED ITER
6730 if (!emit1(JSOp::Dup
)) {
6731 // [stack] NEXT ITER RECEIVED ITER ITER
6734 if (!emitAtomOp(JSOp::GetProp
,
6735 TaggedParserAtomIndex::WellKnown::throw_())) {
6736 // [stack] NEXT ITER RECEIVED ITER THROW
6741 InternalIfEmitter
ifThrowMethodIsNotDefined(this);
6742 if (!emit1(JSOp::IsNullOrUndefined
)) {
6743 // [stack] NEXT ITER RECEIVED ITER THROW NULL-OR-UNDEF
6747 if (!ifThrowMethodIsNotDefined
.emitThenElse(
6748 IfEmitter::ConditionKind::Negative
)) {
6749 // [stack] NEXT ITER RECEIVED ITER THROW
6754 // RESULT = ITER.throw(EXCEPTION)
6755 if (!emit1(JSOp::Swap
)) {
6756 // [stack] NEXT ITER RECEIVED THROW ITER
6759 if (!emit2(JSOp::Pick
, 2)) {
6760 // [stack] NEXT ITER THROW ITER RECEIVED
6763 if (!emitCall(JSOp::Call
, 1, iter
)) {
6764 // [stack] NEXT ITER RESULT
6769 if (iterKind
== IteratorKind::Async
) {
6770 if (!emitAwaitInInnermostScope()) {
6771 // [stack] NEXT ITER RESULT
6777 if (!emitCheckIsObj(CheckIsObjectKind::IteratorThrow
)) {
6778 // [stack] NEXT ITER RESULT
6782 // Bytecode for steps 7.b.ii.5-8 is emitted after the ifKind if-else because
6783 // it's shared with other branches.
6786 if (!ifThrowMethodIsNotDefined
.emitElse()) {
6787 // [stack] NEXT ITER RECEIVED ITER THROW
6790 if (!emit1(JSOp::Pop
)) {
6791 // [stack] NEXT ITER RECEIVED ITER
6795 // Steps 7.b.iii.1-4.
6797 // If the iterator does not have a "throw" method, it calls IteratorClose
6798 // and then throws a TypeError.
6799 if (!emitIteratorCloseInInnermostScope(iterKind
, CompletionKind::Normal
)) {
6800 // [stack] NEXT ITER RECEIVED ITER
6803 // Steps 7.b.iii.5-6.
6804 if (!emit2(JSOp::ThrowMsg
, uint8_t(ThrowMsgKind::IteratorNoThrow
))) {
6805 // [stack] NEXT ITER RECEIVED ITER
6810 if (!ifThrowMethodIsNotDefined
.emitEnd()) {
6815 // Step 7.c. It must be a Return completion.
6816 if (!ifKind
.emitElse()) {
6817 // [stack] NEXT ITER RECEIVED RESUMEKIND
6821 if (!emit1(JSOp::Pop
)) {
6822 // [stack] NEXT ITER RECEIVED
6828 // Call iterator.return() for receiving a "forced return" completion from
6833 // Get the "return" method.
6834 if (!emitDupAt(1)) {
6835 // [stack] NEXT ITER RECEIVED ITER
6838 if (!emit1(JSOp::Dup
)) {
6839 // [stack] NEXT ITER RECEIVED ITER ITER
6842 if (!emitAtomOp(JSOp::GetProp
,
6843 TaggedParserAtomIndex::WellKnown::return_())) {
6844 // [stack] NEXT ITER RECEIVED ITER RET
6850 // Do nothing if "return" is undefined or null.
6851 InternalIfEmitter
ifReturnMethodIsDefined(this);
6852 if (!emit1(JSOp::IsNullOrUndefined
)) {
6853 // [stack] NEXT ITER RECEIVED ITER RET NULL-OR-UNDEF
6859 // Call "return" with the argument passed to Generator.prototype.return.
6860 if (!ifReturnMethodIsDefined
.emitThenElse(
6861 IfEmitter::ConditionKind::Negative
)) {
6862 // [stack] NEXT ITER RECEIVED ITER RET
6865 if (!emit1(JSOp::Swap
)) {
6866 // [stack] NEXT ITER RECEIVED RET ITER
6869 if (!emit2(JSOp::Pick
, 2)) {
6870 // [stack] NEXT ITER RET ITER RECEIVED
6873 if (needsIteratorResult
) {
6874 if (!emitAtomOp(JSOp::GetProp
,
6875 TaggedParserAtomIndex::WellKnown::value())) {
6876 // [stack] NEXT ITER RET ITER VAL
6880 if (!emitCall(JSOp::Call
, 1)) {
6881 // [stack] NEXT ITER RESULT
6886 if (iterKind
== IteratorKind::Async
) {
6887 if (!emitAwaitInInnermostScope()) {
6888 // [stack] NEXT ITER RESULT
6894 if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn
)) {
6895 // [stack] NEXT ITER RESULT
6899 // Check if the returned object from iterator.return() is done. If not,
6900 // continue yielding.
6902 // Steps 7.c.vii-viii.
6903 InternalIfEmitter
ifReturnDone(this);
6904 if (!emit1(JSOp::Dup
)) {
6905 // [stack] NEXT ITER RESULT RESULT
6908 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::done())) {
6909 // [stack] NEXT ITER RESULT DONE
6912 if (!ifReturnDone
.emitThenElse()) {
6913 // [stack] NEXT ITER RESULT
6918 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::value())) {
6919 // [stack] NEXT ITER VALUE
6922 if (needsIteratorResult
) {
6923 if (!emitPrepareIteratorResult()) {
6924 // [stack] NEXT ITER VALUE RESULT
6927 if (!emit1(JSOp::Swap
)) {
6928 // [stack] NEXT ITER RESULT VALUE
6931 if (!emitFinishIteratorResult(true)) {
6932 // [stack] NEXT ITER RESULT
6937 if (!ifReturnDone
.emitElse()) {
6938 // [stack] NEXT ITER RESULT
6942 // Jump to continue label for steps 7.c.ix-x.
6943 if (!emitJump(JSOp::Goto
, &loopInfo
.continues
)) {
6944 // [stack] NEXT ITER RESULT
6948 if (!ifReturnDone
.emitEnd()) {
6949 // [stack] NEXT ITER RESULT
6954 if (!ifReturnMethodIsDefined
.emitElse()) {
6955 // [stack] NEXT ITER RECEIVED ITER RET
6959 // [stack] NEXT ITER RECEIVED
6962 if (iterKind
== IteratorKind::Async
) {
6964 if (!emitAwaitInInnermostScope()) {
6965 // [stack] NEXT ITER RECEIVED
6969 if (!ifReturnMethodIsDefined
.emitEnd()) {
6970 // [stack] NEXT ITER RECEIVED
6974 // Perform a "forced generator return".
6978 if (!emitGetDotGeneratorInInnermostScope()) {
6979 // [stack] NEXT ITER RESULT GENOBJ
6982 if (!emitPushResumeKind(GeneratorResumeKind::Return
)) {
6983 // [stack] NEXT ITER RESULT GENOBJ RESUMEKIND
6986 if (!emit1(JSOp::CheckResumeKind
)) {
6987 // [stack] NEXT ITER RESULT GENOBJ RESUMEKIND
6992 if (!ifKind
.emitEnd()) {
6993 // [stack] NEXT ITER RESULT
6997 // Shared tail for Normal/Throw completions.
7000 // Steps 7.b.ii.5-6.
7002 // [stack] NEXT ITER RESULT
7004 // if (result.done) break;
7005 if (!emit1(JSOp::Dup
)) {
7006 // [stack] NEXT ITER RESULT RESULT
7009 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::done())) {
7010 // [stack] NEXT ITER RESULT DONE
7013 if (!emitJump(JSOp::JumpIfTrue
, &loopInfo
.breaks
)) {
7014 // [stack] NEXT ITER RESULT
7018 // Steps 7.a.vi-vii.
7019 // Steps 7.b.ii.7-8.
7021 if (!loopInfo
.emitContinueTarget(this)) {
7022 // [stack] NEXT ITER RESULT
7025 if (iterKind
== IteratorKind::Async
) {
7026 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::value())) {
7027 // [stack] NEXT ITER RESULT
7031 if (!emitGetDotGeneratorInInnermostScope()) {
7032 // [stack] NEXT ITER RESULT GENOBJ
7035 if (!emitYieldOp(JSOp::Yield
)) {
7036 // [stack] NEXT ITER RVAL GENOBJ RESUMEKIND
7039 if (!emit1(JSOp::Swap
)) {
7040 // [stack] NEXT ITER RVAL RESUMEKIND GENOBJ
7043 if (!emit1(JSOp::Pop
)) {
7044 // [stack] NEXT ITER RVAL RESUMEKIND
7047 if (!loopInfo
.emitLoopEnd(this, JSOp::Goto
, TryNoteKind::Loop
)) {
7048 // [stack] NEXT ITER RVAL RESUMEKIND
7052 // Jumps to this point have 3 (instead of 4) values on the stack.
7053 MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth
);
7054 bytecodeSection().setStackDepth(startDepth
- 1);
7056 // [stack] NEXT ITER RESULT
7062 if (!emit2(JSOp::Unpick
, 2)) {
7063 // [stack] RESULT NEXT ITER
7070 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::value())) {
7075 MOZ_ASSERT(bytecodeSection().stackDepth() == startDepth
- 3);
7080 bool BytecodeEmitter::emitStatementList(ListNode
* stmtList
) {
7081 for (ParseNode
* stmt
: stmtList
->contents()) {
7082 if (!emitTree(stmt
)) {
7089 bool BytecodeEmitter::emitExpressionStatement(UnaryNode
* exprStmt
) {
7090 MOZ_ASSERT(exprStmt
->isKind(ParseNodeKind::ExpressionStmt
));
7093 * Top-level or called-from-a-native JS_Execute/EvaluateScript,
7094 * debugger, and eval frames may need the value of the ultimate
7095 * expression statement as the script's result, despite the fact
7096 * that it appears useless to the compiler.
7098 * API users may also set the ReadOnlyCompileOptions::noScriptRval option when
7099 * calling JS_Compile* to suppress JSOp::SetRval.
7101 bool wantval
= false;
7102 bool useful
= false;
7103 if (sc
->isTopLevelContext()) {
7104 useful
= wantval
= !sc
->noScriptRval();
7107 /* Don't eliminate expressions with side effects. */
7108 ParseNode
* expr
= exprStmt
->kid();
7110 if (!checkSideEffects(expr
, &useful
)) {
7115 * Don't eliminate apparently useless expressions if they are labeled
7116 * expression statements. The startOffset() test catches the case
7117 * where we are nesting in emitTree for a labeled compound statement.
7119 if (innermostNestableControl
&&
7120 innermostNestableControl
->is
<LabelControl
>() &&
7121 innermostNestableControl
->as
<LabelControl
>().startOffset() >=
7122 bytecodeSection().offset()) {
7128 ValueUsage valueUsage
=
7129 wantval
? ValueUsage::WantValue
: ValueUsage::IgnoreValue
;
7130 ExpressionStatementEmitter
ese(this, valueUsage
);
7131 if (!ese
.prepareForExpr(exprStmt
->pn_pos
.begin
)) {
7134 if (!markStepBreakpoint()) {
7137 if (!emitTree(expr
, valueUsage
)) {
7140 if (!ese
.emitEnd()) {
7148 bool BytecodeEmitter::emitDeleteName(UnaryNode
* deleteNode
) {
7149 MOZ_ASSERT(deleteNode
->isKind(ParseNodeKind::DeleteNameExpr
));
7151 NameNode
* nameExpr
= &deleteNode
->kid()->as
<NameNode
>();
7152 MOZ_ASSERT(nameExpr
->isKind(ParseNodeKind::Name
));
7154 return emitAtomOp(JSOp::DelName
, nameExpr
->atom());
7157 bool BytecodeEmitter::emitDeleteProperty(UnaryNode
* deleteNode
) {
7158 MOZ_ASSERT(deleteNode
->isKind(ParseNodeKind::DeletePropExpr
));
7160 PropertyAccess
* propExpr
= &deleteNode
->kid()->as
<PropertyAccess
>();
7161 PropOpEmitter
poe(this, PropOpEmitter::Kind::Delete
,
7162 propExpr
->as
<PropertyAccess
>().isSuper()
7163 ? PropOpEmitter::ObjKind::Super
7164 : PropOpEmitter::ObjKind::Other
);
7165 if (propExpr
->isSuper()) {
7166 // The expression |delete super.foo;| has to evaluate |super.foo|,
7167 // which could throw if |this| hasn't yet been set by a |super(...)|
7168 // call or the super-base is not an object, before throwing a
7169 // ReferenceError for attempting to delete a super-reference.
7170 UnaryNode
* base
= &propExpr
->expression().as
<UnaryNode
>();
7171 if (!emitGetThisForSuperBase(base
)) {
7176 if (!poe
.prepareForObj()) {
7179 if (!emitPropLHS(propExpr
)) {
7185 if (!poe
.emitDelete(propExpr
->key().atom())) {
7186 // [stack] # if Super
7188 // [stack] # otherwise
7189 // [stack] SUCCEEDED
7196 bool BytecodeEmitter::emitDeleteElement(UnaryNode
* deleteNode
) {
7197 MOZ_ASSERT(deleteNode
->isKind(ParseNodeKind::DeleteElemExpr
));
7199 PropertyByValue
* elemExpr
= &deleteNode
->kid()->as
<PropertyByValue
>();
7200 bool isSuper
= elemExpr
->isSuper();
7201 DebugOnly
<bool> isPrivate
=
7202 elemExpr
->key().isKind(ParseNodeKind::PrivateName
);
7203 MOZ_ASSERT(!isPrivate
);
7205 this, ElemOpEmitter::Kind::Delete
,
7206 isSuper
? ElemOpEmitter::ObjKind::Super
: ElemOpEmitter::ObjKind::Other
);
7208 // The expression |delete super[foo];| has to evaluate |super[foo]|,
7209 // which could throw if |this| hasn't yet been set by a |super(...)|
7210 // call, or trigger side-effects when evaluating ToPropertyKey(foo),
7211 // or also throw when the super-base is not an object, before throwing
7212 // a ReferenceError for attempting to delete a super-reference.
7213 if (!eoe
.prepareForObj()) {
7218 UnaryNode
* base
= &elemExpr
->expression().as
<UnaryNode
>();
7219 if (!emitGetThisForSuperBase(base
)) {
7223 if (!eoe
.prepareForKey()) {
7227 if (!emitTree(&elemExpr
->key())) {
7232 if (!emitElemObjAndKey(elemExpr
, false, eoe
)) {
7237 if (!eoe
.emitDelete()) {
7238 // [stack] # if Super
7240 // [stack] # otherwise
7241 // [stack] SUCCEEDED
7248 bool BytecodeEmitter::emitDeleteExpression(UnaryNode
* deleteNode
) {
7249 MOZ_ASSERT(deleteNode
->isKind(ParseNodeKind::DeleteExpr
));
7251 ParseNode
* expression
= deleteNode
->kid();
7253 // If useless, just emit JSOp::True; otherwise convert |delete <expr>| to
7254 // effectively |<expr>, true|.
7255 bool useful
= false;
7256 if (!checkSideEffects(expression
, &useful
)) {
7261 if (!emitTree(expression
)) {
7264 if (!emit1(JSOp::Pop
)) {
7269 return emit1(JSOp::True
);
7272 bool BytecodeEmitter::emitDeleteOptionalChain(UnaryNode
* deleteNode
) {
7273 MOZ_ASSERT(deleteNode
->isKind(ParseNodeKind::DeleteOptionalChainExpr
));
7275 OptionalEmitter
oe(this, bytecodeSection().stackDepth());
7277 ParseNode
* kid
= deleteNode
->kid();
7278 switch (kid
->getKind()) {
7279 case ParseNodeKind::ElemExpr
:
7280 case ParseNodeKind::OptionalElemExpr
: {
7281 auto* elemExpr
= &kid
->as
<PropertyByValueBase
>();
7282 if (!emitDeleteElementInOptChain(elemExpr
, oe
)) {
7283 // [stack] # If shortcircuit
7284 // [stack] UNDEFINED-OR-NULL
7285 // [stack] # otherwise
7286 // [stack] SUCCEEDED
7292 case ParseNodeKind::DotExpr
:
7293 case ParseNodeKind::OptionalDotExpr
: {
7294 auto* propExpr
= &kid
->as
<PropertyAccessBase
>();
7295 if (!emitDeletePropertyInOptChain(propExpr
, oe
)) {
7296 // [stack] # If shortcircuit
7297 // [stack] UNDEFINED-OR-NULL
7298 // [stack] # otherwise
7299 // [stack] SUCCEEDED
7305 MOZ_ASSERT_UNREACHABLE("Unrecognized optional delete ParseNodeKind");
7308 if (!oe
.emitOptionalJumpTarget(JSOp::True
)) {
7309 // [stack] # If shortcircuit
7311 // [stack] # otherwise
7312 // [stack] SUCCEEDED
7319 bool BytecodeEmitter::emitDeletePropertyInOptChain(PropertyAccessBase
* propExpr
,
7320 OptionalEmitter
& oe
) {
7321 MOZ_ASSERT_IF(propExpr
->is
<PropertyAccess
>(),
7322 !propExpr
->as
<PropertyAccess
>().isSuper());
7323 PropOpEmitter
poe(this, PropOpEmitter::Kind::Delete
,
7324 PropOpEmitter::ObjKind::Other
);
7326 if (!poe
.prepareForObj()) {
7330 if (!emitOptionalTree(&propExpr
->expression(), oe
)) {
7334 if (propExpr
->isKind(ParseNodeKind::OptionalDotExpr
)) {
7335 if (!oe
.emitJumpShortCircuit()) {
7336 // [stack] # if Jump
7337 // [stack] UNDEFINED-OR-NULL
7338 // [stack] # otherwise
7344 if (!poe
.emitDelete(propExpr
->key().atom())) {
7345 // [stack] SUCCEEDED
7352 bool BytecodeEmitter::emitDeleteElementInOptChain(PropertyByValueBase
* elemExpr
,
7353 OptionalEmitter
& oe
) {
7354 MOZ_ASSERT_IF(elemExpr
->is
<PropertyByValue
>(),
7355 !elemExpr
->as
<PropertyByValue
>().isSuper());
7356 ElemOpEmitter
eoe(this, ElemOpEmitter::Kind::Delete
,
7357 ElemOpEmitter::ObjKind::Other
);
7359 if (!eoe
.prepareForObj()) {
7364 if (!emitOptionalTree(&elemExpr
->expression(), oe
)) {
7369 if (elemExpr
->isKind(ParseNodeKind::OptionalElemExpr
)) {
7370 if (!oe
.emitJumpShortCircuit()) {
7371 // [stack] # if Jump
7372 // [stack] UNDEFINED-OR-NULL
7373 // [stack] # otherwise
7379 if (!eoe
.prepareForKey()) {
7384 if (!emitTree(&elemExpr
->key())) {
7389 if (!eoe
.emitDelete()) {
7390 // [stack] SUCCEEDED
7397 bool BytecodeEmitter::emitDebugCheckSelfHosted() {
7401 if (!emit1(JSOp::DebugCheckSelfHosted
)) {
7410 bool BytecodeEmitter::emitSelfHostedCallFunction(CallNode
* callNode
, JSOp op
) {
7411 // Special-casing of callFunction to emit bytecode that directly
7412 // invokes the callee with the correct |this| object and arguments.
7413 // callFunction(fun, thisArg, arg0, arg1) thus becomes:
7414 // - emit lookup for fun
7415 // - emit lookup for thisArg
7416 // - emit lookups for arg0, arg1
7418 // argc is set to the amount of actually emitted args and the
7419 // emitting of args below is disabled by setting emitArgs to false.
7420 NameNode
* calleeNode
= &callNode
->callee()->as
<NameNode
>();
7421 ListNode
* argsList
= callNode
->args();
7423 MOZ_ASSERT(argsList
->count() >= 2);
7425 MOZ_ASSERT(callNode
->callOp() == JSOp::Call
);
7428 calleeNode
->name() ==
7429 TaggedParserAtomIndex::WellKnown::constructContentFunction();
7430 ParseNode
* funNode
= argsList
->head();
7432 if (!emitTree(funNode
)) {
7438 MOZ_ASSERT(op
== JSOp::Call
|| op
== JSOp::CallContent
||
7439 op
== JSOp::NewContent
);
7440 if (op
== JSOp::Call
) {
7441 if (!emitDebugCheckSelfHosted()) {
7448 ParseNode
* thisOrNewTarget
= funNode
->pn_next
;
7450 // Save off the new.target value, but here emit a proper |this| for a
7451 // constructing call.
7452 if (!emit1(JSOp::IsConstructing
)) {
7453 // [stack] CALLEE IS_CONSTRUCTING
7457 // It's |this|, emit it.
7458 if (!emitTree(thisOrNewTarget
)) {
7459 // [stack] CALLEE THIS
7464 for (ParseNode
* argpn
: argsList
->contentsFrom(thisOrNewTarget
->pn_next
)) {
7465 if (!emitTree(argpn
)) {
7466 // [stack] CALLEE ... ARGS...
7472 if (!emitTree(thisOrNewTarget
)) {
7473 // [stack] CALLEE IS_CONSTRUCTING ARGS... NEW.TARGET
7478 uint32_t argc
= argsList
->count() - 2;
7479 if (!emitCall(op
, argc
)) {
7487 bool BytecodeEmitter::emitSelfHostedResumeGenerator(CallNode
* callNode
) {
7488 ListNode
* argsList
= callNode
->args();
7490 // Syntax: resumeGenerator(gen, value, 'next'|'throw'|'return')
7491 MOZ_ASSERT(argsList
->count() == 3);
7493 ParseNode
* genNode
= argsList
->head();
7494 if (!emitTree(genNode
)) {
7495 // [stack] GENERATOR
7499 ParseNode
* valNode
= genNode
->pn_next
;
7500 if (!emitTree(valNode
)) {
7501 // [stack] GENERATOR VALUE
7505 ParseNode
* kindNode
= valNode
->pn_next
;
7506 MOZ_ASSERT(kindNode
->isKind(ParseNodeKind::StringExpr
));
7507 GeneratorResumeKind kind
=
7508 ParserAtomToResumeKind(kindNode
->as
<NameNode
>().atom());
7509 MOZ_ASSERT(!kindNode
->pn_next
);
7511 if (!emitPushResumeKind(kind
)) {
7512 // [stack] GENERATOR VALUE RESUMEKIND
7516 if (!emit1(JSOp::Resume
)) {
7524 bool BytecodeEmitter::emitSelfHostedForceInterpreter() {
7525 // JSScript::hasForceInterpreterOp() relies on JSOp::ForceInterpreter being
7526 // the first bytecode op in the script.
7527 MOZ_ASSERT(bytecodeSection().code().empty());
7529 if (!emit1(JSOp::ForceInterpreter
)) {
7532 if (!emit1(JSOp::Undefined
)) {
7539 bool BytecodeEmitter::emitSelfHostedAllowContentIter(CallNode
* callNode
) {
7540 ListNode
* argsList
= callNode
->args();
7542 MOZ_ASSERT(argsList
->count() == 1);
7544 // We're just here as a sentinel. Pass the value through directly.
7545 return emitTree(argsList
->head());
7548 bool BytecodeEmitter::emitSelfHostedAllowContentIterWith(CallNode
* callNode
) {
7549 ListNode
* argsList
= callNode
->args();
7551 MOZ_ASSERT(argsList
->count() == 2 || argsList
->count() == 3);
7553 // We're just here as a sentinel. Pass the value through directly.
7554 return emitTree(argsList
->head());
7557 bool BytecodeEmitter::emitSelfHostedAllowContentIterWithNext(
7558 CallNode
* callNode
) {
7559 ListNode
* argsList
= callNode
->args();
7561 MOZ_ASSERT(argsList
->count() == 2);
7563 // We're just here as a sentinel. Pass the value through directly.
7564 return emitTree(argsList
->head());
7567 bool BytecodeEmitter::emitSelfHostedDefineDataProperty(CallNode
* callNode
) {
7568 ListNode
* argsList
= callNode
->args();
7570 // Only optimize when 3 arguments are passed.
7571 MOZ_ASSERT(argsList
->count() == 3);
7573 ParseNode
* objNode
= argsList
->head();
7574 if (!emitTree(objNode
)) {
7578 ParseNode
* idNode
= objNode
->pn_next
;
7579 if (!emitTree(idNode
)) {
7583 ParseNode
* valNode
= idNode
->pn_next
;
7584 if (!emitTree(valNode
)) {
7588 // This will leave the object on the stack instead of pushing |undefined|,
7589 // but that's fine because the self-hosted code doesn't use the return
7591 return emit1(JSOp::InitElem
);
7594 bool BytecodeEmitter::emitSelfHostedHasOwn(CallNode
* callNode
) {
7595 ListNode
* argsList
= callNode
->args();
7597 MOZ_ASSERT(argsList
->count() == 2);
7599 ParseNode
* idNode
= argsList
->head();
7600 if (!emitTree(idNode
)) {
7604 ParseNode
* objNode
= idNode
->pn_next
;
7605 if (!emitTree(objNode
)) {
7609 return emit1(JSOp::HasOwn
);
7612 bool BytecodeEmitter::emitSelfHostedGetPropertySuper(CallNode
* callNode
) {
7613 ListNode
* argsList
= callNode
->args();
7615 MOZ_ASSERT(argsList
->count() == 3);
7617 ParseNode
* objNode
= argsList
->head();
7618 ParseNode
* idNode
= objNode
->pn_next
;
7619 ParseNode
* receiverNode
= idNode
->pn_next
;
7621 if (!emitTree(receiverNode
)) {
7625 if (!emitTree(idNode
)) {
7629 if (!emitTree(objNode
)) {
7633 return emitElemOpBase(JSOp::GetElemSuper
);
7636 bool BytecodeEmitter::emitSelfHostedToNumeric(CallNode
* callNode
) {
7637 ListNode
* argsList
= callNode
->args();
7639 MOZ_ASSERT(argsList
->count() == 1);
7641 ParseNode
* argNode
= argsList
->head();
7643 if (!emitTree(argNode
)) {
7647 return emit1(JSOp::ToNumeric
);
7650 bool BytecodeEmitter::emitSelfHostedToString(CallNode
* callNode
) {
7651 ListNode
* argsList
= callNode
->args();
7653 MOZ_ASSERT(argsList
->count() == 1);
7655 ParseNode
* argNode
= argsList
->head();
7657 if (!emitTree(argNode
)) {
7661 return emit1(JSOp::ToString
);
7664 bool BytecodeEmitter::emitSelfHostedIsNullOrUndefined(CallNode
* callNode
) {
7665 ListNode
* argsList
= callNode
->args();
7667 MOZ_ASSERT(argsList
->count() == 1);
7669 ParseNode
* argNode
= argsList
->head();
7671 if (!emitTree(argNode
)) {
7675 if (!emit1(JSOp::IsNullOrUndefined
)) {
7676 // [stack] ARG IS_NULL_OR_UNDEF
7679 if (!emit1(JSOp::Swap
)) {
7680 // [stack] IS_NULL_OR_UNDEF ARG
7683 if (!emit1(JSOp::Pop
)) {
7684 // [stack] IS_NULL_OR_UNDEF
7690 bool BytecodeEmitter::emitSelfHostedIteratorClose(CallNode
* callNode
) {
7691 ListNode
* argsList
= callNode
->args();
7692 MOZ_ASSERT(argsList
->count() == 1);
7694 ParseNode
* argNode
= argsList
->head();
7695 if (!emitTree(argNode
)) {
7700 if (!emit2(JSOp::CloseIter
, uint8_t(CompletionKind::Normal
))) {
7705 // This is still a call node, so we must generate a stack value.
7706 if (!emit1(JSOp::Undefined
)) {
7714 bool BytecodeEmitter::emitSelfHostedGetBuiltinConstructorOrPrototype(
7715 CallNode
* callNode
, bool isConstructor
) {
7716 ListNode
* argsList
= callNode
->args();
7718 MOZ_ASSERT(argsList
->count() == 1);
7720 ParseNode
* argNode
= argsList
->head();
7722 if (!argNode
->isKind(ParseNodeKind::StringExpr
)) {
7723 reportError(callNode
, JSMSG_UNEXPECTED_TYPE
, "built-in name",
7724 "not a string constant");
7728 auto name
= argNode
->as
<NameNode
>().atom();
7730 BuiltinObjectKind kind
;
7731 if (isConstructor
) {
7732 kind
= BuiltinConstructorForName(name
);
7734 kind
= BuiltinPrototypeForName(name
);
7737 if (kind
== BuiltinObjectKind::None
) {
7738 reportError(callNode
, JSMSG_UNEXPECTED_TYPE
, "built-in name",
7739 "not a valid built-in");
7743 return emitBuiltinObject(kind
);
7746 bool BytecodeEmitter::emitSelfHostedGetBuiltinConstructor(CallNode
* callNode
) {
7747 return emitSelfHostedGetBuiltinConstructorOrPrototype(
7748 callNode
, /* isConstructor = */ true);
7751 bool BytecodeEmitter::emitSelfHostedGetBuiltinPrototype(CallNode
* callNode
) {
7752 return emitSelfHostedGetBuiltinConstructorOrPrototype(
7753 callNode
, /* isConstructor = */ false);
7756 JS::SymbolCode
ParserAtomToSymbolCode(TaggedParserAtomIndex atom
) {
7757 // NOTE: This is a linear search, but the set of entries is quite small and
7758 // this is only used for initial self-hosted parse.
7759 #define MATCH_WELL_KNOWN_SYMBOL(NAME) \
7760 if (atom == TaggedParserAtomIndex::WellKnown::NAME()) { \
7761 return JS::SymbolCode::NAME; \
7763 JS_FOR_EACH_WELL_KNOWN_SYMBOL(MATCH_WELL_KNOWN_SYMBOL
)
7764 #undef MATCH_WELL_KNOWN_SYMBOL
7766 return JS::SymbolCode::Limit
;
7769 bool BytecodeEmitter::emitSelfHostedGetBuiltinSymbol(CallNode
* callNode
) {
7770 ListNode
* argsList
= callNode
->args();
7772 MOZ_ASSERT(argsList
->count() == 1);
7774 ParseNode
* argNode
= argsList
->head();
7776 if (!argNode
->isKind(ParseNodeKind::StringExpr
)) {
7777 reportError(callNode
, JSMSG_UNEXPECTED_TYPE
, "built-in name",
7778 "not a string constant");
7782 auto name
= argNode
->as
<NameNode
>().atom();
7784 JS::SymbolCode code
= ParserAtomToSymbolCode(name
);
7785 if (code
== JS::SymbolCode::Limit
) {
7786 reportError(callNode
, JSMSG_UNEXPECTED_TYPE
, "built-in name",
7787 "not a valid built-in");
7791 return emit2(JSOp::Symbol
, uint8_t(code
));
7794 bool BytecodeEmitter::emitSelfHostedArgumentsLength(CallNode
* callNode
) {
7795 MOZ_ASSERT(!sc
->asFunctionBox()->needsArgsObj());
7796 sc
->asFunctionBox()->setUsesArgumentsIntrinsics();
7798 MOZ_ASSERT(callNode
->args()->count() == 0);
7800 return emit1(JSOp::ArgumentsLength
);
7803 bool BytecodeEmitter::emitSelfHostedGetArgument(CallNode
* callNode
) {
7804 MOZ_ASSERT(!sc
->asFunctionBox()->needsArgsObj());
7805 sc
->asFunctionBox()->setUsesArgumentsIntrinsics();
7807 ListNode
* argsList
= callNode
->args();
7808 MOZ_ASSERT(argsList
->count() == 1);
7810 ParseNode
* argNode
= argsList
->head();
7811 if (!emitTree(argNode
)) {
7815 return emit1(JSOp::GetActualArg
);
7819 void BytecodeEmitter::assertSelfHostedExpectedTopLevel(ParseNode
* node
) {
7820 // The function argument is expected to be a simple binding/function name.
7821 // Eg. `function foo() { }; SpecialIntrinsic(foo)`
7822 MOZ_ASSERT(node
->isKind(ParseNodeKind::Name
),
7823 "argument must be a function name");
7824 TaggedParserAtomIndex targetName
= node
->as
<NameNode
>().name();
7826 // The special intrinsics must follow the target functions definition. A
7827 // simple assert is fine here since any hoisted function will cause a non-null
7828 // value to be set here.
7829 MOZ_ASSERT(prevSelfHostedTopLevelFunction
);
7831 // The target function must match the most recently defined top-level
7832 // self-hosted function.
7833 MOZ_ASSERT(prevSelfHostedTopLevelFunction
->explicitName() == targetName
,
7834 "selfhost decorator must immediately follow target function");
7838 bool BytecodeEmitter::emitSelfHostedSetIsInlinableLargeFunction(
7839 CallNode
* callNode
) {
7841 ListNode
* argsList
= callNode
->args();
7843 MOZ_ASSERT(argsList
->count() == 1);
7845 assertSelfHostedExpectedTopLevel(argsList
->head());
7848 MOZ_ASSERT(prevSelfHostedTopLevelFunction
->isInitialCompilation
);
7849 prevSelfHostedTopLevelFunction
->setIsInlinableLargeFunction();
7851 // This is still a call node, so we must generate a stack value.
7852 return emit1(JSOp::Undefined
);
7855 bool BytecodeEmitter::emitSelfHostedSetCanonicalName(CallNode
* callNode
) {
7856 ListNode
* argsList
= callNode
->args();
7858 MOZ_ASSERT(argsList
->count() == 2);
7861 assertSelfHostedExpectedTopLevel(argsList
->head());
7864 ParseNode
* nameNode
= argsList
->last();
7865 MOZ_ASSERT(nameNode
->isKind(ParseNodeKind::StringExpr
));
7866 TaggedParserAtomIndex specName
= nameNode
->as
<NameNode
>().atom();
7867 // Canonical name must be atomized.
7868 compilationState
.parserAtoms
.markUsedByStencil(specName
,
7869 ParserAtom::Atomize::Yes
);
7871 // Store the canonical name for instantiation.
7872 prevSelfHostedTopLevelFunction
->functionStencil().setSelfHostedCanonicalName(
7875 return emit1(JSOp::Undefined
);
7879 void BytecodeEmitter::assertSelfHostedUnsafeGetReservedSlot(
7880 ListNode
* argsList
) {
7881 MOZ_ASSERT(argsList
->count() == 2);
7883 ParseNode
* objNode
= argsList
->head();
7884 ParseNode
* slotNode
= objNode
->pn_next
;
7886 // Ensure that the slot argument is fixed, this is required by the JITs.
7887 MOZ_ASSERT(slotNode
->isKind(ParseNodeKind::NumberExpr
),
7888 "slot argument must be a constant");
7891 void BytecodeEmitter::assertSelfHostedUnsafeSetReservedSlot(
7892 ListNode
* argsList
) {
7893 MOZ_ASSERT(argsList
->count() == 3);
7895 ParseNode
* objNode
= argsList
->head();
7896 ParseNode
* slotNode
= objNode
->pn_next
;
7898 // Ensure that the slot argument is fixed, this is required by the JITs.
7899 MOZ_ASSERT(slotNode
->isKind(ParseNodeKind::NumberExpr
),
7900 "slot argument must be a constant");
7904 /* A version of emitCalleeAndThis for the optional cases:
7911 * See emitCallOrNew and emitOptionalCall for more context.
7913 bool BytecodeEmitter::emitOptionalCalleeAndThis(ParseNode
* callee
,
7915 CallOrNewEmitter
& cone
,
7916 OptionalEmitter
& oe
) {
7917 AutoCheckRecursionLimit
recursion(fc
);
7918 if (!recursion
.check(fc
)) {
7922 switch (ParseNodeKind kind
= callee
->getKind()) {
7923 case ParseNodeKind::Name
: {
7924 auto name
= callee
->as
<NameNode
>().name();
7925 if (!cone
.emitNameCallee(name
)) {
7926 // [stack] CALLEE THIS
7932 case ParseNodeKind::OptionalDotExpr
: {
7933 MOZ_ASSERT(emitterMode
!= BytecodeEmitter::SelfHosting
);
7934 OptionalPropertyAccess
* prop
= &callee
->as
<OptionalPropertyAccess
>();
7935 bool isSuper
= false;
7937 PropOpEmitter
& poe
= cone
.prepareForPropCallee(isSuper
);
7938 if (!emitOptionalDotExpression(prop
, poe
, isSuper
, oe
)) {
7939 // [stack] CALLEE THIS
7944 case ParseNodeKind::DotExpr
: {
7945 MOZ_ASSERT(emitterMode
!= BytecodeEmitter::SelfHosting
);
7946 PropertyAccess
* prop
= &callee
->as
<PropertyAccess
>();
7947 bool isSuper
= prop
->isSuper();
7949 PropOpEmitter
& poe
= cone
.prepareForPropCallee(isSuper
);
7950 if (!emitOptionalDotExpression(prop
, poe
, isSuper
, oe
)) {
7951 // [stack] CALLEE THIS
7957 case ParseNodeKind::OptionalElemExpr
: {
7958 OptionalPropertyByValue
* elem
= &callee
->as
<OptionalPropertyByValue
>();
7959 bool isSuper
= false;
7960 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
7961 ElemOpEmitter
& eoe
= cone
.prepareForElemCallee(isSuper
);
7962 if (!emitOptionalElemExpression(elem
, eoe
, isSuper
, oe
)) {
7963 // [stack] CALLEE THIS
7968 case ParseNodeKind::ElemExpr
: {
7969 PropertyByValue
* elem
= &callee
->as
<PropertyByValue
>();
7970 bool isSuper
= elem
->isSuper();
7971 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
7972 ElemOpEmitter
& eoe
= cone
.prepareForElemCallee(isSuper
);
7973 if (!emitOptionalElemExpression(elem
, eoe
, isSuper
, oe
)) {
7974 // [stack] CALLEE THIS
7980 case ParseNodeKind::PrivateMemberExpr
:
7981 case ParseNodeKind::OptionalPrivateMemberExpr
: {
7982 PrivateMemberAccessBase
* privateExpr
=
7983 &callee
->as
<PrivateMemberAccessBase
>();
7984 PrivateOpEmitter
& xoe
=
7985 cone
.prepareForPrivateCallee(privateExpr
->privateName().name());
7986 if (!emitOptionalPrivateExpression(privateExpr
, xoe
, oe
)) {
7987 // [stack] CALLEE THIS
7993 case ParseNodeKind::Function
:
7994 if (!cone
.prepareForFunctionCallee()) {
7997 if (!emitOptionalTree(callee
, oe
)) {
8003 case ParseNodeKind::OptionalChain
: {
8004 return emitCalleeAndThisForOptionalChain(&callee
->as
<UnaryNode
>(), call
,
8009 MOZ_RELEASE_ASSERT(kind
!= ParseNodeKind::SuperBase
);
8011 if (!cone
.prepareForOtherCallee()) {
8014 if (!emitOptionalTree(callee
, oe
)) {
8021 if (!cone
.emitThis()) {
8022 // [stack] CALLEE THIS
8029 bool BytecodeEmitter::emitCalleeAndThis(ParseNode
* callee
, CallNode
* maybeCall
,
8030 CallOrNewEmitter
& cone
) {
8031 MOZ_ASSERT_IF(maybeCall
, maybeCall
->callee() == callee
);
8033 switch (callee
->getKind()) {
8034 case ParseNodeKind::Name
: {
8035 auto name
= callee
->as
<NameNode
>().name();
8036 if (!cone
.emitNameCallee(name
)) {
8037 // [stack] CALLEE THIS?
8042 case ParseNodeKind::DotExpr
: {
8043 MOZ_ASSERT(emitterMode
!= BytecodeEmitter::SelfHosting
);
8044 PropertyAccess
* prop
= &callee
->as
<PropertyAccess
>();
8045 bool isSuper
= prop
->isSuper();
8047 PropOpEmitter
& poe
= cone
.prepareForPropCallee(isSuper
);
8048 if (!poe
.prepareForObj()) {
8052 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
8053 if (!emitGetThisForSuperBase(base
)) {
8058 if (!emitPropLHS(prop
)) {
8063 if (!poe
.emitGet(prop
->key().atom())) {
8064 // [stack] CALLEE THIS?
8070 case ParseNodeKind::ElemExpr
: {
8071 MOZ_ASSERT(emitterMode
!= BytecodeEmitter::SelfHosting
);
8072 PropertyByValue
* elem
= &callee
->as
<PropertyByValue
>();
8073 bool isSuper
= elem
->isSuper();
8074 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
8075 ElemOpEmitter
& eoe
= cone
.prepareForElemCallee(isSuper
);
8076 if (!emitElemObjAndKey(elem
, isSuper
, eoe
)) {
8077 // [stack] # if Super
8078 // [stack] THIS? THIS KEY
8079 // [stack] # otherwise
8080 // [stack] OBJ? OBJ KEY
8083 if (!eoe
.emitGet()) {
8084 // [stack] CALLEE THIS?
8090 case ParseNodeKind::PrivateMemberExpr
: {
8091 MOZ_ASSERT(emitterMode
!= BytecodeEmitter::SelfHosting
);
8092 PrivateMemberAccessBase
* privateExpr
=
8093 &callee
->as
<PrivateMemberAccessBase
>();
8094 PrivateOpEmitter
& xoe
=
8095 cone
.prepareForPrivateCallee(privateExpr
->privateName().name());
8096 if (!emitTree(&privateExpr
->expression())) {
8100 if (!xoe
.emitReference()) {
8104 if (!xoe
.emitGetForCallOrNew()) {
8105 // [stack] CALLEE THIS
8111 case ParseNodeKind::Function
:
8112 if (!cone
.prepareForFunctionCallee()) {
8115 if (!emitTree(callee
)) {
8120 case ParseNodeKind::SuperBase
:
8121 MOZ_ASSERT(maybeCall
);
8122 MOZ_ASSERT(maybeCall
->isKind(ParseNodeKind::SuperCallExpr
));
8123 MOZ_ASSERT(callee
->isKind(ParseNodeKind::SuperBase
));
8124 if (!cone
.emitSuperCallee()) {
8125 // [stack] CALLEE IsConstructing
8129 case ParseNodeKind::OptionalChain
: {
8130 MOZ_ASSERT(maybeCall
);
8131 return emitCalleeAndThisForOptionalChain(&callee
->as
<UnaryNode
>(),
8135 if (!cone
.prepareForOtherCallee()) {
8138 if (!emitTree(callee
)) {
8144 if (!cone
.emitThis()) {
8145 // [stack] CALLEE THIS
8152 ParseNode
* BytecodeEmitter::getCoordNode(ParseNode
* callNode
,
8153 ParseNode
* calleeNode
, JSOp op
,
8154 ListNode
* argsList
) {
8155 ParseNode
* coordNode
= callNode
;
8156 if (op
== JSOp::Call
|| op
== JSOp::SpreadCall
) {
8157 // Default to using the location of the `(` itself.
8158 // obj[expr]() // expression
8159 // ^ // column coord
8160 coordNode
= argsList
;
8162 switch (calleeNode
->getKind()) {
8163 case ParseNodeKind::DotExpr
:
8164 // Use the position of a property access identifier.
8166 // obj().aprop() // expression
8167 // ^ // column coord
8169 // Note: Because of the constant folding logic in FoldElement,
8170 // this case also applies for constant string properties.
8172 // obj()['aprop']() // expression
8173 // ^ // column coord
8174 coordNode
= &calleeNode
->as
<PropertyAccess
>().key();
8176 case ParseNodeKind::Name
: {
8177 // Use the start of callee name unless it is at a separator
8180 // 2 + obj() // expression
8181 // ^ // column coord
8183 if (argsList
->empty() ||
8184 !bytecodeSection().atSeparator(calleeNode
->pn_pos
.begin
)) {
8185 // Use the start of callee names.
8186 coordNode
= calleeNode
;
8198 bool BytecodeEmitter::emitArguments(ListNode
* argsList
, bool isCall
,
8199 bool isSpread
, CallOrNewEmitter
& cone
) {
8200 uint32_t argc
= argsList
->count();
8201 if (argc
>= ARGC_LIMIT
) {
8202 reportError(argsList
,
8203 isCall
? JSMSG_TOO_MANY_FUN_ARGS
: JSMSG_TOO_MANY_CON_ARGS
);
8207 if (!cone
.prepareForNonSpreadArguments()) {
8208 // [stack] CALLEE THIS
8211 for (ParseNode
* arg
: argsList
->contents()) {
8212 if (!updateSourceCoordNotesIfNonLiteral(arg
)) {
8215 if (!emitTree(arg
)) {
8216 // [stack] CALLEE THIS ARG*
8220 } else if (cone
.wantSpreadOperand()) {
8221 auto* spreadNode
= &argsList
->head()->as
<UnaryNode
>();
8222 if (!updateSourceCoordNotesIfNonLiteral(spreadNode
->kid())) {
8225 if (!emitTree(spreadNode
->kid())) {
8226 // [stack] CALLEE THIS ARG0
8230 if (!cone
.emitSpreadArgumentsTest()) {
8231 // [stack] CALLEE THIS ARG0
8235 if (cone
.wantSpreadIteration()) {
8236 if (!emitSpreadIntoArray(spreadNode
)) {
8237 // [stack] CALLEE THIS ARR
8242 if (!cone
.emitSpreadArgumentsTestEnd()) {
8243 // [stack] CALLEE THIS ARR
8247 if (!cone
.prepareForSpreadArguments()) {
8248 // [stack] CALLEE THIS
8251 if (!emitArray(argsList
)) {
8252 // [stack] CALLEE THIS ARR
8260 bool BytecodeEmitter::emitOptionalCall(CallNode
* callNode
, OptionalEmitter
& oe
,
8261 ValueUsage valueUsage
) {
8263 * A modified version of emitCallOrNew that handles optional calls.
8265 * These include the following:
8271 * See CallOrNewEmitter for more context.
8273 ParseNode
* calleeNode
= callNode
->callee();
8274 ListNode
* argsList
= callNode
->args();
8275 bool isSpread
= IsSpreadOp(callNode
->callOp());
8276 JSOp op
= callNode
->callOp();
8277 uint32_t argc
= argsList
->count();
8278 bool isOptimizableSpread
= isSpread
&& argc
== 1;
8280 CallOrNewEmitter
cone(this, op
,
8282 ? CallOrNewEmitter::ArgumentsKind::SingleSpread
8283 : CallOrNewEmitter::ArgumentsKind::Other
,
8286 ParseNode
* coordNode
= getCoordNode(callNode
, calleeNode
, op
, argsList
);
8288 if (!emitOptionalCalleeAndThis(calleeNode
, callNode
, cone
, oe
)) {
8289 // [stack] CALLEE THIS
8293 if (callNode
->isKind(ParseNodeKind::OptionalCallExpr
)) {
8294 if (!oe
.emitJumpShortCircuitForCall()) {
8295 // [stack] CALLEE THIS
8300 if (!emitArguments(argsList
, /* isCall = */ true, isSpread
, cone
)) {
8301 // [stack] CALLEE THIS ARGS...
8305 if (!cone
.emitEnd(argc
, coordNode
->pn_pos
.begin
)) {
8313 bool BytecodeEmitter::emitCallOrNew(CallNode
* callNode
, ValueUsage valueUsage
) {
8315 * Emit callable invocation or operator new (constructor call) code.
8316 * First, emit code for the left operand to evaluate the callable or
8317 * constructable object expression.
8319 * Then (or in a call case that has no explicit reference-base
8320 * object) we emit JSOp::Undefined to produce the undefined |this|
8321 * value required for calls (which non-strict mode functions
8322 * will box into the global object).
8324 bool isCall
= callNode
->isKind(ParseNodeKind::CallExpr
) ||
8325 callNode
->isKind(ParseNodeKind::TaggedTemplateExpr
);
8326 ParseNode
* calleeNode
= callNode
->callee();
8327 ListNode
* argsList
= callNode
->args();
8328 JSOp op
= callNode
->callOp();
8330 if (calleeNode
->isKind(ParseNodeKind::Name
) &&
8331 emitterMode
== BytecodeEmitter::SelfHosting
&& op
== JSOp::Call
) {
8332 // Calls to "forceInterpreter", "callFunction",
8333 // "callContentFunction", or "resumeGenerator" in self-hosted
8334 // code generate inline bytecode.
8336 // NOTE: The list of special instruction names has to be kept in sync with
8337 // "js/src/builtin/.eslintrc.js".
8338 auto calleeName
= calleeNode
->as
<NameNode
>().name();
8339 if (calleeName
== TaggedParserAtomIndex::WellKnown::callFunction()) {
8340 return emitSelfHostedCallFunction(callNode
, JSOp::Call
);
8342 if (calleeName
== TaggedParserAtomIndex::WellKnown::callContentFunction()) {
8343 return emitSelfHostedCallFunction(callNode
, JSOp::CallContent
);
8346 TaggedParserAtomIndex::WellKnown::constructContentFunction()) {
8347 return emitSelfHostedCallFunction(callNode
, JSOp::NewContent
);
8349 if (calleeName
== TaggedParserAtomIndex::WellKnown::resumeGenerator()) {
8350 return emitSelfHostedResumeGenerator(callNode
);
8352 if (calleeName
== TaggedParserAtomIndex::WellKnown::forceInterpreter()) {
8353 return emitSelfHostedForceInterpreter();
8355 if (calleeName
== TaggedParserAtomIndex::WellKnown::allowContentIter()) {
8356 return emitSelfHostedAllowContentIter(callNode
);
8359 TaggedParserAtomIndex::WellKnown::allowContentIterWith()) {
8360 return emitSelfHostedAllowContentIterWith(callNode
);
8363 TaggedParserAtomIndex::WellKnown::allowContentIterWithNext()) {
8364 return emitSelfHostedAllowContentIterWithNext(callNode
);
8366 if (calleeName
== TaggedParserAtomIndex::WellKnown::DefineDataProperty() &&
8367 argsList
->count() == 3) {
8368 return emitSelfHostedDefineDataProperty(callNode
);
8370 if (calleeName
== TaggedParserAtomIndex::WellKnown::hasOwn()) {
8371 return emitSelfHostedHasOwn(callNode
);
8373 if (calleeName
== TaggedParserAtomIndex::WellKnown::getPropertySuper()) {
8374 return emitSelfHostedGetPropertySuper(callNode
);
8376 if (calleeName
== TaggedParserAtomIndex::WellKnown::ToNumeric()) {
8377 return emitSelfHostedToNumeric(callNode
);
8379 if (calleeName
== TaggedParserAtomIndex::WellKnown::ToString()) {
8380 return emitSelfHostedToString(callNode
);
8383 TaggedParserAtomIndex::WellKnown::GetBuiltinConstructor()) {
8384 return emitSelfHostedGetBuiltinConstructor(callNode
);
8386 if (calleeName
== TaggedParserAtomIndex::WellKnown::GetBuiltinPrototype()) {
8387 return emitSelfHostedGetBuiltinPrototype(callNode
);
8389 if (calleeName
== TaggedParserAtomIndex::WellKnown::GetBuiltinSymbol()) {
8390 return emitSelfHostedGetBuiltinSymbol(callNode
);
8392 if (calleeName
== TaggedParserAtomIndex::WellKnown::ArgumentsLength()) {
8393 return emitSelfHostedArgumentsLength(callNode
);
8395 if (calleeName
== TaggedParserAtomIndex::WellKnown::GetArgument()) {
8396 return emitSelfHostedGetArgument(callNode
);
8399 TaggedParserAtomIndex::WellKnown::SetIsInlinableLargeFunction()) {
8400 return emitSelfHostedSetIsInlinableLargeFunction(callNode
);
8402 if (calleeName
== TaggedParserAtomIndex::WellKnown::SetCanonicalName()) {
8403 return emitSelfHostedSetCanonicalName(callNode
);
8405 if (calleeName
== TaggedParserAtomIndex::WellKnown::IsNullOrUndefined()) {
8406 return emitSelfHostedIsNullOrUndefined(callNode
);
8408 if (calleeName
== TaggedParserAtomIndex::WellKnown::IteratorClose()) {
8409 return emitSelfHostedIteratorClose(callNode
);
8413 TaggedParserAtomIndex::WellKnown::UnsafeGetReservedSlot() ||
8414 calleeName
== TaggedParserAtomIndex::WellKnown::
8415 UnsafeGetObjectFromReservedSlot() ||
8416 calleeName
== TaggedParserAtomIndex::WellKnown::
8417 UnsafeGetInt32FromReservedSlot() ||
8418 calleeName
== TaggedParserAtomIndex::WellKnown::
8419 UnsafeGetStringFromReservedSlot()) {
8420 // Make sure that this call is correct, but don't emit any special code.
8421 assertSelfHostedUnsafeGetReservedSlot(argsList
);
8424 TaggedParserAtomIndex::WellKnown::UnsafeSetReservedSlot()) {
8425 // Make sure that this call is correct, but don't emit any special code.
8426 assertSelfHostedUnsafeSetReservedSlot(argsList
);
8432 uint32_t argc
= argsList
->count();
8433 bool isSpread
= IsSpreadOp(op
);
8434 bool isOptimizableSpread
= isSpread
&& argc
== 1;
8435 bool isDefaultDerivedClassConstructor
=
8436 sc
->isFunctionBox() && sc
->asFunctionBox()->isDerivedClassConstructor() &&
8437 sc
->asFunctionBox()->isSyntheticFunction();
8438 MOZ_ASSERT_IF(isDefaultDerivedClassConstructor
, isOptimizableSpread
);
8439 CallOrNewEmitter
cone(
8442 ? isDefaultDerivedClassConstructor
8443 ? CallOrNewEmitter::ArgumentsKind::PassthroughRest
8444 : CallOrNewEmitter::ArgumentsKind::SingleSpread
8445 : CallOrNewEmitter::ArgumentsKind::Other
,
8448 if (!emitCalleeAndThis(calleeNode
, callNode
, cone
)) {
8449 // [stack] CALLEE THIS
8452 if (!emitArguments(argsList
, isCall
, isSpread
, cone
)) {
8453 // [stack] CALLEE THIS ARGS...
8457 // Push new.target for construct calls.
8458 if (IsConstructOp(op
)) {
8459 if (op
== JSOp::SuperCall
|| op
== JSOp::SpreadSuperCall
) {
8460 if (!emitNewTarget(callNode
)) {
8461 // [stack] CALLEE THIS ARGS.. NEW.TARGET
8465 // Repush the callee as new.target
8466 uint32_t effectiveArgc
= isSpread
? 1 : argc
;
8467 if (!emitDupAt(effectiveArgc
+ 1)) {
8468 // [stack] CALLEE THIS ARGS.. CALLEE
8474 ParseNode
* coordNode
= getCoordNode(callNode
, calleeNode
, op
, argsList
);
8476 if (!cone
.emitEnd(argc
, coordNode
->pn_pos
.begin
)) {
8484 // This list must be kept in the same order in several places:
8485 // - The binary operators in ParseNode.h ,
8486 // - the binary operators in TokenKind.h
8487 // - the precedence list in Parser.cpp
8488 static const JSOp ParseNodeKindToJSOp
[] = {
8489 // Some binary ops require special code generation (PrivateIn);
8490 // these should not use BinaryOpParseNodeKindToJSOp. This table fills those
8491 // slots with Nops to make the rest of the table lookup work.
8492 JSOp::Coalesce
, JSOp::Or
, JSOp::And
, JSOp::BitOr
, JSOp::BitXor
,
8493 JSOp::BitAnd
, JSOp::StrictEq
, JSOp::Eq
, JSOp::StrictNe
, JSOp::Ne
,
8494 JSOp::Lt
, JSOp::Le
, JSOp::Gt
, JSOp::Ge
, JSOp::Instanceof
,
8495 JSOp::In
, JSOp::Nop
, JSOp::Lsh
, JSOp::Rsh
, JSOp::Ursh
,
8496 JSOp::Add
, JSOp::Sub
, JSOp::Mul
, JSOp::Div
, JSOp::Mod
,
8499 static inline JSOp
BinaryOpParseNodeKindToJSOp(ParseNodeKind pnk
) {
8500 MOZ_ASSERT(pnk
>= ParseNodeKind::BinOpFirst
);
8501 MOZ_ASSERT(pnk
<= ParseNodeKind::BinOpLast
);
8502 int parseNodeFirst
= size_t(ParseNodeKind::BinOpFirst
);
8504 int jsopArraySize
= std::size(ParseNodeKindToJSOp
);
8505 int parseNodeKindListSize
=
8506 size_t(ParseNodeKind::BinOpLast
) - parseNodeFirst
+ 1;
8507 MOZ_ASSERT(jsopArraySize
== parseNodeKindListSize
);
8508 // Ensure we don't use this to find an op for a parse node
8509 // requiring special emission rules.
8510 MOZ_ASSERT(ParseNodeKindToJSOp
[size_t(pnk
) - parseNodeFirst
] != JSOp::Nop
);
8512 return ParseNodeKindToJSOp
[size_t(pnk
) - parseNodeFirst
];
8515 bool BytecodeEmitter::emitRightAssociative(ListNode
* node
) {
8516 // ** is the only right-associative operator.
8517 MOZ_ASSERT(node
->isKind(ParseNodeKind::PowExpr
));
8519 // Right-associative operator chain.
8520 for (ParseNode
* subexpr
: node
->contents()) {
8521 if (!updateSourceCoordNotesIfNonLiteral(subexpr
)) {
8524 if (!emitTree(subexpr
)) {
8528 for (uint32_t i
= 0; i
< node
->count() - 1; i
++) {
8529 if (!emit1(JSOp::Pow
)) {
8536 bool BytecodeEmitter::emitLeftAssociative(ListNode
* node
) {
8537 // Left-associative operator chain.
8538 if (!emitTree(node
->head())) {
8541 JSOp op
= BinaryOpParseNodeKindToJSOp(node
->getKind());
8542 ParseNode
* nextExpr
= node
->head()->pn_next
;
8544 if (!updateSourceCoordNotesIfNonLiteral(nextExpr
)) {
8547 if (!emitTree(nextExpr
)) {
8553 } while ((nextExpr
= nextExpr
->pn_next
));
8557 bool BytecodeEmitter::emitPrivateInExpr(ListNode
* node
) {
8558 MOZ_ASSERT(node
->head()->isKind(ParseNodeKind::PrivateName
));
8560 NameNode
& privateNameNode
= node
->head()->as
<NameNode
>();
8561 TaggedParserAtomIndex privateName
= privateNameNode
.name();
8563 PrivateOpEmitter
xoe(this, PrivateOpEmitter::Kind::ErgonomicBrandCheck
,
8566 ParseNode
* valueNode
= node
->head()->pn_next
;
8567 MOZ_ASSERT(valueNode
->pn_next
== nullptr);
8569 if (!emitTree(valueNode
)) {
8574 if (!xoe
.emitReference()) {
8575 // [stack] OBJ BRAND if private method
8576 // [stack] OBJ NAME if private field or accessor.
8580 if (!xoe
.emitBrandCheck()) {
8581 // [stack] OBJ BRAND BOOL if private method
8582 // [stack] OBJ NAME BOOL if private field or accessor.
8586 if (!emitUnpickN(2)) {
8587 // [stack] BOOL OBJ BRAND if private method
8588 // [stack] BOOL OBJ NAME if private field or accessor.
8601 * Special `emitTree` for Optional Chaining case.
8602 * Examples of this are `emitOptionalChain`, `emitDeleteOptionalChain` and
8603 * `emitCalleeAndThisForOptionalChain`.
8605 bool BytecodeEmitter::emitOptionalTree(
8606 ParseNode
* pn
, OptionalEmitter
& oe
,
8607 ValueUsage valueUsage
/* = ValueUsage::WantValue */) {
8608 AutoCheckRecursionLimit
recursion(fc
);
8609 if (!recursion
.check(fc
)) {
8612 ParseNodeKind kind
= pn
->getKind();
8614 case ParseNodeKind::OptionalDotExpr
: {
8615 OptionalPropertyAccess
* prop
= &pn
->as
<OptionalPropertyAccess
>();
8616 bool isSuper
= false;
8617 PropOpEmitter
poe(this, PropOpEmitter::Kind::Get
,
8618 PropOpEmitter::ObjKind::Other
);
8619 if (!emitOptionalDotExpression(prop
, poe
, isSuper
, oe
)) {
8624 case ParseNodeKind::DotExpr
: {
8625 PropertyAccess
* prop
= &pn
->as
<PropertyAccess
>();
8626 bool isSuper
= prop
->isSuper();
8627 PropOpEmitter
poe(this, PropOpEmitter::Kind::Get
,
8628 isSuper
? PropOpEmitter::ObjKind::Super
8629 : PropOpEmitter::ObjKind::Other
);
8630 if (!emitOptionalDotExpression(prop
, poe
, isSuper
, oe
)) {
8636 case ParseNodeKind::OptionalElemExpr
: {
8637 OptionalPropertyByValue
* elem
= &pn
->as
<OptionalPropertyByValue
>();
8638 bool isSuper
= false;
8639 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
8640 ElemOpEmitter
eoe(this, ElemOpEmitter::Kind::Get
,
8641 ElemOpEmitter::ObjKind::Other
);
8643 if (!emitOptionalElemExpression(elem
, eoe
, isSuper
, oe
)) {
8648 case ParseNodeKind::ElemExpr
: {
8649 PropertyByValue
* elem
= &pn
->as
<PropertyByValue
>();
8650 bool isSuper
= elem
->isSuper();
8651 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
8652 ElemOpEmitter
eoe(this, ElemOpEmitter::Kind::Get
,
8653 isSuper
? ElemOpEmitter::ObjKind::Super
8654 : ElemOpEmitter::ObjKind::Other
);
8656 if (!emitOptionalElemExpression(elem
, eoe
, isSuper
, oe
)) {
8661 case ParseNodeKind::PrivateMemberExpr
:
8662 case ParseNodeKind::OptionalPrivateMemberExpr
: {
8663 PrivateMemberAccessBase
* privateExpr
= &pn
->as
<PrivateMemberAccessBase
>();
8664 PrivateOpEmitter
xoe(this, PrivateOpEmitter::Kind::Get
,
8665 privateExpr
->privateName().name());
8666 if (!emitOptionalPrivateExpression(privateExpr
, xoe
, oe
)) {
8671 case ParseNodeKind::CallExpr
:
8672 case ParseNodeKind::OptionalCallExpr
:
8673 if (!emitOptionalCall(&pn
->as
<CallNode
>(), oe
, valueUsage
)) {
8677 // List of accepted ParseNodeKinds that might appear only at the beginning
8678 // of an Optional Chain.
8679 // For example, a taggedTemplateExpr node might occur if we have
8680 // `test`?.b, with `test` as the taggedTemplateExpr ParseNode.
8683 // https://tc39.es/ecma262/#sec-primary-expression
8684 bool isPrimaryExpression
=
8685 kind
== ParseNodeKind::ThisExpr
|| kind
== ParseNodeKind::Name
||
8686 kind
== ParseNodeKind::PrivateName
||
8687 kind
== ParseNodeKind::NullExpr
|| kind
== ParseNodeKind::TrueExpr
||
8688 kind
== ParseNodeKind::FalseExpr
||
8689 kind
== ParseNodeKind::NumberExpr
||
8690 kind
== ParseNodeKind::BigIntExpr
||
8691 kind
== ParseNodeKind::StringExpr
||
8692 kind
== ParseNodeKind::ArrayExpr
||
8693 kind
== ParseNodeKind::ObjectExpr
||
8694 kind
== ParseNodeKind::Function
|| kind
== ParseNodeKind::ClassDecl
||
8695 kind
== ParseNodeKind::RegExpExpr
||
8696 kind
== ParseNodeKind::TemplateStringExpr
||
8697 kind
== ParseNodeKind::TemplateStringListExpr
||
8698 kind
== ParseNodeKind::RawUndefinedExpr
|| pn
->isInParens();
8700 // https://tc39.es/ecma262/#sec-left-hand-side-expressions
8701 bool isMemberExpression
= isPrimaryExpression
||
8702 kind
== ParseNodeKind::TaggedTemplateExpr
||
8703 kind
== ParseNodeKind::NewExpr
||
8704 kind
== ParseNodeKind::NewTargetExpr
||
8705 kind
== ParseNodeKind::ImportMetaExpr
;
8707 bool isCallExpression
= kind
== ParseNodeKind::SetThis
||
8708 kind
== ParseNodeKind::CallImportExpr
;
8710 MOZ_ASSERT(isMemberExpression
|| isCallExpression
,
8711 "Unknown ParseNodeKind for OptionalChain");
8713 return emitTree(pn
);
8718 // Handle the case of a call made on a OptionalChainParseNode.
8719 // For example `(a?.b)()` and `(a?.b)?.()`.
8720 bool BytecodeEmitter::emitCalleeAndThisForOptionalChain(
8721 UnaryNode
* optionalChain
, CallNode
* callNode
, CallOrNewEmitter
& cone
) {
8722 ParseNode
* calleeNode
= optionalChain
->kid();
8724 // Create a new OptionalEmitter, in order to emit the right bytecode
8726 OptionalEmitter
oe(this, bytecodeSection().stackDepth());
8728 if (!emitOptionalCalleeAndThis(calleeNode
, callNode
, cone
, oe
)) {
8729 // [stack] CALLEE THIS
8733 // complete the jump if necessary. This will set both the "this" value
8734 // and the "callee" value to undefined, if the callee is undefined. It
8735 // does not matter much what the this value is, the function call will
8736 // fail if it is not optional, and be set to undefined otherwise.
8737 if (!oe
.emitOptionalJumpTarget(JSOp::Undefined
,
8738 OptionalEmitter::Kind::Reference
)) {
8739 // [stack] # If shortcircuit
8740 // [stack] UNDEFINED UNDEFINED
8741 // [stack] # otherwise
8742 // [stack] CALLEE THIS
8748 bool BytecodeEmitter::emitOptionalChain(UnaryNode
* optionalChain
,
8749 ValueUsage valueUsage
) {
8750 ParseNode
* expr
= optionalChain
->kid();
8752 OptionalEmitter
oe(this, bytecodeSection().stackDepth());
8754 if (!emitOptionalTree(expr
, oe
, valueUsage
)) {
8759 if (!oe
.emitOptionalJumpTarget(JSOp::Undefined
)) {
8760 // [stack] # If shortcircuit
8761 // [stack] UNDEFINED
8762 // [stack] # otherwise
8770 bool BytecodeEmitter::emitOptionalDotExpression(PropertyAccessBase
* prop
,
8773 OptionalEmitter
& oe
) {
8774 if (!poe
.prepareForObj()) {
8780 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
8781 if (!emitGetThisForSuperBase(base
)) {
8786 if (!emitOptionalTree(&prop
->expression(), oe
)) {
8792 if (prop
->isKind(ParseNodeKind::OptionalDotExpr
)) {
8793 MOZ_ASSERT(!isSuper
);
8794 if (!oe
.emitJumpShortCircuit()) {
8795 // [stack] # if Jump
8796 // [stack] UNDEFINED-OR-NULL
8797 // [stack] # otherwise
8803 if (!poe
.emitGet(prop
->key().atom())) {
8811 bool BytecodeEmitter::emitOptionalElemExpression(PropertyByValueBase
* elem
,
8814 OptionalEmitter
& oe
) {
8815 if (!eoe
.prepareForObj()) {
8821 UnaryNode
* base
= &elem
->expression().as
<UnaryNode
>();
8822 if (!emitGetThisForSuperBase(base
)) {
8827 if (!emitOptionalTree(&elem
->expression(), oe
)) {
8833 if (elem
->isKind(ParseNodeKind::OptionalElemExpr
)) {
8834 MOZ_ASSERT(!isSuper
);
8835 if (!oe
.emitJumpShortCircuit()) {
8836 // [stack] # if Jump
8837 // [stack] UNDEFINED-OR-NULL
8838 // [stack] # otherwise
8844 if (!eoe
.prepareForKey()) {
8849 if (!emitTree(&elem
->key())) {
8850 // [stack] OBJ? OBJ KEY
8854 if (!eoe
.emitGet()) {
8862 bool BytecodeEmitter::emitOptionalPrivateExpression(
8863 PrivateMemberAccessBase
* privateExpr
, PrivateOpEmitter
& xoe
,
8864 OptionalEmitter
& oe
) {
8865 if (!emitOptionalTree(&privateExpr
->expression(), oe
)) {
8870 if (privateExpr
->isKind(ParseNodeKind::OptionalPrivateMemberExpr
)) {
8871 if (!oe
.emitJumpShortCircuit()) {
8872 // [stack] # if Jump
8873 // [stack] UNDEFINED-OR-NULL
8874 // [stack] # otherwise
8880 if (!xoe
.emitReference()) {
8884 if (!xoe
.emitGet()) {
8885 // [stack] CALLEE THIS # if call
8886 // [stack] VALUE # otherwise
8893 bool BytecodeEmitter::emitShortCircuit(ListNode
* node
, ValueUsage valueUsage
) {
8894 MOZ_ASSERT(node
->isKind(ParseNodeKind::OrExpr
) ||
8895 node
->isKind(ParseNodeKind::CoalesceExpr
) ||
8896 node
->isKind(ParseNodeKind::AndExpr
));
8899 * JSOp::Or converts the operand on the stack to boolean, leaves the original
8900 * value on the stack and jumps if true; otherwise it falls into the next
8901 * bytecode, which pops the left operand and then evaluates the right operand.
8902 * The jump goes around the right operand evaluation.
8904 * JSOp::And converts the operand on the stack to boolean and jumps if false;
8905 * otherwise it falls into the right operand's bytecode.
8908 TDZCheckCache
tdzCache(this);
8911 switch (node
->getKind()) {
8912 case ParseNodeKind::OrExpr
:
8915 case ParseNodeKind::CoalesceExpr
:
8916 op
= JSOp::Coalesce
;
8918 case ParseNodeKind::AndExpr
:
8922 MOZ_CRASH("Unexpected ParseNodeKind");
8927 // Left-associative operator chain: avoid too much recursion.
8929 // Emit all nodes but the last.
8930 for (ParseNode
* expr
: node
->contentsTo(node
->last())) {
8931 if (!emitTree(expr
)) {
8934 if (!emitJump(op
, &jump
)) {
8937 if (!emit1(JSOp::Pop
)) {
8942 // Emit the last node
8943 if (!emitTree(node
->last(), valueUsage
)) {
8947 if (!emitJumpTargetAndPatch(jump
)) {
8953 bool BytecodeEmitter::emitSequenceExpr(ListNode
* node
, ValueUsage valueUsage
) {
8954 for (ParseNode
* child
: node
->contentsTo(node
->last())) {
8955 if (!updateSourceCoordNotes(child
->pn_pos
.begin
)) {
8958 if (!emitTree(child
, ValueUsage::IgnoreValue
)) {
8961 if (!emit1(JSOp::Pop
)) {
8966 ParseNode
* child
= node
->last();
8967 if (!updateSourceCoordNotes(child
->pn_pos
.begin
)) {
8970 if (!emitTree(child
, valueUsage
)) {
8976 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
8977 // the comment on emitSwitch.
8978 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitIncOrDec(UnaryNode
* incDec
,
8979 ValueUsage valueUsage
) {
8980 switch (incDec
->kid()->getKind()) {
8981 case ParseNodeKind::DotExpr
:
8982 return emitPropIncDec(incDec
, valueUsage
);
8983 case ParseNodeKind::ElemExpr
:
8984 return emitElemIncDec(incDec
, valueUsage
);
8985 case ParseNodeKind::PrivateMemberExpr
:
8986 return emitPrivateIncDec(incDec
, valueUsage
);
8987 case ParseNodeKind::CallExpr
:
8988 return emitCallIncDec(incDec
);
8990 return emitNameIncDec(incDec
, valueUsage
);
8994 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
8995 // the comment on emitSwitch.
8996 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitLabeledStatement(
8997 const LabeledStatement
* labeledStmt
) {
8998 auto name
= labeledStmt
->label();
8999 LabelEmitter
label(this);
9001 label
.emitLabel(name
);
9003 if (!emitTree(labeledStmt
->statement())) {
9006 if (!label
.emitEnd()) {
9013 bool BytecodeEmitter::emitConditionalExpression(
9014 ConditionalExpression
& conditional
, ValueUsage valueUsage
) {
9015 CondEmitter
cond(this);
9016 if (!cond
.emitCond()) {
9020 ParseNode
* conditionNode
= &conditional
.condition();
9021 auto conditionKind
= IfEmitter::ConditionKind::Positive
;
9022 if (conditionNode
->isKind(ParseNodeKind::NotExpr
)) {
9023 conditionNode
= conditionNode
->as
<UnaryNode
>().kid();
9024 conditionKind
= IfEmitter::ConditionKind::Negative
;
9027 // NOTE: NotExpr of conditionNode may be unwrapped, and in that case the
9028 // negation is handled by conditionKind.
9029 if (!emitTree(conditionNode
)) {
9033 if (!cond
.emitThenElse(conditionKind
)) {
9037 if (!emitTree(&conditional
.thenExpression(), valueUsage
)) {
9041 if (!cond
.emitElse()) {
9045 if (!emitTree(&conditional
.elseExpression(), valueUsage
)) {
9049 if (!cond
.emitEnd()) {
9052 MOZ_ASSERT(cond
.pushed() == 1);
9057 // Check for an object-literal property list that can be handled by the
9058 // ObjLiteral writer. We ensure that for each `prop: value` pair, the key is a
9059 // constant name or numeric index, there is no accessor specified, and the value
9060 // can be encoded by an ObjLiteral instruction (constant number, string,
9061 // boolean, null/undefined).
9062 void BytecodeEmitter::isPropertyListObjLiteralCompatible(ListNode
* obj
,
9064 bool* withoutValues
) {
9066 bool valuesOK
= true;
9067 uint32_t propCount
= 0;
9069 for (ParseNode
* propdef
: obj
->contents()) {
9070 if (!propdef
->is
<BinaryNode
>()) {
9076 BinaryNode
* prop
= &propdef
->as
<BinaryNode
>();
9077 ParseNode
* key
= prop
->left();
9078 ParseNode
* value
= prop
->right();
9080 // Computed keys not OK (ObjLiteral data stores constant keys).
9081 if (key
->isKind(ParseNodeKind::ComputedName
)) {
9086 // BigIntExprs should have been lowered to computed names at parse
9087 // time, and so should be excluded above.
9088 MOZ_ASSERT(!key
->isKind(ParseNodeKind::BigIntExpr
));
9090 // Numeric keys OK as long as they are integers and in range.
9091 if (key
->isKind(ParseNodeKind::NumberExpr
)) {
9092 double numValue
= key
->as
<NumericLiteral
>().value();
9094 if (!NumberIsInt32(numValue
, &i
)) {
9098 if (!ObjLiteralWriter::arrayIndexInRange(i
)) {
9104 MOZ_ASSERT(key
->isKind(ParseNodeKind::ObjectPropertyName
) ||
9105 key
->isKind(ParseNodeKind::StringExpr
) ||
9106 key
->isKind(ParseNodeKind::NumberExpr
));
9108 AccessorType accessorType
=
9109 prop
->is
<PropertyDefinition
>()
9110 ? prop
->as
<PropertyDefinition
>().accessorType()
9111 : AccessorType::None
;
9112 if (accessorType
!= AccessorType::None
) {
9117 if (!isRHSObjLiteralCompatible(value
)) {
9122 if (propCount
> SharedPropMap::MaxPropsForNonDictionary
) {
9123 // JSOp::NewObject cannot accept dictionary-mode objects.
9127 *withValues
= keysOK
&& valuesOK
;
9128 *withoutValues
= keysOK
;
9131 bool BytecodeEmitter::isArrayObjLiteralCompatible(ListNode
* array
) {
9132 for (ParseNode
* elem
: array
->contents()) {
9133 if (elem
->isKind(ParseNodeKind::Spread
)) {
9136 if (!isRHSObjLiteralCompatible(elem
)) {
9143 bool BytecodeEmitter::emitPropertyList(ListNode
* obj
, PropertyEmitter
& pe
,
9144 PropListType type
) {
9145 // [stack] CTOR? OBJ
9147 size_t curFieldKeyIndex
= 0;
9148 size_t curStaticFieldKeyIndex
= 0;
9149 for (ParseNode
* propdef
: obj
->contents()) {
9150 if (propdef
->is
<ClassField
>()) {
9151 MOZ_ASSERT(type
== ClassBody
);
9152 // Only handle computing field keys here: the .initializers lambda array
9153 // is created elsewhere.
9154 ClassField
* field
= &propdef
->as
<ClassField
>();
9155 if (field
->name().getKind() == ParseNodeKind::ComputedName
) {
9158 ? TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_()
9159 : TaggedParserAtomIndex::WellKnown::dot_fieldKeys_();
9160 if (!emitGetName(fieldKeys
)) {
9161 // [stack] CTOR OBJ ARRAY
9165 ParseNode
* nameExpr
= field
->name().as
<UnaryNode
>().kid();
9167 if (!emitTree(nameExpr
, ValueUsage::WantValue
)) {
9168 // [stack] CTOR OBJ ARRAY KEY
9172 if (!emit1(JSOp::ToPropertyKey
)) {
9173 // [stack] CTOR OBJ ARRAY KEY
9177 size_t fieldKeysIndex
;
9178 if (field
->isStatic()) {
9179 fieldKeysIndex
= curStaticFieldKeyIndex
++;
9181 fieldKeysIndex
= curFieldKeyIndex
++;
9184 if (!emitUint32Operand(JSOp::InitElemArray
, fieldKeysIndex
)) {
9185 // [stack] CTOR OBJ ARRAY
9189 if (!emit1(JSOp::Pop
)) {
9197 if (propdef
->isKind(ParseNodeKind::StaticClassBlock
)) {
9198 // Static class blocks are emitted as part of
9199 // emitCreateMemberInitializers.
9203 if (propdef
->is
<LexicalScopeNode
>()) {
9204 // Constructors are sometimes wrapped in LexicalScopeNodes. As we
9205 // already handled emitting the constructor, skip it.
9207 propdef
->as
<LexicalScopeNode
>().scopeBody()->is
<ClassMethod
>());
9211 // Handle __proto__: v specially because *only* this form, and no other
9212 // involving "__proto__", performs [[Prototype]] mutation.
9213 if (propdef
->isKind(ParseNodeKind::MutateProto
)) {
9215 MOZ_ASSERT(type
== ObjectLiteral
);
9216 if (!pe
.prepareForProtoValue(propdef
->pn_pos
.begin
)) {
9220 if (!emitTree(propdef
->as
<UnaryNode
>().kid())) {
9221 // [stack] OBJ PROTO
9224 if (!pe
.emitMutateProto()) {
9231 if (propdef
->isKind(ParseNodeKind::Spread
)) {
9232 MOZ_ASSERT(type
== ObjectLiteral
);
9234 if (!pe
.prepareForSpreadOperand(propdef
->pn_pos
.begin
)) {
9238 if (!emitTree(propdef
->as
<UnaryNode
>().kid())) {
9239 // [stack] OBJ OBJ VAL
9242 if (!pe
.emitSpread()) {
9249 BinaryNode
* prop
= &propdef
->as
<BinaryNode
>();
9251 ParseNode
* key
= prop
->left();
9252 AccessorType accessorType
;
9253 if (prop
->is
<ClassMethod
>()) {
9254 ClassMethod
& method
= prop
->as
<ClassMethod
>();
9255 accessorType
= method
.accessorType();
9257 if (!method
.isStatic() && key
->isKind(ParseNodeKind::PrivateName
) &&
9258 accessorType
!= AccessorType::None
) {
9259 // Private non-static accessors are stamped onto instances from
9260 // initializers; see emitCreateMemberInitializers.
9263 } else if (prop
->is
<PropertyDefinition
>()) {
9264 accessorType
= prop
->as
<PropertyDefinition
>().accessorType();
9266 accessorType
= AccessorType::None
;
9269 auto emitValue
= [this, &key
, &prop
, accessorType
, &pe
]() {
9270 // [stack] CTOR? OBJ CTOR? KEY?
9272 ParseNode
* propVal
= prop
->right();
9273 if (propVal
->isDirectRHSAnonFunction()) {
9274 // The following branches except for the last `else` clause emit the
9275 // cases handled in NameResolver::resolveFun (see NameFunctions.cpp)
9276 if (key
->isKind(ParseNodeKind::ObjectPropertyName
) ||
9277 key
->isKind(ParseNodeKind::PrivateName
) ||
9278 key
->isKind(ParseNodeKind::StringExpr
)) {
9279 auto keyAtom
= key
->as
<NameNode
>().atom();
9280 if (!emitAnonymousFunctionWithName(propVal
, keyAtom
)) {
9281 // [stack] CTOR? OBJ CTOR? VAL
9284 } else if (key
->isKind(ParseNodeKind::NumberExpr
)) {
9285 MOZ_ASSERT(accessorType
== AccessorType::None
);
9287 auto keyAtom
= key
->as
<NumericLiteral
>().toAtom(fc
, parserAtoms());
9291 if (!emitAnonymousFunctionWithName(propVal
, keyAtom
)) {
9292 // [stack] CTOR? OBJ CTOR? KEY VAL
9295 } else if (key
->isKind(ParseNodeKind::ComputedName
) &&
9296 (key
->as
<UnaryNode
>().kid()->isKind(
9297 ParseNodeKind::NumberExpr
) ||
9298 key
->as
<UnaryNode
>().kid()->isKind(
9299 ParseNodeKind::StringExpr
)) &&
9300 accessorType
== AccessorType::None
) {
9301 ParseNode
* keyKid
= key
->as
<UnaryNode
>().kid();
9302 if (keyKid
->isKind(ParseNodeKind::NumberExpr
)) {
9304 keyKid
->as
<NumericLiteral
>().toAtom(fc
, parserAtoms());
9308 if (!emitAnonymousFunctionWithName(propVal
, keyAtom
)) {
9309 // [stack] CTOR? OBJ CTOR? KEY VAL
9313 MOZ_ASSERT(keyKid
->isKind(ParseNodeKind::StringExpr
));
9314 auto keyAtom
= keyKid
->as
<NameNode
>().atom();
9315 if (!emitAnonymousFunctionWithName(propVal
, keyAtom
)) {
9316 // [stack] CTOR? OBJ CTOR? KEY VAL
9321 // Either a proper computed property name or a synthetic computed
9322 // property name for BigInt keys.
9323 MOZ_ASSERT(key
->isKind(ParseNodeKind::ComputedName
));
9325 FunctionPrefixKind prefix
=
9326 accessorType
== AccessorType::None
? FunctionPrefixKind::None
9327 : accessorType
== AccessorType::Getter
? FunctionPrefixKind::Get
9328 : FunctionPrefixKind::Set
;
9330 if (!emitAnonymousFunctionWithComputedName(propVal
, prefix
)) {
9331 // [stack] CTOR? OBJ CTOR? KEY VAL
9336 if (!emitTree(propVal
)) {
9337 // [stack] CTOR? OBJ CTOR? KEY? VAL
9342 if (propVal
->is
<FunctionNode
>() &&
9343 propVal
->as
<FunctionNode
>().funbox()->needsHomeObject()) {
9344 if (!pe
.emitInitHomeObject()) {
9345 // [stack] CTOR? OBJ CTOR? KEY? FUN
9350 #ifdef ENABLE_DECORATORS
9351 if (prop
->is
<ClassMethod
>()) {
9352 ClassMethod
& method
= prop
->as
<ClassMethod
>();
9353 if (method
.decorators() && !method
.decorators()->empty()) {
9354 DecoratorEmitter::Kind kind
;
9355 switch (method
.accessorType()) {
9356 case AccessorType::Getter
:
9357 kind
= DecoratorEmitter::Getter
;
9359 case AccessorType::Setter
:
9360 kind
= DecoratorEmitter::Setter
;
9362 case AccessorType::None
:
9363 kind
= DecoratorEmitter::Method
;
9367 // The decorators are applied to the current value on the stack,
9368 // possibly replacing it.
9369 DecoratorEmitter
de(this);
9370 if (!de
.emitApplyDecoratorsToElementDefinition(
9371 kind
, key
, method
.decorators(), method
.isStatic())) {
9372 // [stack] CTOR? OBJ CTOR? KEY? VAL
9382 PropertyEmitter::Kind kind
=
9383 (type
== ClassBody
&& propdef
->as
<ClassMethod
>().isStatic())
9384 ? PropertyEmitter::Kind::Static
9385 : PropertyEmitter::Kind::Prototype
;
9386 if (key
->isKind(ParseNodeKind::ObjectPropertyName
) ||
9387 key
->isKind(ParseNodeKind::StringExpr
)) {
9388 // [stack] CTOR? OBJ
9390 auto keyAtom
= key
->as
<NameNode
>().atom();
9392 // emitClass took care of constructor already.
9393 if (type
== ClassBody
&&
9394 keyAtom
== TaggedParserAtomIndex::WellKnown::constructor() &&
9395 !propdef
->as
<ClassMethod
>().isStatic()) {
9399 if (!pe
.prepareForPropValue(propdef
->pn_pos
.begin
, kind
)) {
9400 // [stack] CTOR? OBJ CTOR?
9405 // [stack] CTOR? OBJ CTOR? VAL
9409 if (!pe
.emitInit(accessorType
, keyAtom
)) {
9410 // [stack] CTOR? OBJ
9417 if (key
->isKind(ParseNodeKind::NumberExpr
)) {
9418 // [stack] CTOR? OBJ
9419 if (!pe
.prepareForIndexPropKey(propdef
->pn_pos
.begin
, kind
)) {
9420 // [stack] CTOR? OBJ CTOR?
9423 if (!emitNumberOp(key
->as
<NumericLiteral
>().value())) {
9424 // [stack] CTOR? OBJ CTOR? KEY
9427 if (!pe
.prepareForIndexPropValue()) {
9428 // [stack] CTOR? OBJ CTOR? KEY
9432 // [stack] CTOR? OBJ CTOR? KEY VAL
9436 if (!pe
.emitInitIndexOrComputed(accessorType
)) {
9437 // [stack] CTOR? OBJ
9444 if (key
->isKind(ParseNodeKind::ComputedName
)) {
9445 // Either a proper computed property name or a synthetic computed property
9446 // name for BigInt keys.
9448 // [stack] CTOR? OBJ
9450 if (!pe
.prepareForComputedPropKey(propdef
->pn_pos
.begin
, kind
)) {
9451 // [stack] CTOR? OBJ CTOR?
9454 if (!emitTree(key
->as
<UnaryNode
>().kid())) {
9455 // [stack] CTOR? OBJ CTOR? KEY
9458 if (!pe
.prepareForComputedPropValue()) {
9459 // [stack] CTOR? OBJ CTOR? KEY
9463 // [stack] CTOR? OBJ CTOR? KEY VAL
9467 if (!pe
.emitInitIndexOrComputed(accessorType
)) {
9468 // [stack] CTOR? OBJ
9475 MOZ_ASSERT(key
->isKind(ParseNodeKind::PrivateName
));
9476 MOZ_ASSERT(type
== ClassBody
);
9478 auto* privateName
= &key
->as
<NameNode
>();
9480 if (kind
== PropertyEmitter::Kind::Prototype
) {
9481 MOZ_ASSERT(accessorType
== AccessorType::None
);
9482 if (!pe
.prepareForPrivateMethod()) {
9486 NameOpEmitter
noe(this, privateName
->atom(),
9487 NameOpEmitter::Kind::SimpleAssignment
);
9489 // Ensure the NameOp emitter doesn't push an environment onto the stack,
9490 // because that would change the stack location of the home object.
9491 MOZ_ASSERT(noe
.loc().kind() == NameLocation::Kind::FrameSlot
||
9492 noe
.loc().kind() == NameLocation::Kind::EnvironmentCoordinate
);
9494 if (!noe
.prepareForRhs()) {
9499 // [stack] CTOR OBJ METHOD
9502 if (!noe
.emitAssignment()) {
9503 // [stack] CTOR OBJ METHOD
9506 if (!emit1(JSOp::Pop
)) {
9510 if (!pe
.skipInit()) {
9517 MOZ_ASSERT(kind
== PropertyEmitter::Kind::Static
);
9521 if (!pe
.prepareForPrivateStaticMethod(propdef
->pn_pos
.begin
)) {
9522 // [stack] CTOR OBJ CTOR
9525 if (!emitGetPrivateName(privateName
)) {
9526 // [stack] CTOR OBJ CTOR KEY
9530 // [stack] CTOR OBJ CTOR KEY VAL
9534 if (!pe
.emitPrivateStaticMethod(accessorType
)) {
9539 if (privateName
->privateNameKind() == PrivateNameKind::Setter
) {
9540 if (!emitDupAt(1)) {
9541 // [stack] CTOR OBJ CTOR
9544 if (!emitGetPrivateName(privateName
)) {
9545 // [stack] CTOR OBJ CTOR NAME
9548 if (!emitAtomOp(JSOp::GetIntrinsic
,
9549 TaggedParserAtomIndex::WellKnown::NoPrivateGetter())) {
9550 // [stack] CTOR OBJ CTOR NAME FUN
9553 if (!emit1(JSOp::InitHiddenElemGetter
)) {
9554 // [stack] CTOR OBJ CTOR
9557 if (!emit1(JSOp::Pop
)) {
9567 bool BytecodeEmitter::emitPropertyListObjLiteral(ListNode
* obj
, JSOp op
,
9568 bool useObjLiteralValues
) {
9569 ObjLiteralWriter writer
;
9572 // In self-hosted JS, we check duplication only on debug build.
9573 mozilla::Maybe
<mozilla::HashSet
<frontend::TaggedParserAtomIndex
,
9574 frontend::TaggedParserAtomIndexHasher
>>
9575 selfHostedPropNames
;
9576 if (emitterMode
== BytecodeEmitter::SelfHosting
) {
9577 selfHostedPropNames
.emplace();
9581 if (op
== JSOp::Object
) {
9582 writer
.beginObject(op
);
9584 MOZ_ASSERT(op
== JSOp::NewObject
);
9585 writer
.beginShape(op
);
9588 for (ParseNode
* propdef
: obj
->contents()) {
9589 BinaryNode
* prop
= &propdef
->as
<BinaryNode
>();
9590 ParseNode
* key
= prop
->left();
9592 if (key
->is
<NameNode
>()) {
9593 if (emitterMode
== BytecodeEmitter::SelfHosting
) {
9594 auto propName
= key
->as
<NameNode
>().atom();
9596 // Self-hosted JS shouldn't contain duplicate properties.
9597 auto p
= selfHostedPropNames
->lookupForAdd(propName
);
9599 if (!selfHostedPropNames
->add(p
, propName
)) {
9600 js::ReportOutOfMemory(fc
);
9604 writer
.setPropNameNoDuplicateCheck(parserAtoms(), propName
);
9606 if (!writer
.setPropName(parserAtoms(), key
->as
<NameNode
>().atom())) {
9611 double numValue
= key
->as
<NumericLiteral
>().value();
9613 DebugOnly
<bool> numIsInt
=
9614 NumberIsInt32(numValue
, &i
); // checked previously.
9615 MOZ_ASSERT(numIsInt
);
9617 ObjLiteralWriter::arrayIndexInRange(i
)); // checked previously.
9619 // Ignore indexed properties if we're not storing property values, and
9620 // rely on InitElem ops to define those. These properties will be either
9621 // dense elements (not possible to represent in the literal's shape) or
9622 // sparse elements (enumerated separately, so this doesn't affect property
9623 // iteration order).
9624 if (!useObjLiteralValues
) {
9628 writer
.setPropIndex(i
);
9631 if (useObjLiteralValues
) {
9632 MOZ_ASSERT(op
== JSOp::Object
);
9633 ParseNode
* value
= prop
->right();
9634 if (!emitObjLiteralValue(writer
, value
)) {
9638 if (!writer
.propWithUndefinedValue(fc
)) {
9645 if (!addObjLiteralData(writer
, &index
)) {
9649 // JSOp::Object may only be used by (top-level) run-once scripts.
9650 MOZ_ASSERT_IF(op
== JSOp::Object
,
9651 sc
->isTopLevelContext() && sc
->treatAsRunOnce());
9653 if (!emitGCIndexOp(op
, index
)) {
9661 bool BytecodeEmitter::emitDestructuringRestExclusionSetObjLiteral(
9662 ListNode
* pattern
) {
9663 // Note: if we want to squeeze out a little more performance, we could switch
9664 // to the `JSOp::Object` opcode, because the exclusion set object is never
9665 // exposed to the user, so it's safe to bake the object into the bytecode.
9666 constexpr JSOp op
= JSOp::NewObject
;
9668 ObjLiteralWriter writer
;
9669 writer
.beginShape(op
);
9671 for (ParseNode
* member
: pattern
->contents()) {
9672 if (member
->isKind(ParseNodeKind::Spread
)) {
9673 MOZ_ASSERT(!member
->pn_next
, "unexpected trailing element after spread");
9677 TaggedParserAtomIndex atom
;
9678 if (member
->isKind(ParseNodeKind::MutateProto
)) {
9679 atom
= TaggedParserAtomIndex::WellKnown::proto_();
9681 ParseNode
* key
= member
->as
<BinaryNode
>().left();
9682 atom
= key
->as
<NameNode
>().atom();
9685 if (!writer
.setPropName(parserAtoms(), atom
)) {
9689 if (!writer
.propWithUndefinedValue(fc
)) {
9695 if (!addObjLiteralData(writer
, &index
)) {
9699 if (!emitGCIndexOp(op
, index
)) {
9707 bool BytecodeEmitter::emitObjLiteralArray(ListNode
* array
) {
9708 MOZ_ASSERT(checkSingletonContext());
9710 constexpr JSOp op
= JSOp::Object
;
9712 ObjLiteralWriter writer
;
9713 writer
.beginArray(op
);
9715 writer
.beginDenseArrayElements();
9716 for (ParseNode
* elem
: array
->contents()) {
9717 if (!emitObjLiteralValue(writer
, elem
)) {
9723 if (!addObjLiteralData(writer
, &index
)) {
9727 if (!emitGCIndexOp(op
, index
)) {
9735 bool BytecodeEmitter::isRHSObjLiteralCompatible(ParseNode
* value
) {
9736 return value
->isKind(ParseNodeKind::NumberExpr
) ||
9737 value
->isKind(ParseNodeKind::TrueExpr
) ||
9738 value
->isKind(ParseNodeKind::FalseExpr
) ||
9739 value
->isKind(ParseNodeKind::NullExpr
) ||
9740 value
->isKind(ParseNodeKind::RawUndefinedExpr
) ||
9741 value
->isKind(ParseNodeKind::StringExpr
) ||
9742 value
->isKind(ParseNodeKind::TemplateStringExpr
);
9745 bool BytecodeEmitter::emitObjLiteralValue(ObjLiteralWriter
& writer
,
9747 MOZ_ASSERT(isRHSObjLiteralCompatible(value
));
9748 if (value
->isKind(ParseNodeKind::NumberExpr
)) {
9749 double numValue
= value
->as
<NumericLiteral
>().value();
9752 if (NumberIsInt32(numValue
, &i
)) {
9755 v
.setDouble(numValue
);
9757 if (!writer
.propWithConstNumericValue(fc
, v
)) {
9760 } else if (value
->isKind(ParseNodeKind::TrueExpr
)) {
9761 if (!writer
.propWithTrueValue(fc
)) {
9764 } else if (value
->isKind(ParseNodeKind::FalseExpr
)) {
9765 if (!writer
.propWithFalseValue(fc
)) {
9768 } else if (value
->isKind(ParseNodeKind::NullExpr
)) {
9769 if (!writer
.propWithNullValue(fc
)) {
9772 } else if (value
->isKind(ParseNodeKind::RawUndefinedExpr
)) {
9773 if (!writer
.propWithUndefinedValue(fc
)) {
9776 } else if (value
->isKind(ParseNodeKind::StringExpr
) ||
9777 value
->isKind(ParseNodeKind::TemplateStringExpr
)) {
9778 if (!writer
.propWithAtomValue(fc
, parserAtoms(),
9779 value
->as
<NameNode
>().atom())) {
9783 MOZ_CRASH("Unexpected parse node");
9788 static bool NeedsPrivateBrand(ParseNode
* member
) {
9789 return member
->is
<ClassMethod
>() &&
9790 member
->as
<ClassMethod
>().name().isKind(ParseNodeKind::PrivateName
) &&
9791 !member
->as
<ClassMethod
>().isStatic();
9794 mozilla::Maybe
<MemberInitializers
> BytecodeEmitter::setupMemberInitializers(
9795 ListNode
* classMembers
, FieldPlacement placement
) {
9796 bool isStatic
= placement
== FieldPlacement::Static
;
9798 size_t numFields
= 0;
9799 size_t numPrivateInitializers
= 0;
9800 bool hasPrivateBrand
= false;
9801 for (ParseNode
* member
: classMembers
->contents()) {
9802 if (NeedsFieldInitializer(member
, isStatic
)) {
9804 } else if (NeedsAccessorInitializer(member
, isStatic
)) {
9805 numPrivateInitializers
++;
9806 hasPrivateBrand
= true;
9807 } else if (NeedsPrivateBrand(member
)) {
9808 hasPrivateBrand
= true;
9812 // If there are more initializers than can be represented, return invalid.
9813 if (numFields
+ numPrivateInitializers
>
9814 MemberInitializers::MaxInitializers
) {
9818 MemberInitializers(hasPrivateBrand
, numFields
+ numPrivateInitializers
));
9821 // Purpose of .fieldKeys:
9822 // Computed field names (`["x"] = 2;`) must be ran at class-evaluation time,
9823 // not object construction time. The transformation to do so is roughly as
9827 // [keyExpr] = valueExpr;
9830 // let .fieldKeys = [keyExpr];
9831 // let .initializers = [
9833 // this[.fieldKeys[0]] = valueExpr;
9838 // .initializers[0]();
9842 // BytecodeEmitter::emitCreateFieldKeys does `let .fieldKeys = [...];`
9843 // BytecodeEmitter::emitPropertyList fills in the elements of the array.
9844 // See GeneralParser::fieldInitializer for the `this[.fieldKeys[0]]` part.
9845 bool BytecodeEmitter::emitCreateFieldKeys(ListNode
* obj
,
9846 FieldPlacement placement
) {
9847 bool isStatic
= placement
== FieldPlacement::Static
;
9848 auto isFieldWithComputedName
= [isStatic
](ParseNode
* propdef
) {
9849 return propdef
->is
<ClassField
>() &&
9850 propdef
->as
<ClassField
>().isStatic() == isStatic
&&
9851 propdef
->as
<ClassField
>().name().getKind() ==
9852 ParseNodeKind::ComputedName
;
9855 size_t numFieldKeys
= std::count_if(
9856 obj
->contents().begin(), obj
->contents().end(), isFieldWithComputedName
);
9857 if (numFieldKeys
== 0) {
9862 isStatic
? TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_()
9863 : TaggedParserAtomIndex::WellKnown::dot_fieldKeys_();
9864 NameOpEmitter
noe(this, fieldKeys
, NameOpEmitter::Kind::Initialize
);
9865 if (!noe
.prepareForRhs()) {
9869 if (!emitUint32Operand(JSOp::NewArray
, numFieldKeys
)) {
9874 if (!noe
.emitAssignment()) {
9879 if (!emit1(JSOp::Pop
)) {
9887 static bool HasInitializer(ParseNode
* node
, bool isStaticContext
) {
9888 return (node
->is
<ClassField
>() &&
9889 node
->as
<ClassField
>().isStatic() == isStaticContext
) ||
9890 (isStaticContext
&& node
->is
<StaticClassBlock
>());
9893 static FunctionNode
* GetInitializer(ParseNode
* node
, bool isStaticContext
) {
9894 MOZ_ASSERT(HasInitializer(node
, isStaticContext
));
9895 MOZ_ASSERT_IF(!node
->is
<ClassField
>(), isStaticContext
);
9896 return node
->is
<ClassField
>() ? node
->as
<ClassField
>().initializer()
9897 : node
->as
<StaticClassBlock
>().function();
9900 static bool IsPrivateInstanceAccessor(const ClassMethod
* classMethod
) {
9901 return !classMethod
->isStatic() &&
9902 classMethod
->name().isKind(ParseNodeKind::PrivateName
) &&
9903 classMethod
->accessorType() != AccessorType::None
;
9906 bool BytecodeEmitter::emitCreateMemberInitializers(ClassEmitter
& ce
,
9908 FieldPlacement placement
9909 #ifdef ENABLE_DECORATORS
9914 // FieldPlacement::Instance, hasHeritage == false
9917 // FieldPlacement::Instance, hasHeritage == true
9918 // [stack] HOMEOBJ HERITAGE
9920 // FieldPlacement::Static
9921 // [stack] CTOR HOMEOBJ
9922 #ifdef ENABLE_DECORATORS
9923 MOZ_ASSERT_IF(placement
== FieldPlacement::Static
, !hasHeritage
);
9925 mozilla::Maybe
<MemberInitializers
> memberInitializers
=
9926 setupMemberInitializers(obj
, placement
);
9927 if (!memberInitializers
) {
9928 ReportAllocationOverflow(fc
);
9932 size_t numInitializers
= memberInitializers
->numMemberInitializers
;
9933 if (numInitializers
== 0) {
9937 bool isStatic
= placement
== FieldPlacement::Static
;
9938 if (!ce
.prepareForMemberInitializers(numInitializers
, isStatic
)) {
9939 // [stack] HOMEOBJ HERITAGE? ARRAY
9941 // [stack] CTOR HOMEOBJ ARRAY
9945 // Private accessors could be used in the field initializers, so make sure
9946 // accessor initializers appear earlier in the .initializers array so they
9947 // run first. Static private methods are not initialized using initializers
9948 // (emitPropertyList emits bytecode to stamp them onto the constructor), so
9949 // skip this step if isStatic.
9951 if (!emitPrivateMethodInitializers(ce
, obj
)) {
9956 for (ParseNode
* propdef
: obj
->contents()) {
9957 if (!HasInitializer(propdef
, isStatic
)) {
9961 FunctionNode
* initializer
= GetInitializer(propdef
, isStatic
);
9963 if (!ce
.prepareForMemberInitializer()) {
9966 if (!emitTree(initializer
)) {
9967 // [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA
9969 // [stack] CTOR HOMEOBJ ARRAY LAMBDA
9972 if (initializer
->funbox()->needsHomeObject()) {
9973 MOZ_ASSERT(initializer
->funbox()->allowSuperProperty());
9974 if (!ce
.emitMemberInitializerHomeObject(isStatic
)) {
9975 // [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA
9977 // [stack] CTOR HOMEOBJ ARRAY LAMBDA
9981 if (!ce
.emitStoreMemberInitializer()) {
9982 // [stack] HOMEOBJ HERITAGE? ARRAY
9984 // [stack] CTOR HOMEOBJ ARRAY
9989 #ifdef ENABLE_DECORATORS
9990 // Index to use to append new initializers returned by decorators to the array
9991 if (!emitNumberOp(numInitializers
)) {
9992 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX
9994 // [stack] CTOR HOMEOBJ ARRAY INDEX
9998 for (ParseNode
* propdef
: obj
->contents()) {
9999 if (!propdef
->is
<ClassField
>()) {
10002 ClassField
* field
= &propdef
->as
<ClassField
>();
10003 if (field
->isStatic() != isStatic
) {
10006 if (field
->decorators() && !field
->decorators()->empty()) {
10007 DecoratorEmitter
de(this);
10008 if (!field
->hasAccessor()) {
10009 if (!de
.emitApplyDecoratorsToFieldDefinition(
10010 &field
->name(), field
->decorators(), field
->isStatic())) {
10011 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS
10013 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS
10017 ClassMethod
* accessorGetterNode
= field
->accessorGetterNode();
10018 auto accessorGetterKeyAtom
=
10019 accessorGetterNode
->left()->as
<NameNode
>().atom();
10020 ClassMethod
* accessorSetterNode
= field
->accessorSetterNode();
10021 auto accessorSetterKeyAtom
=
10022 accessorSetterNode
->left()->as
<NameNode
>().atom();
10023 if (!IsPrivateInstanceAccessor(accessorGetterNode
)) {
10024 if (!emitTree(&accessorGetterNode
->method())) {
10025 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER
10027 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER
10030 if (!emitTree(&accessorSetterNode
->method())) {
10031 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER SETTER
10033 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER SETTER
10037 MOZ_ASSERT(IsPrivateInstanceAccessor(accessorSetterNode
));
10038 auto getAccessor
= [this](
10039 ClassMethod
* classMethod
,
10040 TaggedParserAtomIndex
& updatedAtom
) -> bool {
10043 // Synthesize a name for the lexical variable that will store the
10044 // private method body.
10045 TaggedParserAtomIndex name
=
10046 classMethod
->name().as
<NameNode
>().atom();
10047 AccessorType accessorType
= classMethod
->accessorType();
10048 StringBuffer
storedMethodName(fc
);
10049 if (!storedMethodName
.append(parserAtoms(), name
)) {
10052 if (!storedMethodName
.append(accessorType
== AccessorType::Getter
10057 updatedAtom
= storedMethodName
.finishParserAtom(parserAtoms(), fc
);
10058 if (!updatedAtom
) {
10062 return emitGetName(updatedAtom
);
10063 // [stack] ACCESSOR
10066 if (!getAccessor(accessorGetterNode
, accessorGetterKeyAtom
)) {
10067 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER
10069 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER
10073 if (!getAccessor(accessorSetterNode
, accessorSetterKeyAtom
)) {
10074 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER SETTER
10076 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER SETTER
10081 if (!de
.emitApplyDecoratorsToAccessorDefinition(
10082 &field
->name(), field
->decorators(), field
->isStatic())) {
10083 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX GETTER SETTER INITS
10085 // [stack] CTOR HOMEOBJ ARRAY INDEX GETTER SETTER INITS
10089 if (!emitUnpickN(2)) {
10090 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER SETTER
10092 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER SETTER
10096 if (!IsPrivateInstanceAccessor(accessorGetterNode
)) {
10098 if (!emitPickN(hasHeritage
? 6 : 5)) {
10099 // [stack] HERITAGE? ARRAY INDEX INITS GETTER SETTER HOMEOBJ
10103 if (!emitPickN(6)) {
10104 // [stack] HOMEOBJ ARRAY INDEX INITS GETTER SETTER CTOR
10107 if (!emitPickN(6)) {
10108 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ
10113 PropertyEmitter::Kind kind
= field
->isStatic()
10114 ? PropertyEmitter::Kind::Static
10115 : PropertyEmitter::Kind::Prototype
;
10116 if (!accessorGetterNode
->name().isKind(ParseNodeKind::PrivateName
)) {
10118 !accessorSetterNode
->name().isKind(ParseNodeKind::PrivateName
));
10120 if (!ce
.prepareForPropValue(propdef
->pn_pos
.begin
, kind
)) {
10121 // [stack] HERITAGE? ARRAY INDEX INITS GETTER SETTER HOMEOBJ
10123 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ CTOR
10126 if (!emitPickN(isStatic
? 3 : 1)) {
10127 // [stack] HERITAGE? ARRAY INDEX INITS GETTER HOMEOBJ SETTER
10129 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR SETTER
10132 if (!ce
.emitInit(AccessorType::Setter
, accessorSetterKeyAtom
)) {
10133 // [stack] HERITAGE? ARRAY INDEX INITS GETTER HOMEOBJ
10135 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ
10139 if (!ce
.prepareForPropValue(propdef
->pn_pos
.begin
, kind
)) {
10140 // [stack] HERITAGE? ARRAY INDEX INITS GETTER HOMEOBJ
10142 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR
10145 if (!emitPickN(isStatic
? 3 : 1)) {
10146 // [stack] HERITAGE? ARRAY INDEX INITS HOMEOBJ GETTER
10148 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ CTOR GETTER
10151 if (!ce
.emitInit(AccessorType::Getter
, accessorGetterKeyAtom
)) {
10152 // [stack] HERITAGE? ARRAY INDEX INITS HOMEOBJ
10154 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ
10158 MOZ_ASSERT(isStatic
);
10159 // The getter and setter share the same name.
10160 if (!emitNewPrivateName(accessorSetterKeyAtom
,
10161 accessorSetterKeyAtom
)) {
10164 if (!ce
.prepareForPrivateStaticMethod(propdef
->pn_pos
.begin
)) {
10165 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ CTOR
10168 if (!emitGetPrivateName(
10169 &accessorSetterNode
->name().as
<NameNode
>())) {
10170 // [stack] ARRAY INDEX INITS GETTER SETTER CTOR HOMEOBJ CTOR
10174 if (!emitPickN(4)) {
10175 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR KEY
10179 if (!ce
.emitPrivateStaticMethod(AccessorType::Setter
)) {
10180 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ
10184 if (!ce
.prepareForPrivateStaticMethod(propdef
->pn_pos
.begin
)) {
10185 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR
10188 if (!emitGetPrivateName(
10189 &accessorGetterNode
->name().as
<NameNode
>())) {
10190 // [stack] ARRAY INDEX INITS GETTER CTOR HOMEOBJ CTOR KEY
10193 if (!emitPickN(4)) {
10194 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ CTOR KEY GETTER
10197 if (!ce
.emitPrivateStaticMethod(AccessorType::Getter
)) {
10198 // [stack] ARRAY INDEX INITS CTOR HOMEOBJ
10204 if (!emitUnpickN(hasHeritage
? 4 : 3)) {
10205 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS
10209 if (!emitUnpickN(4)) {
10210 // [stack] HOMEOBJ ARRAY INDEX INITS CTOR
10213 if (!emitUnpickN(4)) {
10214 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS
10219 MOZ_ASSERT(IsPrivateInstanceAccessor(accessorSetterNode
));
10221 if (!emitLexicalInitialization(accessorSetterKeyAtom
)) {
10222 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER SETTER
10224 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER SETTER
10228 if (!emitPopN(1)) {
10229 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER
10231 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER
10235 if (!emitLexicalInitialization(accessorGetterKeyAtom
)) {
10236 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS GETTER
10238 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS GETTER
10242 if (!emitPopN(1)) {
10243 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX INITS
10245 // [stack] CTOR HOMEOBJ ARRAY INDEX INITS
10250 if (!emit1(JSOp::InitElemInc
)) {
10251 // [stack] HOMEOBJ HERITAGE? ARRAY INDEX
10253 // [stack] CTOR HOMEOBJ ARRAY INDEX
10260 if (!emitPopN(1)) {
10261 // [stack] HOMEOBJ HERITAGE? ARRAY
10263 // [stack] CTOR HOMEOBJ ARRAY
10268 if (!ce
.emitMemberInitializersEnd()) {
10269 // [stack] HOMEOBJ HERITAGE?
10271 // [stack] CTOR HOMEOBJ
10278 bool BytecodeEmitter::emitPrivateMethodInitializers(ClassEmitter
& ce
,
10280 for (ParseNode
* propdef
: obj
->contents()) {
10281 if (!propdef
->is
<ClassMethod
>()) {
10284 auto* classMethod
= &propdef
->as
<ClassMethod
>();
10286 // Skip over anything which isn't a private instance accessor.
10287 if (!IsPrivateInstanceAccessor(classMethod
)) {
10291 if (!ce
.prepareForMemberInitializer()) {
10292 // [stack] HOMEOBJ HERITAGE? ARRAY
10294 // [stack] CTOR HOMEOBJ ARRAY
10298 // Synthesize a name for the lexical variable that will store the
10299 // private method body.
10300 TaggedParserAtomIndex name
= classMethod
->name().as
<NameNode
>().atom();
10301 AccessorType accessorType
= classMethod
->accessorType();
10302 StringBuffer
storedMethodName(fc
);
10303 if (!storedMethodName
.append(parserAtoms(), name
)) {
10306 if (!storedMethodName
.append(
10307 accessorType
== AccessorType::Getter
? ".getter" : ".setter")) {
10310 auto storedMethodAtom
=
10311 storedMethodName
.finishParserAtom(parserAtoms(), fc
);
10313 // Emit the private method body and store it as a lexical var.
10314 if (!emitFunction(&classMethod
->method())) {
10315 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
10317 // [stack] CTOR HOMEOBJ ARRAY METHOD
10320 // The private method body needs to access the home object,
10321 // and the CE knows where that is on the stack.
10322 if (classMethod
->method().funbox()->needsHomeObject()) {
10323 if (!ce
.emitMemberInitializerHomeObject(false)) {
10324 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
10326 // [stack] CTOR HOMEOBJ ARRAY METHOD
10330 if (!emitLexicalInitialization(storedMethodAtom
)) {
10331 // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
10333 // [stack] CTOR HOMEOBJ ARRAY METHOD
10336 if (!emit1(JSOp::Pop
)) {
10337 // [stack] HOMEOBJ HERITAGE? ARRAY
10339 // [stack] CTOR HOMEOBJ ARRAY
10343 if (!emitPrivateMethodInitializer(classMethod
, storedMethodAtom
)) {
10344 // [stack] HOMEOBJ HERITAGE? ARRAY
10346 // [stack] CTOR HOMEOBJ ARRAY
10350 // Store the emitted initializer function into the .initializers array.
10351 if (!ce
.emitStoreMemberInitializer()) {
10352 // [stack] HOMEOBJ HERITAGE? ARRAY
10354 // [stack] CTOR HOMEOBJ ARRAY
10362 bool BytecodeEmitter::emitPrivateMethodInitializer(
10363 ClassMethod
* classMethod
, TaggedParserAtomIndex storedMethodAtom
) {
10364 MOZ_ASSERT(IsPrivateInstanceAccessor(classMethod
));
10366 auto* name
= &classMethod
->name().as
<NameNode
>();
10368 // Emit the synthesized initializer function.
10369 FunctionNode
* funNode
= classMethod
->initializerIfPrivate();
10370 MOZ_ASSERT(funNode
);
10371 FunctionBox
* funbox
= funNode
->funbox();
10372 FunctionEmitter
fe(this, funbox
, funNode
->syntaxKind(),
10373 FunctionEmitter::IsHoisted::No
);
10374 if (!fe
.prepareForNonLazy()) {
10379 BytecodeEmitter
bce2(this, funbox
);
10380 if (!bce2
.init(funNode
->pn_pos
)) {
10383 ParamsBodyNode
* paramsBody
= funNode
->body();
10384 FunctionScriptEmitter
fse(&bce2
, funbox
, Nothing(), Nothing());
10385 if (!fse
.prepareForParameters()) {
10389 if (!bce2
.emitFunctionFormalParameters(paramsBody
)) {
10393 if (!fse
.prepareForBody()) {
10398 if (!bce2
.emit1(JSOp::FunctionThis
)) {
10402 if (!bce2
.emitGetPrivateName(name
)) {
10403 // [stack] THIS NAME
10406 if (!bce2
.emitGetName(storedMethodAtom
)) {
10407 // [stack] THIS NAME METHOD
10411 switch (name
->privateNameKind()) {
10412 case PrivateNameKind::Setter
:
10413 if (!bce2
.emit1(JSOp::InitHiddenElemSetter
)) {
10417 if (!bce2
.emitGetPrivateName(name
)) {
10418 // [stack] THIS NAME
10421 if (!bce2
.emitAtomOp(
10422 JSOp::GetIntrinsic
,
10423 TaggedParserAtomIndex::WellKnown::NoPrivateGetter())) {
10424 // [stack] THIS NAME FUN
10427 if (!bce2
.emit1(JSOp::InitHiddenElemGetter
)) {
10432 case PrivateNameKind::Getter
:
10433 case PrivateNameKind::GetterSetter
:
10434 if (classMethod
->accessorType() == AccessorType::Getter
) {
10435 if (!bce2
.emit1(JSOp::InitHiddenElemGetter
)) {
10440 if (!bce2
.emit1(JSOp::InitHiddenElemSetter
)) {
10447 MOZ_CRASH("Invalid op");
10450 // Pop remaining THIS.
10451 if (!bce2
.emit1(JSOp::Pop
)) {
10456 if (!fse
.emitEndBody()) {
10460 if (!fse
.intoStencil()) {
10464 if (!fe
.emitNonLazyEnd()) {
10465 // [stack] HOMEOBJ HERITAGE? ARRAY FUN
10467 // [stack] CTOR HOMEOBJ ARRAY FUN
10474 const MemberInitializers
& BytecodeEmitter::findMemberInitializersForCall() {
10475 for (BytecodeEmitter
* current
= this; current
; current
= current
->parent
) {
10476 if (current
->sc
->isFunctionBox()) {
10477 FunctionBox
* funbox
= current
->sc
->asFunctionBox();
10479 if (funbox
->isArrow()) {
10483 // If we found a non-arrow / non-constructor we were never allowed to
10484 // expect fields in the first place.
10485 MOZ_RELEASE_ASSERT(funbox
->isClassConstructor());
10487 return funbox
->useMemberInitializers() ? funbox
->memberInitializers()
10488 : MemberInitializers::Empty();
10492 MOZ_RELEASE_ASSERT(compilationState
.scopeContext
.memberInitializers
);
10493 return *compilationState
.scopeContext
.memberInitializers
;
10496 bool BytecodeEmitter::emitInitializeInstanceMembers(
10497 bool isDerivedClassConstructor
) {
10498 const MemberInitializers
& memberInitializers
=
10499 findMemberInitializersForCall();
10500 MOZ_ASSERT(memberInitializers
.valid
);
10502 if (memberInitializers
.hasPrivateBrand
) {
10503 // This is guaranteed to run after super(), so we don't need TDZ checks.
10504 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
10508 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_privateBrand_())) {
10509 // [stack] THIS BRAND
10512 if (isDerivedClassConstructor
) {
10513 if (!emitCheckPrivateField(ThrowCondition::ThrowHas
,
10514 ThrowMsgKind::PrivateBrandDoubleInit
)) {
10515 // [stack] THIS BRAND BOOL
10518 if (!emit1(JSOp::Pop
)) {
10519 // [stack] THIS BRAND
10523 if (!emit1(JSOp::Null
)) {
10524 // [stack] THIS BRAND NULL
10527 if (!emit1(JSOp::InitHiddenElem
)) {
10531 if (!emit1(JSOp::Pop
)) {
10537 size_t numInitializers
= memberInitializers
.numMemberInitializers
;
10538 if (numInitializers
> 0) {
10539 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) {
10544 for (size_t index
= 0; index
< numInitializers
; index
++) {
10545 if (index
< numInitializers
- 1) {
10546 // We Dup to keep the array around (it is consumed in the bytecode
10547 // below) for next iterations of this loop, except for the last
10548 // iteration, which avoids an extra Pop at the end of the loop.
10549 if (!emit1(JSOp::Dup
)) {
10550 // [stack] ARRAY ARRAY
10555 if (!emitNumberOp(index
)) {
10556 // [stack] ARRAY? ARRAY INDEX
10560 if (!emit1(JSOp::GetElem
)) {
10561 // [stack] ARRAY? FUNC
10565 // This is guaranteed to run after super(), so we don't need TDZ checks.
10566 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
10567 // [stack] ARRAY? FUNC THIS
10571 // Callee is always internal function.
10572 if (!emitCall(JSOp::CallIgnoresRv
, 0)) {
10573 // [stack] ARRAY? RVAL
10577 if (!emit1(JSOp::Pop
)) {
10582 #ifdef ENABLE_DECORATORS
10583 // Decorators Proposal
10584 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-initializeinstanceelements
10585 // 4. For each element e of elements, do
10586 // 4.a. If elementRecord.[[Kind]] is field or accessor, then
10587 // 4.a.i. Perform ? InitializeFieldOrAccessor(O, elementRecord).
10590 // TODO: (See Bug 1817993) At the moment, we're applying the initialization
10591 // logic in two steps. The pre-decorator initialization code runs, stores
10592 // the initial value, and then we retrieve it here and apply the
10593 // initializers added by decorators. We should unify these two steps.
10594 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) {
10599 if (!emit1(JSOp::Dup
)) {
10600 // [stack] ARRAY ARRAY
10604 if (!emitAtomOp(JSOp::GetProp
,
10605 TaggedParserAtomIndex::WellKnown::length())) {
10606 // [stack] ARRAY LENGTH
10610 if (!emitNumberOp(static_cast<double>(numInitializers
))) {
10611 // [stack] ARRAY LENGTH INDEX
10615 InternalWhileEmitter
wh(this);
10616 // At this point, we have no context to determine offsets in the
10617 // code for this while statement. Ideally, it would correspond to
10618 // the field we're initializing.
10619 if (!wh
.emitCond()) {
10620 // [stack] ARRAY LENGTH INDEX
10624 if (!emit1(JSOp::Dup
)) {
10625 // [stack] ARRAY LENGTH INDEX INDEX
10629 if (!emitDupAt(2)) {
10630 // [stack] ARRAY LENGTH INDEX INDEX LENGTH
10634 if (!emit1(JSOp::Lt
)) {
10635 // [stack] ARRAY LENGTH INDEX BOOL
10639 if (!wh
.emitBody()) {
10640 // [stack] ARRAY LENGTH INDEX
10644 if (!emitDupAt(2)) {
10645 // [stack] ARRAY LENGTH INDEX ARRAY
10649 if (!emitDupAt(1)) {
10650 // [stack] ARRAY LENGTH INDEX ARRAY INDEX
10654 // Retrieve initializers for this field
10655 if (!emit1(JSOp::GetElem
)) {
10656 // [stack] ARRAY LENGTH INDEX INITIALIZERS
10660 // This is guaranteed to run after super(), so we don't need TDZ checks.
10661 if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) {
10662 // [stack] ARRAY LENGTH INDEX INITIALIZERS THIS
10666 if (!emit1(JSOp::Swap
)) {
10667 // [stack] ARRAY LENGTH INDEX THIS INITIALIZERS
10671 DecoratorEmitter
de(this);
10672 if (!de
.emitInitializeFieldOrAccessor()) {
10673 // [stack] ARRAY LENGTH INDEX
10677 if (!emit1(JSOp::Inc
)) {
10678 // [stack] ARRAY LENGTH INDEX
10682 if (!wh
.emitEnd()) {
10683 // [stack] ARRAY LENGTH INDEX
10687 if (!emitPopN(3)) {
10691 // 5. Return unused.
10697 bool BytecodeEmitter::emitInitializeStaticFields(ListNode
* classMembers
) {
10698 auto isStaticField
= [](ParseNode
* propdef
) {
10699 return HasInitializer(propdef
, true);
10702 std::count_if(classMembers
->contents().begin(),
10703 classMembers
->contents().end(), isStaticField
);
10705 if (numFields
== 0) {
10710 TaggedParserAtomIndex::WellKnown::dot_staticInitializers_())) {
10711 // [stack] CTOR ARRAY
10715 for (size_t fieldIndex
= 0; fieldIndex
< numFields
; fieldIndex
++) {
10716 bool hasNext
= fieldIndex
< numFields
- 1;
10718 // We Dup to keep the array around (it is consumed in the bytecode below)
10719 // for next iterations of this loop, except for the last iteration, which
10720 // avoids an extra Pop at the end of the loop.
10721 if (!emit1(JSOp::Dup
)) {
10722 // [stack] CTOR ARRAY ARRAY
10727 if (!emitNumberOp(fieldIndex
)) {
10728 // [stack] CTOR ARRAY? ARRAY INDEX
10732 if (!emit1(JSOp::GetElem
)) {
10733 // [stack] CTOR ARRAY? FUNC
10737 if (!emitDupAt(1 + hasNext
)) {
10738 // [stack] CTOR ARRAY? FUNC CTOR
10742 // Callee is always internal function.
10743 if (!emitCall(JSOp::CallIgnoresRv
, 0)) {
10744 // [stack] CTOR ARRAY? RVAL
10748 if (!emit1(JSOp::Pop
)) {
10749 // [stack] CTOR ARRAY?
10754 #ifdef ENABLE_DECORATORS
10755 // Decorators Proposal
10756 // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-initializeinstanceelements
10757 // 4. For each element e of elements, do
10758 // 4.a. If elementRecord.[[Kind]] is field or accessor, then
10759 // 4.a.i. Perform ? InitializeFieldOrAccessor(O, elementRecord).
10762 // TODO: (See Bug 1817993) At the moment, we're applying the initialization
10763 // logic in two steps. The pre-decorator initialization code runs, stores
10764 // the initial value, and then we retrieve it here and apply the
10765 // initializers added by decorators. We should unify these two steps.
10767 TaggedParserAtomIndex::WellKnown::dot_staticInitializers_())) {
10768 // [stack] CTOR ARRAY
10772 if (!emit1(JSOp::Dup
)) {
10773 // [stack] CTOR ARRAY ARRAY
10777 if (!emitAtomOp(JSOp::GetProp
, TaggedParserAtomIndex::WellKnown::length())) {
10778 // [stack] CTOR ARRAY LENGTH
10782 if (!emitNumberOp(static_cast<double>(numFields
))) {
10783 // [stack] CTOR ARRAY LENGTH INDEX
10787 InternalWhileEmitter
wh(this);
10788 // At this point, we have no context to determine offsets in the
10789 // code for this while statement. Ideally, it would correspond to
10790 // the field we're initializing.
10791 if (!wh
.emitCond()) {
10792 // [stack] CTOR ARRAY LENGTH INDEX
10796 if (!emit1(JSOp::Dup
)) {
10797 // [stack] CTOR ARRAY LENGTH INDEX INDEX
10801 if (!emitDupAt(2)) {
10802 // [stack] CTOR ARRAY LENGTH INDEX INDEX LENGTH
10806 if (!emit1(JSOp::Lt
)) {
10807 // [stack] CTOR ARRAY LENGTH INDEX BOOL
10811 if (!wh
.emitBody()) {
10812 // [stack] CTOR ARRAY LENGTH INDEX
10816 if (!emitDupAt(2)) {
10817 // [stack] CTOR ARRAY LENGTH INDEX ARRAY
10821 if (!emitDupAt(1)) {
10822 // [stack] CTOR ARRAY LENGTH INDEX ARRAY INDEX
10826 // Retrieve initializers for this field
10827 if (!emit1(JSOp::GetElem
)) {
10828 // [stack] CTOR ARRAY LENGTH INDEX INITIALIZERS
10832 if (!emitDupAt(4)) {
10833 // [stack] CTOR ARRAY LENGTH INDEX INITIALIZERS CTOR
10837 if (!emit1(JSOp::Swap
)) {
10838 // [stack] CTOR ARRAY LENGTH INDEX CTOR INITIALIZERS
10842 DecoratorEmitter
de(this);
10843 if (!de
.emitInitializeFieldOrAccessor()) {
10844 // [stack] CTOR ARRAY LENGTH INDEX
10848 if (!emit1(JSOp::Inc
)) {
10849 // [stack] CTOR ARRAY LENGTH INDEX
10853 if (!wh
.emitEnd()) {
10854 // [stack] CTOR ARRAY LENGTH INDEX
10858 if (!emitPopN(3)) {
10862 // 5. Return unused.
10865 // Overwrite |.staticInitializers| and |.staticFieldKeys| with undefined to
10866 // avoid keeping the arrays alive indefinitely.
10867 auto clearStaticFieldSlot
= [&](TaggedParserAtomIndex name
) {
10868 NameOpEmitter
noe(this, name
, NameOpEmitter::Kind::SimpleAssignment
);
10869 if (!noe
.prepareForRhs()) {
10870 // [stack] ENV? VAL?
10874 if (!emit1(JSOp::Undefined
)) {
10875 // [stack] ENV? VAL? UNDEFINED
10879 if (!noe
.emitAssignment()) {
10884 if (!emit1(JSOp::Pop
)) {
10892 if (!clearStaticFieldSlot(
10893 TaggedParserAtomIndex::WellKnown::dot_staticInitializers_())) {
10897 auto isStaticFieldWithComputedName
= [](ParseNode
* propdef
) {
10898 return propdef
->is
<ClassField
>() && propdef
->as
<ClassField
>().isStatic() &&
10899 propdef
->as
<ClassField
>().name().getKind() ==
10900 ParseNodeKind::ComputedName
;
10903 if (std::any_of(classMembers
->contents().begin(),
10904 classMembers
->contents().end(),
10905 isStaticFieldWithComputedName
)) {
10906 if (!clearStaticFieldSlot(
10907 TaggedParserAtomIndex::WellKnown::dot_staticFieldKeys_())) {
10915 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
10916 // the comment on emitSwitch.
10917 MOZ_NEVER_INLINE
bool BytecodeEmitter::emitObject(ListNode
* objNode
) {
10918 // Note: this method uses the ObjLiteralWriter and emits ObjLiteralStencil
10919 // objects into the GCThingList, which will evaluate them into real GC objects
10920 // or shapes during JSScript::fullyInitFromEmitter. Eventually we want
10921 // JSOp::Object to be a real opcode, but for now, performance constraints
10922 // limit us to evaluating object literals at the end of parse, when we're
10923 // allowed to allocate GC things.
10925 // There are four cases here, in descending order of preference:
10927 // 1. The list of property names is "normal" and constant (no computed
10928 // values, no integer indices), the values are all simple constants
10929 // (numbers, booleans, strings), *and* this occurs in a run-once
10930 // (singleton) context. In this case, we can emit ObjLiteral
10931 // instructions to build an object with values, and the object will be
10932 // attached to a JSOp::Object opcode, whose semantics are for the backend
10933 // to simply steal the object from the script.
10935 // 2. The list of property names is "normal" and constant as above, *and* this
10936 // occurs in a run-once (singleton) context, but some values are complex
10937 // (computed expressions, sub-objects, functions, etc.). In this case, we
10938 // can still use JSOp::Object (because singleton context), but the object
10939 // has |undefined| property values and InitProp ops are emitted to set the
10942 // 3. The list of property names is "normal" and constant as above, but this
10943 // occurs in a non-run-once (non-singleton) context. In this case, we can
10944 // use the ObjLiteral functionality to describe an *empty* object (all
10945 // values left undefined) with the right fields, which will become a
10946 // JSOp::NewObject opcode using the object's shape to speed up the creation
10947 // of the object each time it executes. The emitted bytecode still needs
10948 // InitProp ops to set the values in this case.
10950 // 4. Any other case. As a fallback, we use NewInit to create a new, empty
10951 // object (i.e., `{}`) and then emit bytecode to initialize its properties
10954 bool useObjLiteral
= false;
10955 bool useObjLiteralValues
= false;
10956 isPropertyListObjLiteralCompatible(objNode
, &useObjLiteralValues
,
10961 ObjectEmitter
oe(this);
10962 if (useObjLiteral
) {
10963 bool singleton
= checkSingletonContext() &&
10964 !objNode
->hasNonConstInitializer() && objNode
->head();
10971 useObjLiteralValues
= false;
10972 op
= JSOp::NewObject
;
10975 // Use an ObjLiteral op. This will record ObjLiteral insns in the
10976 // objLiteralWriter's buffer and add a fixup to the list of ObjLiteral
10977 // fixups so that at GC-publish time at the end of parse, the full object
10978 // (case 1 or 2) or shape (case 3) can be allocated and the bytecode can be
10979 // patched to refer to it.
10980 if (!emitPropertyListObjLiteral(objNode
, op
, useObjLiteralValues
)) {
10984 // Put the ObjectEmitter in the right state. This tells it that there will
10985 // already be an object on the stack as a result of the (eventual)
10986 // NewObject or Object op, and prepares it to emit values if needed.
10987 if (!oe
.emitObjectWithTemplateOnStack()) {
10991 if (!useObjLiteralValues
) {
10992 // Case 2 or 3 above: we still need to emit bytecode to fill in the
10993 // object's property values.
10994 if (!emitPropertyList(objNode
, oe
, ObjectLiteral
)) {
11000 // Case 4 above: no ObjLiteral use, just bytecode to build the object from
11002 if (!oe
.emitObject(objNode
->count())) {
11006 if (!emitPropertyList(objNode
, oe
, ObjectLiteral
)) {
11012 if (!oe
.emitEnd()) {
11020 bool BytecodeEmitter::emitArrayLiteral(ListNode
* array
) {
11021 // Emit JSOp::Object if the array consists entirely of primitive values and we
11022 // are in a singleton context.
11023 if (checkSingletonContext() && !array
->hasNonConstInitializer() &&
11024 !array
->empty() && isArrayObjLiteralCompatible(array
)) {
11025 return emitObjLiteralArray(array
);
11028 return emitArray(array
);
11031 bool BytecodeEmitter::emitArray(ListNode
* array
) {
11033 * Emit code for [a, b, c] that is equivalent to constructing a new
11034 * array and in source order evaluating each element value and adding
11035 * it to the array, without invoking latent setters. We use the
11036 * JSOp::NewInit and JSOp::InitElemArray bytecodes to ignore setters and
11037 * to avoid dup'ing and popping the array as each element is added, as
11038 * JSOp::SetElem/JSOp::SetProp would do.
11041 uint32_t nspread
= 0;
11042 for (ParseNode
* elem
: array
->contents()) {
11043 if (elem
->isKind(ParseNodeKind::Spread
)) {
11048 // Array literal's length is limited to NELEMENTS_LIMIT in parser.
11049 static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT
<= INT32_MAX
,
11050 "array literals' maximum length must not exceed limits "
11051 "required by BaselineCompiler::emit_NewArray, "
11052 "BaselineCompiler::emit_InitElemArray, "
11053 "and DoSetElemFallback's handling of JSOp::InitElemArray");
11055 uint32_t count
= array
->count();
11056 MOZ_ASSERT(count
>= nspread
);
11057 MOZ_ASSERT(count
<= NativeObject::MAX_DENSE_ELEMENTS_COUNT
,
11058 "the parser must throw an error if the array exceeds maximum "
11061 // For arrays with spread, this is a very pessimistic allocation, the
11062 // minimum possible final size.
11063 if (!emitUint32Operand(JSOp::NewArray
, count
- nspread
)) {
11068 uint32_t index
= 0;
11069 bool afterSpread
= false;
11070 for (ParseNode
* elem
: array
->contents()) {
11071 if (elem
->isKind(ParseNodeKind::Spread
)) {
11072 if (!afterSpread
) {
11073 afterSpread
= true;
11074 if (!emitNumberOp(index
)) {
11075 // [stack] ARRAY INDEX
11080 ParseNode
* expr
= elem
->as
<UnaryNode
>().kid();
11081 SelfHostedIter selfHostedIter
= getSelfHostedIterFor(expr
);
11083 if (!updateSourceCoordNotes(elem
->pn_pos
.begin
)) {
11086 if (!emitIterable(expr
, selfHostedIter
)) {
11087 // [stack] ARRAY INDEX ITERABLE
11090 if (!emitIterator(selfHostedIter
)) {
11091 // [stack] ARRAY INDEX NEXT ITER
11094 if (!emit2(JSOp::Pick
, 3)) {
11095 // [stack] INDEX NEXT ITER ARRAY
11098 if (!emit2(JSOp::Pick
, 3)) {
11099 // [stack] NEXT ITER ARRAY INDEX
11102 if (!emitSpread(selfHostedIter
)) {
11103 // [stack] ARRAY INDEX
11107 if (!updateSourceCoordNotesIfNonLiteral(elem
)) {
11110 if (elem
->isKind(ParseNodeKind::Elision
)) {
11111 if (!emit1(JSOp::Hole
)) {
11115 if (!emitTree(elem
, ValueUsage::WantValue
)) {
11116 // [stack] ARRAY INDEX? VALUE
11122 if (!emit1(JSOp::InitElemInc
)) {
11123 // [stack] ARRAY (INDEX+1)
11127 if (!emitUint32Operand(JSOp::InitElemArray
, index
)) {
11136 MOZ_ASSERT(index
== count
);
11138 if (!emit1(JSOp::Pop
)) {
11146 bool BytecodeEmitter::emitSpreadIntoArray(UnaryNode
* elem
) {
11147 MOZ_ASSERT(elem
->isKind(ParseNodeKind::Spread
));
11149 if (!updateSourceCoordNotes(elem
->pn_pos
.begin
)) {
11154 SelfHostedIter selfHostedIter
= getSelfHostedIterFor(elem
->kid());
11155 MOZ_ASSERT(selfHostedIter
== SelfHostedIter::Deny
||
11156 selfHostedIter
== SelfHostedIter::AllowContent
);
11158 if (!emitIterator(selfHostedIter
)) {
11159 // [stack] NEXT ITER
11163 if (!emitUint32Operand(JSOp::NewArray
, 0)) {
11164 // [stack] NEXT ITER ARRAY
11168 if (!emitNumberOp(0)) {
11169 // [stack] NEXT ITER ARRAY INDEX
11173 if (!emitSpread(selfHostedIter
)) {
11174 // [stack] ARRAY INDEX
11178 if (!emit1(JSOp::Pop
)) {
11185 #ifdef ENABLE_RECORD_TUPLE
11186 bool BytecodeEmitter::emitRecordLiteral(ListNode
* record
) {
11187 if (!emitUint32Operand(JSOp::InitRecord
, record
->count())) {
11192 for (ParseNode
* propdef
: record
->contents()) {
11193 if (propdef
->isKind(ParseNodeKind::Spread
)) {
11194 if (!emitTree(propdef
->as
<UnaryNode
>().kid())) {
11195 // [stack] RECORD SPREADEE
11198 if (!emit1(JSOp::AddRecordSpread
)) {
11203 BinaryNode
* prop
= &propdef
->as
<BinaryNode
>();
11205 ParseNode
* key
= prop
->left();
11206 ParseNode
* value
= prop
->right();
11208 switch (key
->getKind()) {
11209 case ParseNodeKind::ObjectPropertyName
:
11210 if (!emitStringOp(JSOp::String
, key
->as
<NameNode
>().atom())) {
11214 case ParseNodeKind::ComputedName
:
11215 if (!emitTree(key
->as
<UnaryNode
>().kid())) {
11220 MOZ_ASSERT(key
->isKind(ParseNodeKind::StringExpr
) ||
11221 key
->isKind(ParseNodeKind::NumberExpr
) ||
11222 key
->isKind(ParseNodeKind::BigIntExpr
));
11223 if (!emitTree(key
)) {
11228 // [stack] RECORD KEY
11230 if (!emitTree(value
)) {
11231 // [stack] RECORD KEY VALUE
11235 if (!emit1(JSOp::AddRecordProperty
)) {
11242 if (!emit1(JSOp::FinishRecord
)) {
11250 bool BytecodeEmitter::emitTupleLiteral(ListNode
* tuple
) {
11251 if (!emitUint32Operand(JSOp::InitTuple
, tuple
->count())) {
11256 for (ParseNode
* elt
: tuple
->contents()) {
11257 if (elt
->isKind(ParseNodeKind::Spread
)) {
11258 ParseNode
* expr
= elt
->as
<UnaryNode
>().kid();
11259 auto selfHostedIter
= getSelfHostedIterFor(expr
);
11261 if (!emitIterable(expr
, selfHostedIter
)) {
11262 // [stack] TUPLE ITERABLE
11265 if (!emitIterator(selfHostedIter
)) {
11266 // [stack] TUPLE NEXT ITER
11269 if (!emit2(JSOp::Pick
, 2)) {
11270 // [stack] NEXT ITER TUPLE
11273 if (!emitSpread(selfHostedIter
, /* spreadeeStackItems = */ 1,
11274 JSOp::AddTupleElement
)) {
11279 // Update location to throw errors about non-primitive elements
11280 // in the correct position.
11281 if (!updateSourceCoordNotesIfNonLiteral(elt
)) {
11285 if (!emitTree(elt
)) {
11286 // [stack] TUPLE VALUE
11290 if (!emit1(JSOp::AddTupleElement
)) {
11297 if (!emit1(JSOp::FinishTuple
)) {
11306 static inline JSOp
UnaryOpParseNodeKindToJSOp(ParseNodeKind pnk
) {
11308 case ParseNodeKind::ThrowStmt
:
11309 return JSOp::Throw
;
11310 case ParseNodeKind::VoidExpr
:
11312 case ParseNodeKind::NotExpr
:
11314 case ParseNodeKind::BitNotExpr
:
11315 return JSOp::BitNot
;
11316 case ParseNodeKind::PosExpr
:
11318 case ParseNodeKind::NegExpr
:
11321 MOZ_CRASH("unexpected unary op");
11325 bool BytecodeEmitter::emitUnary(UnaryNode
* unaryNode
) {
11326 if (!updateSourceCoordNotes(unaryNode
->pn_pos
.begin
)) {
11330 JSOp op
= UnaryOpParseNodeKindToJSOp(unaryNode
->getKind());
11331 ValueUsage valueUsage
=
11332 op
== JSOp::Void
? ValueUsage::IgnoreValue
: ValueUsage::WantValue
;
11333 if (!emitTree(unaryNode
->kid(), valueUsage
)) {
11339 bool BytecodeEmitter::emitTypeof(UnaryNode
* typeofNode
, JSOp op
) {
11340 MOZ_ASSERT(op
== JSOp::Typeof
|| op
== JSOp::TypeofExpr
);
11342 if (!updateSourceCoordNotes(typeofNode
->pn_pos
.begin
)) {
11346 if (!emitTree(typeofNode
->kid())) {
11353 bool BytecodeEmitter::emitFunctionFormalParameters(ParamsBodyNode
* paramsBody
) {
11354 FunctionBox
* funbox
= sc
->asFunctionBox();
11356 bool hasRest
= funbox
->hasRest();
11358 FunctionParamsEmitter
fpe(this, funbox
);
11359 for (ParseNode
* arg
: paramsBody
->parameters()) {
11360 ParseNode
* bindingElement
= arg
;
11361 ParseNode
* initializer
= nullptr;
11362 if (arg
->isKind(ParseNodeKind::AssignExpr
)) {
11363 bindingElement
= arg
->as
<BinaryNode
>().left();
11364 initializer
= arg
->as
<BinaryNode
>().right();
11366 bool hasInitializer
= !!initializer
;
11368 hasRest
&& arg
->pn_next
== *std::end(paramsBody
->parameters());
11369 bool isDestructuring
= !bindingElement
->isKind(ParseNodeKind::Name
);
11371 // Left-hand sides are either simple names or destructuring patterns.
11372 MOZ_ASSERT(bindingElement
->isKind(ParseNodeKind::Name
) ||
11373 bindingElement
->isKind(ParseNodeKind::ArrayExpr
) ||
11374 bindingElement
->isKind(ParseNodeKind::ObjectExpr
));
11376 auto emitDefaultInitializer
= [this, &initializer
, &bindingElement
]() {
11379 if (!this->emitInitializer(initializer
, bindingElement
)) {
11386 auto emitDestructuring
= [this, &bindingElement
]() {
11389 if (!this->emitDestructuringOps(&bindingElement
->as
<ListNode
>(),
11390 DestructuringFlavor::Declaration
)) {
11399 if (isDestructuring
) {
11400 if (!fpe
.prepareForDestructuringRest()) {
11404 if (!emitDestructuring()) {
11408 if (!fpe
.emitDestructuringRestEnd()) {
11413 auto paramName
= bindingElement
->as
<NameNode
>().name();
11414 if (!fpe
.emitRest(paramName
)) {
11423 if (isDestructuring
) {
11424 if (hasInitializer
) {
11425 if (!fpe
.prepareForDestructuringDefaultInitializer()) {
11429 if (!emitDefaultInitializer()) {
11433 if (!fpe
.prepareForDestructuringDefault()) {
11437 if (!emitDestructuring()) {
11441 if (!fpe
.emitDestructuringDefaultEnd()) {
11446 if (!fpe
.prepareForDestructuring()) {
11450 if (!emitDestructuring()) {
11454 if (!fpe
.emitDestructuringEnd()) {
11463 if (hasInitializer
) {
11464 if (!fpe
.prepareForDefault()) {
11468 if (!emitDefaultInitializer()) {
11472 auto paramName
= bindingElement
->as
<NameNode
>().name();
11473 if (!fpe
.emitDefaultEnd(paramName
)) {
11481 auto paramName
= bindingElement
->as
<NameNode
>().name();
11482 if (!fpe
.emitSimple(paramName
)) {
11491 bool BytecodeEmitter::emitInitializeFunctionSpecialNames() {
11492 FunctionBox
* funbox
= sc
->asFunctionBox();
11496 auto emitInitializeFunctionSpecialName
=
11497 [](BytecodeEmitter
* bce
, TaggedParserAtomIndex name
, JSOp op
) {
11498 // A special name must be slotful, either on the frame or on the
11499 // call environment.
11500 MOZ_ASSERT(bce
->lookupName(name
).hasKnownSlot());
11502 NameOpEmitter
noe(bce
, name
, NameOpEmitter::Kind::Initialize
);
11503 if (!noe
.prepareForRhs()) {
11507 if (!bce
->emit1(op
)) {
11508 // [stack] THIS/ARGUMENTS/NEW.TARGET
11511 if (!noe
.emitAssignment()) {
11512 // [stack] THIS/ARGUMENTS/NEW.TARGET
11515 if (!bce
->emit1(JSOp::Pop
)) {
11523 // Do nothing if the function doesn't have an arguments binding.
11524 if (funbox
->needsArgsObj()) {
11525 // Self-hosted code should use the more efficient ArgumentsLength and
11526 // GetArgument intrinsics instead of `arguments`.
11527 MOZ_ASSERT(emitterMode
!= BytecodeEmitter::SelfHosting
);
11528 if (!emitInitializeFunctionSpecialName(
11529 this, TaggedParserAtomIndex::WellKnown::arguments(),
11530 JSOp::Arguments
)) {
11536 // Do nothing if the function doesn't have a this-binding (this
11537 // happens for instance if it doesn't use this/eval or if it's an
11538 // arrow function).
11539 if (funbox
->functionHasThisBinding()) {
11540 if (!emitInitializeFunctionSpecialName(
11541 this, TaggedParserAtomIndex::WellKnown::dot_this_(),
11542 JSOp::FunctionThis
)) {
11547 // Do nothing if the function doesn't have a new.target-binding (this happens
11548 // for instance if it doesn't use new.target/eval or if it's an arrow
11550 if (funbox
->functionHasNewTargetBinding()) {
11551 if (!emitInitializeFunctionSpecialName(
11552 this, TaggedParserAtomIndex::WellKnown::dot_newTarget_(),
11553 JSOp::NewTarget
)) {
11558 // Do nothing if the function doesn't implicitly return a promise result.
11559 if (funbox
->needsPromiseResult()) {
11560 if (!emitInitializeFunctionSpecialName(
11561 this, TaggedParserAtomIndex::WellKnown::dot_generator_(),
11562 JSOp::Generator
)) {
11570 bool BytecodeEmitter::emitLexicalInitialization(NameNode
* name
) {
11571 return emitLexicalInitialization(name
->name());
11574 bool BytecodeEmitter::emitLexicalInitialization(TaggedParserAtomIndex name
) {
11575 NameOpEmitter
noe(this, name
, NameOpEmitter::Kind::Initialize
);
11576 if (!noe
.prepareForRhs()) {
11580 // The caller has pushed the RHS to the top of the stack. Assert that the
11581 // binding can be initialized without a binding object on the stack, and that
11582 // no JSOp::BindName or JSOp::BindGName ops were emitted.
11583 MOZ_ASSERT(noe
.loc().isLexical() || noe
.loc().isSynthetic() ||
11584 noe
.loc().isPrivateMethod());
11585 MOZ_ASSERT(!noe
.emittedBindOp());
11587 if (!noe
.emitAssignment()) {
11594 static MOZ_ALWAYS_INLINE ParseNode
* FindConstructor(ListNode
* classMethods
) {
11595 for (ParseNode
* classElement
: classMethods
->contents()) {
11596 ParseNode
* unwrappedElement
= classElement
;
11597 if (unwrappedElement
->is
<LexicalScopeNode
>()) {
11598 unwrappedElement
= unwrappedElement
->as
<LexicalScopeNode
>().scopeBody();
11600 if (unwrappedElement
->is
<ClassMethod
>()) {
11601 ClassMethod
& method
= unwrappedElement
->as
<ClassMethod
>();
11602 ParseNode
& methodName
= method
.name();
11603 if (!method
.isStatic() &&
11604 (methodName
.isKind(ParseNodeKind::ObjectPropertyName
) ||
11605 methodName
.isKind(ParseNodeKind::StringExpr
)) &&
11606 methodName
.as
<NameNode
>().atom() ==
11607 TaggedParserAtomIndex::WellKnown::constructor()) {
11608 return classElement
;
11615 bool BytecodeEmitter::emitNewPrivateName(TaggedParserAtomIndex bindingName
,
11616 TaggedParserAtomIndex symbolName
) {
11617 if (!emitAtomOp(JSOp::NewPrivateName
, symbolName
)) {
11618 // [stack] HERITAGE PRIVATENAME
11622 // Add a binding for #name => privatename
11623 if (!emitLexicalInitialization(bindingName
)) {
11624 // [stack] HERITAGE PRIVATENAME
11628 // Pop Private name off the stack.
11629 if (!emit1(JSOp::Pop
)) {
11630 // [stack] HERITAGE
11637 bool BytecodeEmitter::emitNewPrivateNames(
11638 TaggedParserAtomIndex privateBrandName
, ListNode
* classMembers
) {
11639 bool hasPrivateBrand
= false;
11641 for (ParseNode
* classElement
: classMembers
->contents()) {
11642 ParseNode
* elementName
;
11643 if (classElement
->is
<ClassMethod
>()) {
11644 elementName
= &classElement
->as
<ClassMethod
>().name();
11645 } else if (classElement
->is
<ClassField
>()) {
11646 elementName
= &classElement
->as
<ClassField
>().name();
11651 if (!elementName
->isKind(ParseNodeKind::PrivateName
)) {
11655 // Non-static private methods' private names are optimized away.
11656 bool isOptimized
= false;
11657 if (classElement
->is
<ClassMethod
>() &&
11658 !classElement
->as
<ClassMethod
>().isStatic()) {
11659 hasPrivateBrand
= true;
11660 if (classElement
->as
<ClassMethod
>().accessorType() ==
11661 AccessorType::None
) {
11662 isOptimized
= true;
11666 if (!isOptimized
) {
11667 auto privateName
= elementName
->as
<NameNode
>().name();
11668 if (!emitNewPrivateName(privateName
, privateName
)) {
11674 if (hasPrivateBrand
) {
11675 // We don't make a private name for every optimized method, but we need one
11676 // private name per class, the `.privateBrand`.
11677 if (!emitNewPrivateName(
11678 TaggedParserAtomIndex::WellKnown::dot_privateBrand_(),
11679 privateBrandName
)) {
11686 // This follows ES6 14.5.14 (ClassDefinitionEvaluation) and ES6 14.5.15
11687 // (BindingClassDeclarationEvaluation).
11688 bool BytecodeEmitter::emitClass(
11689 ClassNode
* classNode
,
11690 ClassNameKind nameKind
/* = ClassNameKind::BindingName */,
11691 TaggedParserAtomIndex
11692 nameForAnonymousClass
/* = TaggedParserAtomIndex::null() */) {
11693 MOZ_ASSERT((nameKind
== ClassNameKind::InferredName
) ==
11694 bool(nameForAnonymousClass
));
11696 ParseNode
* heritageExpression
= classNode
->heritage();
11697 ListNode
* classMembers
= classNode
->memberList();
11698 ParseNode
* constructor
= FindConstructor(classMembers
);
11700 // If |nameKind != ClassNameKind::ComputedName|
11705 ClassEmitter
ce(this);
11706 TaggedParserAtomIndex innerName
;
11707 ClassEmitter::Kind kind
= ClassEmitter::Kind::Expression
;
11708 if (ClassNames
* names
= classNode
->names()) {
11709 MOZ_ASSERT(nameKind
== ClassNameKind::BindingName
);
11710 innerName
= names
->innerBinding()->name();
11711 MOZ_ASSERT(innerName
);
11713 if (names
->outerBinding()) {
11714 MOZ_ASSERT(names
->outerBinding()->name());
11715 MOZ_ASSERT(names
->outerBinding()->name() == innerName
);
11716 kind
= ClassEmitter::Kind::Declaration
;
11720 if (LexicalScopeNode
* scopeBindings
= classNode
->scopeBindings()) {
11721 if (!ce
.emitScope(scopeBindings
->scopeBindings())) {
11727 bool isDerived
= !!heritageExpression
;
11729 if (!updateSourceCoordNotes(classNode
->pn_pos
.begin
)) {
11732 if (!markStepBreakpoint()) {
11735 if (!emitTree(heritageExpression
)) {
11736 // [stack] HERITAGE
11741 // The class body scope holds any private names. Those mustn't be visible in
11742 // the heritage expression and hence the scope must be emitted after the
11743 // heritage expression.
11744 if (ClassBodyScopeNode
* bodyScopeBindings
= classNode
->bodyScopeBindings()) {
11745 if (!ce
.emitBodyScope(bodyScopeBindings
->scopeBindings())) {
11746 // [stack] HERITAGE
11750 // The spec does not say anything about private brands being symbols. It's
11751 // an implementation detail. So we can give the special private brand
11752 // symbol any description we want and users won't normally see it. For
11753 // debugging, use the class name.
11754 auto privateBrandName
= innerName
;
11756 privateBrandName
= nameForAnonymousClass
11757 ? nameForAnonymousClass
11758 : TaggedParserAtomIndex::WellKnown::anonymous();
11760 if (!emitNewPrivateNames(privateBrandName
, classMembers
)) {
11765 bool hasNameOnStack
= nameKind
== ClassNameKind::ComputedName
;
11767 if (!ce
.emitDerivedClass(innerName
, nameForAnonymousClass
,
11769 // [stack] HERITAGE HOMEOBJ
11773 if (!ce
.emitClass(innerName
, nameForAnonymousClass
, hasNameOnStack
)) {
11779 // Stack currently has HOMEOBJ followed by optional HERITAGE. When HERITAGE
11780 // is not used, an implicit value of %FunctionPrototype% is implied.
11782 // See |Parser::classMember(...)| for the reason why |.initializers| is
11783 // created within its own scope.
11784 Maybe
<LexicalScopeEmitter
> lse
;
11785 FunctionNode
* ctor
;
11786 if (constructor
->is
<LexicalScopeNode
>()) {
11787 LexicalScopeNode
* constructorScope
= &constructor
->as
<LexicalScopeNode
>();
11789 // The constructor scope should only contain the |.initializers| binding.
11790 MOZ_ASSERT(!constructorScope
->isEmptyScope());
11791 MOZ_ASSERT(constructorScope
->scopeBindings()->length
== 1);
11792 MOZ_ASSERT(GetScopeDataTrailingNames(constructorScope
->scopeBindings())[0]
11794 TaggedParserAtomIndex::WellKnown::dot_initializers_());
11796 auto needsInitializer
= [](ParseNode
* propdef
) {
11797 return NeedsFieldInitializer(propdef
, false) ||
11798 NeedsAccessorInitializer(propdef
, false);
11801 // As an optimization omit the |.initializers| binding when no instance
11802 // fields or private methods are present.
11803 bool needsInitializers
=
11804 std::any_of(classMembers
->contents().begin(),
11805 classMembers
->contents().end(), needsInitializer
);
11806 if (needsInitializers
) {
11808 if (!lse
->emitScope(ScopeKind::Lexical
,
11809 constructorScope
->scopeBindings())) {
11813 // Any class with field initializers will have a constructor
11814 if (!emitCreateMemberInitializers(ce
, classMembers
,
11815 FieldPlacement::Instance
11816 #ifdef ENABLE_DECORATORS
11825 ctor
= &constructorScope
->scopeBody()->as
<ClassMethod
>().method();
11827 // The |.initializers| binding is never emitted when in self-hosting mode.
11828 MOZ_ASSERT(emitterMode
== BytecodeEmitter::SelfHosting
);
11829 ctor
= &constructor
->as
<ClassMethod
>().method();
11832 bool needsHomeObject
= ctor
->funbox()->needsHomeObject();
11833 // HERITAGE is consumed inside emitFunction.
11834 if (nameKind
== ClassNameKind::InferredName
) {
11835 if (!setFunName(ctor
->funbox(), nameForAnonymousClass
)) {
11839 if (!emitFunction(ctor
, isDerived
)) {
11840 // [stack] HOMEOBJ CTOR
11843 if (lse
.isSome()) {
11844 if (!lse
->emitEnd()) {
11849 if (!ce
.emitInitConstructor(needsHomeObject
)) {
11850 // [stack] CTOR HOMEOBJ
11854 if (!emitCreateFieldKeys(classMembers
, FieldPlacement::Instance
)) {
11858 if (!emitCreateMemberInitializers(ce
, classMembers
, FieldPlacement::Static
11859 #ifdef ENABLE_DECORATORS
11867 if (!emitCreateFieldKeys(classMembers
, FieldPlacement::Static
)) {
11871 if (!emitPropertyList(classMembers
, ce
, ClassBody
)) {
11872 // [stack] CTOR HOMEOBJ
11876 if (!ce
.emitBinding()) {
11881 if (!emitInitializeStaticFields(classMembers
)) {
11886 #if ENABLE_DECORATORS
11887 if (!ce
.prepareForDecorators()) {
11891 if (classNode
->decorators() != nullptr) {
11892 DecoratorEmitter
de(this);
11893 NameNode
* className
=
11894 classNode
->names() ? classNode
->names()->innerBinding() : nullptr;
11895 if (!de
.emitApplyDecoratorsToClassDefinition(className
,
11896 classNode
->decorators())) {
11903 if (!ce
.emitEnd(kind
)) {
11904 // [stack] # class declaration
11906 // [stack] # class expression
11914 bool BytecodeEmitter::emitExportDefault(BinaryNode
* exportNode
) {
11915 MOZ_ASSERT(exportNode
->isKind(ParseNodeKind::ExportDefaultStmt
));
11917 ParseNode
* valueNode
= exportNode
->left();
11918 if (valueNode
->isDirectRHSAnonFunction()) {
11919 MOZ_ASSERT(exportNode
->right());
11921 if (!emitAnonymousFunctionWithName(
11922 valueNode
, TaggedParserAtomIndex::WellKnown::default_())) {
11926 if (!emitTree(valueNode
)) {
11931 if (ParseNode
* binding
= exportNode
->right()) {
11932 if (!emitLexicalInitialization(&binding
->as
<NameNode
>())) {
11936 if (!emit1(JSOp::Pop
)) {
11944 bool BytecodeEmitter::emitTree(
11945 ParseNode
* pn
, ValueUsage valueUsage
/* = ValueUsage::WantValue */,
11946 EmitLineNumberNote emitLineNote
/* = EMIT_LINENOTE */) {
11947 AutoCheckRecursionLimit
recursion(fc
);
11948 if (!recursion
.check(fc
)) {
11952 /* Emit notes to tell the current bytecode's source line number.
11953 However, a couple trees require special treatment; see the
11954 relevant emitter functions for details. */
11955 if (emitLineNote
== EMIT_LINENOTE
&&
11956 !ParseNodeRequiresSpecialLineNumberNotes(pn
)) {
11957 if (!updateLineNumberNotes(pn
->pn_pos
.begin
)) {
11962 switch (pn
->getKind()) {
11963 case ParseNodeKind::Function
:
11964 if (!emitFunction(&pn
->as
<FunctionNode
>())) {
11969 case ParseNodeKind::ParamsBody
:
11970 MOZ_ASSERT_UNREACHABLE(
11971 "ParamsBody should be handled in emitFunctionScript.");
11974 case ParseNodeKind::IfStmt
:
11975 if (!emitIf(&pn
->as
<TernaryNode
>())) {
11980 case ParseNodeKind::SwitchStmt
:
11981 if (!emitSwitch(&pn
->as
<SwitchStatement
>())) {
11986 case ParseNodeKind::WhileStmt
:
11987 if (!emitWhile(&pn
->as
<BinaryNode
>())) {
11992 case ParseNodeKind::DoWhileStmt
:
11993 if (!emitDo(&pn
->as
<BinaryNode
>())) {
11998 case ParseNodeKind::ForStmt
:
11999 if (!emitFor(&pn
->as
<ForNode
>())) {
12004 case ParseNodeKind::BreakStmt
:
12005 // Ensure that the column of the 'break' is set properly.
12006 if (!updateSourceCoordNotes(pn
->pn_pos
.begin
)) {
12009 if (!markStepBreakpoint()) {
12013 if (!emitBreak(pn
->as
<BreakStatement
>().label())) {
12018 case ParseNodeKind::ContinueStmt
:
12019 // Ensure that the column of the 'continue' is set properly.
12020 if (!updateSourceCoordNotes(pn
->pn_pos
.begin
)) {
12023 if (!markStepBreakpoint()) {
12027 if (!emitContinue(pn
->as
<ContinueStatement
>().label())) {
12032 case ParseNodeKind::WithStmt
:
12033 if (!emitWith(&pn
->as
<BinaryNode
>())) {
12038 case ParseNodeKind::TryStmt
:
12039 if (!emitTry(&pn
->as
<TryNode
>())) {
12044 case ParseNodeKind::Catch
:
12045 if (!emitCatch(&pn
->as
<BinaryNode
>())) {
12050 case ParseNodeKind::VarStmt
:
12051 if (!emitDeclarationList(&pn
->as
<ListNode
>())) {
12056 case ParseNodeKind::ReturnStmt
:
12057 if (!emitReturn(&pn
->as
<UnaryNode
>())) {
12062 case ParseNodeKind::YieldStarExpr
:
12063 if (!emitYieldStar(pn
->as
<UnaryNode
>().kid())) {
12068 case ParseNodeKind::Generator
:
12069 if (!emit1(JSOp::Generator
)) {
12074 case ParseNodeKind::InitialYield
:
12075 if (!emitInitialYield(&pn
->as
<UnaryNode
>())) {
12080 case ParseNodeKind::YieldExpr
:
12081 if (!emitYield(&pn
->as
<UnaryNode
>())) {
12086 case ParseNodeKind::AwaitExpr
:
12087 if (!emitAwaitInInnermostScope(&pn
->as
<UnaryNode
>())) {
12092 case ParseNodeKind::StatementList
:
12093 if (!emitStatementList(&pn
->as
<ListNode
>())) {
12098 case ParseNodeKind::EmptyStmt
:
12101 case ParseNodeKind::ExpressionStmt
:
12102 if (!emitExpressionStatement(&pn
->as
<UnaryNode
>())) {
12107 case ParseNodeKind::LabelStmt
:
12108 if (!emitLabeledStatement(&pn
->as
<LabeledStatement
>())) {
12113 case ParseNodeKind::CommaExpr
:
12114 if (!emitSequenceExpr(&pn
->as
<ListNode
>(), valueUsage
)) {
12119 case ParseNodeKind::InitExpr
:
12120 case ParseNodeKind::AssignExpr
:
12121 case ParseNodeKind::AddAssignExpr
:
12122 case ParseNodeKind::SubAssignExpr
:
12123 case ParseNodeKind::BitOrAssignExpr
:
12124 case ParseNodeKind::BitXorAssignExpr
:
12125 case ParseNodeKind::BitAndAssignExpr
:
12126 case ParseNodeKind::LshAssignExpr
:
12127 case ParseNodeKind::RshAssignExpr
:
12128 case ParseNodeKind::UrshAssignExpr
:
12129 case ParseNodeKind::MulAssignExpr
:
12130 case ParseNodeKind::DivAssignExpr
:
12131 case ParseNodeKind::ModAssignExpr
:
12132 case ParseNodeKind::PowAssignExpr
: {
12133 BinaryNode
* assignNode
= &pn
->as
<BinaryNode
>();
12134 if (!emitAssignmentOrInit(assignNode
->getKind(), assignNode
->left(),
12135 assignNode
->right())) {
12141 case ParseNodeKind::CoalesceAssignExpr
:
12142 case ParseNodeKind::OrAssignExpr
:
12143 case ParseNodeKind::AndAssignExpr
:
12144 if (!emitShortCircuitAssignment(&pn
->as
<AssignmentNode
>())) {
12149 case ParseNodeKind::ConditionalExpr
:
12150 if (!emitConditionalExpression(pn
->as
<ConditionalExpression
>(),
12156 case ParseNodeKind::OrExpr
:
12157 case ParseNodeKind::CoalesceExpr
:
12158 case ParseNodeKind::AndExpr
:
12159 if (!emitShortCircuit(&pn
->as
<ListNode
>(), valueUsage
)) {
12164 case ParseNodeKind::AddExpr
:
12165 case ParseNodeKind::SubExpr
:
12166 case ParseNodeKind::BitOrExpr
:
12167 case ParseNodeKind::BitXorExpr
:
12168 case ParseNodeKind::BitAndExpr
:
12169 case ParseNodeKind::StrictEqExpr
:
12170 case ParseNodeKind::EqExpr
:
12171 case ParseNodeKind::StrictNeExpr
:
12172 case ParseNodeKind::NeExpr
:
12173 case ParseNodeKind::LtExpr
:
12174 case ParseNodeKind::LeExpr
:
12175 case ParseNodeKind::GtExpr
:
12176 case ParseNodeKind::GeExpr
:
12177 case ParseNodeKind::InExpr
:
12178 case ParseNodeKind::InstanceOfExpr
:
12179 case ParseNodeKind::LshExpr
:
12180 case ParseNodeKind::RshExpr
:
12181 case ParseNodeKind::UrshExpr
:
12182 case ParseNodeKind::MulExpr
:
12183 case ParseNodeKind::DivExpr
:
12184 case ParseNodeKind::ModExpr
:
12185 if (!emitLeftAssociative(&pn
->as
<ListNode
>())) {
12190 case ParseNodeKind::PrivateInExpr
:
12191 if (!emitPrivateInExpr(&pn
->as
<ListNode
>())) {
12196 case ParseNodeKind::PowExpr
:
12197 if (!emitRightAssociative(&pn
->as
<ListNode
>())) {
12202 case ParseNodeKind::TypeOfNameExpr
:
12203 if (!emitTypeof(&pn
->as
<UnaryNode
>(), JSOp::Typeof
)) {
12208 case ParseNodeKind::TypeOfExpr
:
12209 if (!emitTypeof(&pn
->as
<UnaryNode
>(), JSOp::TypeofExpr
)) {
12214 case ParseNodeKind::ThrowStmt
:
12215 if (!updateSourceCoordNotes(pn
->pn_pos
.begin
)) {
12218 if (!markStepBreakpoint()) {
12222 case ParseNodeKind::VoidExpr
:
12223 case ParseNodeKind::NotExpr
:
12224 case ParseNodeKind::BitNotExpr
:
12225 case ParseNodeKind::PosExpr
:
12226 case ParseNodeKind::NegExpr
:
12227 if (!emitUnary(&pn
->as
<UnaryNode
>())) {
12232 case ParseNodeKind::PreIncrementExpr
:
12233 case ParseNodeKind::PreDecrementExpr
:
12234 case ParseNodeKind::PostIncrementExpr
:
12235 case ParseNodeKind::PostDecrementExpr
:
12236 if (!emitIncOrDec(&pn
->as
<UnaryNode
>(), valueUsage
)) {
12241 case ParseNodeKind::DeleteNameExpr
:
12242 if (!emitDeleteName(&pn
->as
<UnaryNode
>())) {
12247 case ParseNodeKind::DeletePropExpr
:
12248 if (!emitDeleteProperty(&pn
->as
<UnaryNode
>())) {
12253 case ParseNodeKind::DeleteElemExpr
:
12254 if (!emitDeleteElement(&pn
->as
<UnaryNode
>())) {
12259 case ParseNodeKind::DeleteExpr
:
12260 if (!emitDeleteExpression(&pn
->as
<UnaryNode
>())) {
12265 case ParseNodeKind::DeleteOptionalChainExpr
:
12266 if (!emitDeleteOptionalChain(&pn
->as
<UnaryNode
>())) {
12271 case ParseNodeKind::OptionalChain
:
12272 if (!emitOptionalChain(&pn
->as
<UnaryNode
>(), valueUsage
)) {
12277 case ParseNodeKind::DotExpr
: {
12278 PropertyAccess
* prop
= &pn
->as
<PropertyAccess
>();
12279 bool isSuper
= prop
->isSuper();
12280 PropOpEmitter
poe(this, PropOpEmitter::Kind::Get
,
12281 isSuper
? PropOpEmitter::ObjKind::Super
12282 : PropOpEmitter::ObjKind::Other
);
12283 if (!poe
.prepareForObj()) {
12287 UnaryNode
* base
= &prop
->expression().as
<UnaryNode
>();
12288 if (!emitGetThisForSuperBase(base
)) {
12293 if (!emitPropLHS(prop
)) {
12298 if (!poe
.emitGet(prop
->key().atom())) {
12305 case ParseNodeKind::ElemExpr
: {
12306 PropertyByValue
* elem
= &pn
->as
<PropertyByValue
>();
12307 bool isSuper
= elem
->isSuper();
12308 MOZ_ASSERT(!elem
->key().isKind(ParseNodeKind::PrivateName
));
12309 ElemOpEmitter
eoe(this, ElemOpEmitter::Kind::Get
,
12310 isSuper
? ElemOpEmitter::ObjKind::Super
12311 : ElemOpEmitter::ObjKind::Other
);
12312 if (!emitElemObjAndKey(elem
, isSuper
, eoe
)) {
12313 // [stack] # if Super
12314 // [stack] THIS KEY
12315 // [stack] # otherwise
12319 if (!eoe
.emitGet()) {
12327 case ParseNodeKind::PrivateMemberExpr
: {
12328 PrivateMemberAccess
* privateExpr
= &pn
->as
<PrivateMemberAccess
>();
12329 PrivateOpEmitter
xoe(this, PrivateOpEmitter::Kind::Get
,
12330 privateExpr
->privateName().name());
12331 if (!emitTree(&privateExpr
->expression())) {
12335 if (!xoe
.emitReference()) {
12336 // [stack] OBJ NAME
12339 if (!xoe
.emitGet()) {
12347 case ParseNodeKind::NewExpr
:
12348 case ParseNodeKind::TaggedTemplateExpr
:
12349 case ParseNodeKind::CallExpr
:
12350 case ParseNodeKind::SuperCallExpr
:
12351 if (!emitCallOrNew(&pn
->as
<CallNode
>(), valueUsage
)) {
12356 case ParseNodeKind::LexicalScope
:
12357 if (!emitLexicalScope(&pn
->as
<LexicalScopeNode
>())) {
12362 case ParseNodeKind::ConstDecl
:
12363 case ParseNodeKind::LetDecl
:
12364 if (!emitDeclarationList(&pn
->as
<ListNode
>())) {
12369 case ParseNodeKind::ImportDecl
:
12370 MOZ_ASSERT(sc
->isModuleContext());
12373 case ParseNodeKind::ExportStmt
: {
12374 MOZ_ASSERT(sc
->isModuleContext());
12375 UnaryNode
* node
= &pn
->as
<UnaryNode
>();
12376 ParseNode
* decl
= node
->kid();
12377 if (decl
->getKind() != ParseNodeKind::ExportSpecList
) {
12378 if (!emitTree(decl
)) {
12385 case ParseNodeKind::ExportDefaultStmt
:
12386 MOZ_ASSERT(sc
->isModuleContext());
12387 if (!emitExportDefault(&pn
->as
<BinaryNode
>())) {
12392 case ParseNodeKind::ExportFromStmt
:
12393 MOZ_ASSERT(sc
->isModuleContext());
12396 case ParseNodeKind::CallSiteObj
:
12397 if (!emitCallSiteObject(&pn
->as
<CallSiteNode
>())) {
12402 case ParseNodeKind::ArrayExpr
:
12403 if (!emitArrayLiteral(&pn
->as
<ListNode
>())) {
12408 case ParseNodeKind::ObjectExpr
:
12409 if (!emitObject(&pn
->as
<ListNode
>())) {
12414 case ParseNodeKind::Name
:
12415 if (!emitGetName(&pn
->as
<NameNode
>())) {
12420 case ParseNodeKind::PrivateName
:
12421 if (!emitGetPrivateName(&pn
->as
<NameNode
>())) {
12426 case ParseNodeKind::TemplateStringListExpr
:
12427 if (!emitTemplateString(&pn
->as
<ListNode
>())) {
12432 case ParseNodeKind::TemplateStringExpr
:
12433 case ParseNodeKind::StringExpr
:
12434 if (!emitStringOp(JSOp::String
, pn
->as
<NameNode
>().atom())) {
12439 case ParseNodeKind::NumberExpr
:
12440 if (!emitNumberOp(pn
->as
<NumericLiteral
>().value())) {
12445 case ParseNodeKind::BigIntExpr
:
12446 if (!emitBigIntOp(&pn
->as
<BigIntLiteral
>())) {
12451 case ParseNodeKind::RegExpExpr
: {
12452 GCThingIndex index
;
12453 if (!perScriptData().gcThingList().append(&pn
->as
<RegExpLiteral
>(),
12457 if (!emitRegExp(index
)) {
12463 case ParseNodeKind::TrueExpr
:
12464 if (!emit1(JSOp::True
)) {
12468 case ParseNodeKind::FalseExpr
:
12469 if (!emit1(JSOp::False
)) {
12473 case ParseNodeKind::NullExpr
:
12474 if (!emit1(JSOp::Null
)) {
12478 case ParseNodeKind::RawUndefinedExpr
:
12479 if (!emit1(JSOp::Undefined
)) {
12484 case ParseNodeKind::ThisExpr
:
12485 if (!emitThisLiteral(&pn
->as
<ThisLiteral
>())) {
12490 case ParseNodeKind::DebuggerStmt
:
12491 if (!updateSourceCoordNotes(pn
->pn_pos
.begin
)) {
12494 if (!markStepBreakpoint()) {
12497 if (!emit1(JSOp::Debugger
)) {
12502 case ParseNodeKind::ClassDecl
:
12503 if (!emitClass(&pn
->as
<ClassNode
>())) {
12508 case ParseNodeKind::NewTargetExpr
:
12509 if (!emitNewTarget(&pn
->as
<NewTargetNode
>())) {
12514 case ParseNodeKind::ImportMetaExpr
:
12515 if (!emit1(JSOp::ImportMeta
)) {
12520 case ParseNodeKind::CallImportExpr
: {
12521 BinaryNode
* spec
= &pn
->as
<BinaryNode
>().right()->as
<BinaryNode
>();
12523 if (!emitTree(spec
->left())) {
12524 // [stack] specifier
12528 if (!spec
->right()->isKind(ParseNodeKind::PosHolder
)) {
12529 // [stack] specifier options
12530 if (!emitTree(spec
->right())) {
12534 // [stack] specifier undefined
12535 if (!emit1(JSOp::Undefined
)) {
12540 if (!emit1(JSOp::DynamicImport
)) {
12547 case ParseNodeKind::SetThis
:
12548 if (!emitSetThis(&pn
->as
<BinaryNode
>())) {
12553 #ifdef ENABLE_RECORD_TUPLE
12554 case ParseNodeKind::RecordExpr
:
12555 if (!emitRecordLiteral(&pn
->as
<ListNode
>())) {
12560 case ParseNodeKind::TupleExpr
:
12561 if (!emitTupleLiteral(&pn
->as
<ListNode
>())) {
12567 case ParseNodeKind::PropertyNameExpr
:
12568 case ParseNodeKind::PosHolder
:
12569 MOZ_FALLTHROUGH_ASSERT(
12570 "Should never try to emit ParseNodeKind::PosHolder or ::Property");
12579 static bool AllocSrcNote(FrontendContext
* fc
, SrcNotesVector
& notes
,
12580 unsigned size
, unsigned* index
) {
12581 size_t oldLength
= notes
.length();
12583 if (MOZ_UNLIKELY(oldLength
+ size
> MaxSrcNotesLength
)) {
12584 ReportAllocationOverflow(fc
);
12588 if (!notes
.growByUninitialized(size
)) {
12592 *index
= oldLength
;
12596 bool BytecodeEmitter::addTryNote(TryNoteKind kind
, uint32_t stackDepth
,
12597 BytecodeOffset start
, BytecodeOffset end
) {
12598 MOZ_ASSERT(!inPrologue());
12599 return bytecodeSection().tryNoteList().append(kind
, stackDepth
, start
, end
);
12602 bool BytecodeEmitter::newSrcNote(SrcNoteType type
, unsigned* indexp
) {
12603 SrcNotesVector
& notes
= bytecodeSection().notes();
12607 * Compute delta from the last annotated bytecode's offset. If it's too
12608 * big to fit in sn, allocate one or more xdelta notes and reset sn.
12610 BytecodeOffset offset
= bytecodeSection().offset();
12611 ptrdiff_t delta
= (offset
- bytecodeSection().lastNoteOffset()).value();
12612 bytecodeSection().setLastNoteOffset(offset
);
12614 auto allocator
= [&](unsigned size
) -> SrcNote
* {
12615 if (!AllocSrcNote(fc
, notes
, size
, &index
)) {
12618 return ¬es
[index
];
12621 if (!SrcNoteWriter::writeNote(type
, delta
, allocator
)) {
12629 if (type
== SrcNoteType::NewLine
|| type
== SrcNoteType::SetLine
) {
12630 lastLineOnlySrcNoteIndex
= index
;
12632 lastLineOnlySrcNoteIndex
= LastSrcNoteIsNotLineOnly
;
12638 bool BytecodeEmitter::newSrcNote2(SrcNoteType type
, ptrdiff_t offset
,
12639 unsigned* indexp
) {
12641 if (!newSrcNote(type
, &index
)) {
12644 if (!newSrcNoteOperand(offset
)) {
12653 bool BytecodeEmitter::convertLastNewLineToNewLineColumn(
12654 JS::LimitedColumnNumberOneOrigin column
) {
12655 SrcNotesVector
& notes
= bytecodeSection().notes();
12656 MOZ_ASSERT(lastLineOnlySrcNoteIndex
== notes
.length() - 1);
12657 SrcNote
* sn
= ¬es
[lastLineOnlySrcNoteIndex
];
12658 MOZ_ASSERT(sn
->type() == SrcNoteType::NewLine
);
12660 SrcNoteWriter::convertNote(sn
, SrcNoteType::NewLineColumn
);
12661 if (!newSrcNoteOperand(SrcNote::NewLineColumn::toOperand(column
))) {
12665 lastLineOnlySrcNoteIndex
= LastSrcNoteIsNotLineOnly
;
12669 bool BytecodeEmitter::convertLastSetLineToSetLineColumn(
12670 JS::LimitedColumnNumberOneOrigin column
) {
12671 SrcNotesVector
& notes
= bytecodeSection().notes();
12672 // The Line operand is either 1 byte or 4 bytes.
12673 MOZ_ASSERT(lastLineOnlySrcNoteIndex
== notes
.length() - 1 - 1 ||
12674 lastLineOnlySrcNoteIndex
== notes
.length() - 1 - 4);
12675 SrcNote
* sn
= ¬es
[lastLineOnlySrcNoteIndex
];
12676 MOZ_ASSERT(sn
->type() == SrcNoteType::SetLine
);
12678 SrcNoteWriter::convertNote(sn
, SrcNoteType::SetLineColumn
);
12679 if (!newSrcNoteOperand(SrcNote::SetLineColumn::columnToOperand(column
))) {
12683 lastLineOnlySrcNoteIndex
= LastSrcNoteIsNotLineOnly
;
12687 bool BytecodeEmitter::newSrcNoteOperand(ptrdiff_t operand
) {
12688 if (!SrcNote::isRepresentableOperand(operand
)) {
12689 reportError(nullptr, JSMSG_NEED_DIET
, "script");
12693 SrcNotesVector
& notes
= bytecodeSection().notes();
12695 auto allocator
= [&](unsigned size
) -> SrcNote
* {
12697 if (!AllocSrcNote(fc
, notes
, size
, &index
)) {
12700 return ¬es
[index
];
12703 return SrcNoteWriter::writeOperand(operand
, allocator
);
12706 bool BytecodeEmitter::intoScriptStencil(ScriptIndex scriptIndex
) {
12707 js::UniquePtr
<ImmutableScriptData
> immutableScriptData
=
12708 createImmutableScriptData();
12709 if (!immutableScriptData
) {
12713 MOZ_ASSERT(outermostScope().hasNonSyntacticScopeOnChain() ==
12714 sc
->hasNonSyntacticScope());
12716 auto& things
= perScriptData().gcThingList().objects();
12717 if (!compilationState
.appendGCThings(fc
, scriptIndex
, things
)) {
12721 // Hand over the ImmutableScriptData instance generated by BCE.
12723 SharedImmutableScriptData::createWith(fc
, std::move(immutableScriptData
));
12728 // De-duplicate the bytecode within the runtime.
12729 if (!compilationState
.sharedData
.addAndShare(fc
, scriptIndex
, sharedData
)) {
12733 ScriptStencil
& script
= compilationState
.scriptData
[scriptIndex
];
12734 script
.setHasSharedData();
12736 // Update flags specific to functions.
12737 if (sc
->isFunctionBox()) {
12738 FunctionBox
* funbox
= sc
->asFunctionBox();
12739 MOZ_ASSERT(&script
== &funbox
->functionStencil());
12740 funbox
->copyUpdatedImmutableFlags();
12741 MOZ_ASSERT(script
.isFunction());
12743 ScriptStencilExtra
& scriptExtra
= compilationState
.scriptExtra
[scriptIndex
];
12744 sc
->copyScriptExtraFields(scriptExtra
);
12750 SelfHostedIter
BytecodeEmitter::getSelfHostedIterFor(ParseNode
* parseNode
) {
12751 if (emitterMode
== BytecodeEmitter::SelfHosting
&&
12752 parseNode
->isKind(ParseNodeKind::CallExpr
)) {
12753 auto* callee
= parseNode
->as
<CallNode
>().callee();
12754 if (callee
->isName(TaggedParserAtomIndex::WellKnown::allowContentIter())) {
12755 return SelfHostedIter::AllowContent
;
12757 if (callee
->isName(
12758 TaggedParserAtomIndex::WellKnown::allowContentIterWith())) {
12759 return SelfHostedIter::AllowContentWith
;
12761 if (callee
->isName(
12762 TaggedParserAtomIndex::WellKnown::allowContentIterWithNext())) {
12763 return SelfHostedIter::AllowContentWithNext
;
12767 return SelfHostedIter::Deny
;
12770 #if defined(DEBUG) || defined(JS_JITSPEW)
12771 void BytecodeEmitter::dumpAtom(TaggedParserAtomIndex index
) const {
12772 parserAtoms().dump(index
);