Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / js / src / frontend / AsyncEmitter.cpp
blobbee6b804f17d7dffae20104f4d04161ddb1ed542
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
16 using namespace js;
17 using namespace js::frontend;
19 bool AsyncEmitter::prepareForParamsWithExpressionOrDestructuring() {
20 MOZ_ASSERT(state_ == State::Start);
21 #ifdef DEBUG
22 state_ = State::Parameters;
23 #endif
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);
32 #ifdef DEBUG
33 state_ = State::Parameters;
34 #endif
35 return true;
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()) {
49 return false;
53 #ifdef DEBUG
54 state_ = State::PostParams;
55 #endif
56 return true;
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);
66 MOZ_ASSERT(
67 bce_->lookupName(TaggedParserAtomIndex::WellKnown::dot_generator_())
68 .hasKnownSlot());
70 NameOpEmitter noe(bce_, TaggedParserAtomIndex::WellKnown::dot_generator_(),
71 NameOpEmitter::Kind::Initialize);
72 if (!noe.prepareForRhs()) {
73 // [stack]
74 return false;
76 if (!bce_->emit1(JSOp::Generator)) {
77 // [stack] GEN
78 return false;
80 if (!noe.emitAssignment()) {
81 // [stack] GEN
82 return false;
84 if (!bce_->emit1(JSOp::Pop)) {
85 // [stack]
86 return false;
89 #ifdef DEBUG
90 state_ = State::ModulePrologue;
91 #endif
93 return true;
96 bool AsyncEmitter::prepareForBody() {
97 MOZ_ASSERT(state_ == State::PostParams || state_ == State::ModulePrologue);
99 rejectTryCatch_.emplace(bce_, TryEmitter::Kind::TryCatch,
100 TryEmitter::ControlKind::NonSyntactic);
101 #ifdef DEBUG
102 state_ = State::Body;
103 #endif
104 return rejectTryCatch_->emitTry();
107 bool AsyncEmitter::emitEndFunction() {
108 #ifdef DEBUG
109 MOZ_ASSERT(state_ == State::Body);
110 #endif
112 // The final yield has already been emitted
113 // by FunctionScriptEmitter::emitEndBody().
115 if (!emitRejectCatch()) {
116 return false;
119 #ifdef DEBUG
120 state_ = State::End;
121 #endif
122 return true;
125 bool AsyncEmitter::emitEndModule() {
126 #ifdef DEBUG
127 MOZ_ASSERT(state_ == State::Body);
128 #endif
130 if (!emitFinalYield()) {
131 return false;
134 if (!emitRejectCatch()) {
135 return false;
138 #ifdef DEBUG
139 state_ = State::End;
140 #endif
141 return true;
144 bool AsyncEmitter::emitFinalYield() {
145 if (!bce_->emit1(JSOp::Undefined)) {
146 // [stack] UNDEF
147 return false;
150 if (!bce_->emitGetDotGeneratorInInnermostScope()) {
151 // [stack] UNDEF GEN
152 return false;
155 if (!bce_->emit1(JSOp::AsyncResolve)) {
156 // [stack] PROMISE
157 return false;
160 if (!bce_->emit1(JSOp::SetRval)) {
161 // [stack]
162 return false;
165 if (!bce_->emitGetDotGeneratorInInnermostScope()) {
166 // [stack] GEN
167 return false;
170 if (!bce_->emitYieldOp(JSOp::FinalYieldRval)) {
171 // [stack]
172 return false;
175 return true;
178 bool AsyncEmitter::emitRejectCatch() {
179 if (!rejectTryCatch_->emitCatch(TryEmitter::ExceptionStack::Yes)) {
180 // [stack] EXC STACK
181 return false;
184 if (!bce_->emitGetDotGeneratorInInnermostScope()) {
185 // [stack] EXC STACK GEN
186 return false;
189 if (!bce_->emit1(JSOp::AsyncReject)) {
190 // [stack] PROMISE
191 return false;
194 if (!bce_->emit1(JSOp::SetRval)) {
195 // [stack]
196 return false;
199 if (!bce_->emitGetDotGeneratorInInnermostScope()) {
200 // [stack] GEN
201 return false;
204 if (!bce_->emitYieldOp(JSOp::FinalYieldRval)) {
205 // [stack]
206 return false;
209 if (!rejectTryCatch_->emitEnd()) {
210 return false;
213 rejectTryCatch_.reset();
214 return true;