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/Opcodes.h" // JSOp
17 using namespace js::frontend
;
19 bool AsyncEmitter::prepareForParamsWithExpressionOrDestructuring() {
20 MOZ_ASSERT(state_
== State::Start
);
22 state_
= State::Parameters
;
25 rejectTryCatch_
.emplace(bce_
, TryEmitter::Kind::TryCatch
,
26 TryEmitter::ControlKind::NonSyntactic
);
27 return rejectTryCatch_
->emitTry();
30 bool AsyncEmitter::prepareForParamsWithoutExpressionOrDestructuring() {
31 MOZ_ASSERT(state_
== State::Start
);
33 state_
= State::Parameters
;
38 bool AsyncEmitter::emitParamsEpilogue() {
39 MOZ_ASSERT(state_
== State::Parameters
);
41 if (rejectTryCatch_
) {
42 // If we get here, we need to reset the TryEmitter. Parameters can't reuse
43 // the reject try-catch block from the function body, because the body
44 // may have pushed an additional var-environment. This messes up scope
45 // resolution for the |.generator| variable, because we'd need different
46 // hops to reach |.generator| depending on whether the error was thrown
47 // from the parameters or the function body.
48 if (!emitRejectCatch()) {
54 state_
= State::PostParams
;
59 bool AsyncEmitter::prepareForModule() {
60 // Unlike functions, modules do not have params that we need to worry about.
61 // Instead, this code is for setting up the required generator that will be
62 // used for top level await. Before we can start using top-level await in
63 // modules, we need to emit a
64 // |.generator| which we can use to pause and resume execution.
65 MOZ_ASSERT(state_
== State::Start
);
67 bce_
->lookupName(TaggedParserAtomIndex::WellKnown::dot_generator_())
70 NameOpEmitter
noe(bce_
, TaggedParserAtomIndex::WellKnown::dot_generator_(),
71 NameOpEmitter::Kind::Initialize
);
72 if (!noe
.prepareForRhs()) {
76 if (!bce_
->emit1(JSOp::Generator
)) {
80 if (!noe
.emitAssignment()) {
84 if (!bce_
->emit1(JSOp::Pop
)) {
90 state_
= State::ModulePrologue
;
96 bool AsyncEmitter::prepareForBody() {
97 MOZ_ASSERT(state_
== State::PostParams
|| state_
== State::ModulePrologue
);
99 rejectTryCatch_
.emplace(bce_
, TryEmitter::Kind::TryCatch
,
100 TryEmitter::ControlKind::NonSyntactic
);
102 state_
= State::Body
;
104 return rejectTryCatch_
->emitTry();
107 bool AsyncEmitter::emitEndFunction() {
109 MOZ_ASSERT(state_
== State::Body
);
112 // The final yield has already been emitted
113 // by FunctionScriptEmitter::emitEndBody().
115 if (!emitRejectCatch()) {
125 bool AsyncEmitter::emitEndModule() {
127 MOZ_ASSERT(state_
== State::Body
);
130 if (!emitFinalYield()) {
134 if (!emitRejectCatch()) {
144 bool AsyncEmitter::emitFinalYield() {
145 if (!bce_
->emit1(JSOp::Undefined
)) {
150 if (!bce_
->emitGetDotGeneratorInInnermostScope()) {
155 if (!bce_
->emit1(JSOp::AsyncResolve
)) {
160 if (!bce_
->emit1(JSOp::SetRval
)) {
165 if (!bce_
->emitGetDotGeneratorInInnermostScope()) {
170 if (!bce_
->emitYieldOp(JSOp::FinalYieldRval
)) {
178 bool AsyncEmitter::emitRejectCatch() {
179 if (!rejectTryCatch_
->emitCatch(TryEmitter::ExceptionStack::Yes
)) {
184 if (!bce_
->emitGetDotGeneratorInInnermostScope()) {
185 // [stack] EXC STACK GEN
189 if (!bce_
->emit1(JSOp::AsyncReject
)) {
194 if (!bce_
->emit1(JSOp::SetRval
)) {
199 if (!bce_
->emitGetDotGeneratorInInnermostScope()) {
204 if (!bce_
->emitYieldOp(JSOp::FinalYieldRval
)) {
209 if (!rejectTryCatch_
->emitEnd()) {
213 rejectTryCatch_
.reset();