Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / AsyncEmitter.cpp
blobc635ccd73e3a52fb38be91bf74d03adf2e478df6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "frontend/AsyncEmitter.h"
9 #include "mozilla/Assertions.h" // MOZ_ASSERT
11 #include "frontend/BytecodeEmitter.h" // BytecodeEmitter
12 #include "frontend/NameOpEmitter.h" // NameOpEmitter
13 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex
14 #include "vm/AsyncFunctionResolveKind.h" // AsyncFunctionResolveKind
15 #include "vm/Opcodes.h" // JSOp
17 using namespace js;
18 using namespace js::frontend;
20 bool AsyncEmitter::prepareForParamsWithExpressionOrDestructuring() {
21 MOZ_ASSERT(state_ == State::Start);
22 #ifdef DEBUG
23 state_ = State::Parameters;
24 #endif
26 rejectTryCatch_.emplace(bce_, TryEmitter::Kind::TryCatch,
27 TryEmitter::ControlKind::NonSyntactic);
28 return rejectTryCatch_->emitTry();
31 bool AsyncEmitter::prepareForParamsWithoutExpressionOrDestructuring() {
32 MOZ_ASSERT(state_ == State::Start);
33 #ifdef DEBUG
34 state_ = State::Parameters;
35 #endif
36 return true;
39 bool AsyncEmitter::emitParamsEpilogue() {
40 MOZ_ASSERT(state_ == State::Parameters);
42 if (rejectTryCatch_) {
43 // If we get here, we need to reset the TryEmitter. Parameters can't reuse
44 // the reject try-catch block from the function body, because the body
45 // may have pushed an additional var-environment. This messes up scope
46 // resolution for the |.generator| variable, because we'd need different
47 // hops to reach |.generator| depending on whether the error was thrown
48 // from the parameters or the function body.
49 if (!emitRejectCatch()) {
50 return false;
54 #ifdef DEBUG
55 state_ = State::PostParams;
56 #endif
57 return true;
60 bool AsyncEmitter::prepareForModule() {
61 // Unlike functions, modules do not have params that we need to worry about.
62 // Instead, this code is for setting up the required generator that will be
63 // used for top level await. Before we can start using top-level await in
64 // modules, we need to emit a
65 // |.generator| which we can use to pause and resume execution.
66 MOZ_ASSERT(state_ == State::Start);
67 MOZ_ASSERT(
68 bce_->lookupName(TaggedParserAtomIndex::WellKnown::dot_generator_())
69 .hasKnownSlot());
71 NameOpEmitter noe(bce_, TaggedParserAtomIndex::WellKnown::dot_generator_(),
72 NameOpEmitter::Kind::Initialize);
73 if (!noe.prepareForRhs()) {
74 // [stack]
75 return false;
77 if (!bce_->emit1(JSOp::Generator)) {
78 // [stack] GEN
79 return false;
81 if (!noe.emitAssignment()) {
82 // [stack] GEN
83 return false;
85 if (!bce_->emit1(JSOp::Pop)) {
86 // [stack]
87 return false;
90 #ifdef DEBUG
91 state_ = State::ModulePrologue;
92 #endif
94 return true;
97 bool AsyncEmitter::prepareForBody() {
98 MOZ_ASSERT(state_ == State::PostParams || state_ == State::ModulePrologue);
100 rejectTryCatch_.emplace(bce_, TryEmitter::Kind::TryCatch,
101 TryEmitter::ControlKind::NonSyntactic);
102 #ifdef DEBUG
103 state_ = State::Body;
104 #endif
105 return rejectTryCatch_->emitTry();
108 bool AsyncEmitter::emitEndFunction() {
109 #ifdef DEBUG
110 MOZ_ASSERT(state_ == State::Body);
111 #endif
113 // The final yield has already been emitted
114 // by FunctionScriptEmitter::emitEndBody().
116 if (!emitRejectCatch()) {
117 return false;
120 #ifdef DEBUG
121 state_ = State::End;
122 #endif
123 return true;
126 bool AsyncEmitter::emitEndModule() {
127 #ifdef DEBUG
128 MOZ_ASSERT(state_ == State::Body);
129 #endif
131 if (!emitFinalYield()) {
132 return false;
135 if (!emitRejectCatch()) {
136 return false;
139 #ifdef DEBUG
140 state_ = State::End;
141 #endif
142 return true;
145 bool AsyncEmitter::emitFinalYield() {
146 if (!bce_->emit1(JSOp::Undefined)) {
147 // [stack] UNDEF
148 return false;
151 if (!bce_->emitGetDotGeneratorInInnermostScope()) {
152 // [stack] UNDEF GEN
153 return false;
156 if (!bce_->emit2(JSOp::AsyncResolve,
157 uint8_t(AsyncFunctionResolveKind::Fulfill))) {
158 // [stack] PROMISE
159 return false;
162 if (!bce_->emit1(JSOp::SetRval)) {
163 // [stack]
164 return false;
167 if (!bce_->emitGetDotGeneratorInInnermostScope()) {
168 // [stack] GEN
169 return false;
172 if (!bce_->emitYieldOp(JSOp::FinalYieldRval)) {
173 // [stack]
174 return false;
177 return true;
180 bool AsyncEmitter::emitRejectCatch() {
181 if (!rejectTryCatch_->emitCatch()) {
182 // [stack] EXC
183 return false;
186 if (!bce_->emitGetDotGeneratorInInnermostScope()) {
187 // [stack] EXC GEN
188 return false;
191 if (!bce_->emit2(JSOp::AsyncResolve,
192 uint8_t(AsyncFunctionResolveKind::Reject))) {
193 // [stack] PROMISE
194 return false;
197 if (!bce_->emit1(JSOp::SetRval)) {
198 // [stack]
199 return false;
202 if (!bce_->emitGetDotGeneratorInInnermostScope()) {
203 // [stack] GEN
204 return false;
207 if (!bce_->emitYieldOp(JSOp::FinalYieldRval)) {
208 // [stack]
209 return false;
212 if (!rejectTryCatch_->emitEnd()) {
213 return false;
216 rejectTryCatch_.reset();
217 return true;