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
18 using namespace js::frontend
;
20 bool AsyncEmitter::prepareForParamsWithExpressionOrDestructuring() {
21 MOZ_ASSERT(state_
== State::Start
);
23 state_
= State::Parameters
;
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
);
34 state_
= State::Parameters
;
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()) {
55 state_
= State::PostParams
;
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
);
68 bce_
->lookupName(TaggedParserAtomIndex::WellKnown::dot_generator_())
71 NameOpEmitter
noe(bce_
, TaggedParserAtomIndex::WellKnown::dot_generator_(),
72 NameOpEmitter::Kind::Initialize
);
73 if (!noe
.prepareForRhs()) {
77 if (!bce_
->emit1(JSOp::Generator
)) {
81 if (!noe
.emitAssignment()) {
85 if (!bce_
->emit1(JSOp::Pop
)) {
91 state_
= State::ModulePrologue
;
97 bool AsyncEmitter::prepareForBody() {
98 MOZ_ASSERT(state_
== State::PostParams
|| state_
== State::ModulePrologue
);
100 rejectTryCatch_
.emplace(bce_
, TryEmitter::Kind::TryCatch
,
101 TryEmitter::ControlKind::NonSyntactic
);
103 state_
= State::Body
;
105 return rejectTryCatch_
->emitTry();
108 bool AsyncEmitter::emitEndFunction() {
110 MOZ_ASSERT(state_
== State::Body
);
113 // The final yield has already been emitted
114 // by FunctionScriptEmitter::emitEndBody().
116 if (!emitRejectCatch()) {
126 bool AsyncEmitter::emitEndModule() {
128 MOZ_ASSERT(state_
== State::Body
);
131 if (!emitFinalYield()) {
135 if (!emitRejectCatch()) {
145 bool AsyncEmitter::emitFinalYield() {
146 if (!bce_
->emit1(JSOp::Undefined
)) {
151 if (!bce_
->emitGetDotGeneratorInInnermostScope()) {
156 if (!bce_
->emit2(JSOp::AsyncResolve
,
157 uint8_t(AsyncFunctionResolveKind::Fulfill
))) {
162 if (!bce_
->emit1(JSOp::SetRval
)) {
167 if (!bce_
->emitGetDotGeneratorInInnermostScope()) {
172 if (!bce_
->emitYieldOp(JSOp::FinalYieldRval
)) {
180 bool AsyncEmitter::emitRejectCatch() {
181 if (!rejectTryCatch_
->emitCatch()) {
186 if (!bce_
->emitGetDotGeneratorInInnermostScope()) {
191 if (!bce_
->emit2(JSOp::AsyncResolve
,
192 uint8_t(AsyncFunctionResolveKind::Reject
))) {
197 if (!bce_
->emit1(JSOp::SetRval
)) {
202 if (!bce_
->emitGetDotGeneratorInInnermostScope()) {
207 if (!bce_
->emitYieldOp(JSOp::FinalYieldRval
)) {
212 if (!rejectTryCatch_
->emitEnd()) {
216 rejectTryCatch_
.reset();