AsyncEmitter.h (5709B)
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/. */ 6 7 #ifndef frontend_AsyncEmitter_h 8 #define frontend_AsyncEmitter_h 9 10 #include "mozilla/Attributes.h" // MOZ_STACK_CLASS 11 12 #include "frontend/TryEmitter.h" // TryEmitter 13 14 namespace js { 15 namespace frontend { 16 17 struct BytecodeEmitter; 18 19 // Class for emitting Bytecode associated with the AsyncFunctionGenerator. 20 // 21 // Usage: 22 // 23 // For an async function, the params have to be handled separately, 24 // because the body may have pushed an additional var environment, changing 25 // the number of hops required to reach the |.generator| variable. In order 26 // to handle this, we can't reuse the same TryCatch emitter. 27 // 28 // Simple case - For a function without expression or destructuring 29 // parameters: 30 // `async function f(<params>) {<body>}`, 31 // AsyncEmitter ae(this); 32 // 33 // ae.prepareForParamsWithoutExpressionOrDestructuring(); 34 // // Emit Params. 35 // ... 36 // ae.paramsEpilogue(); // We need to emit the epilogue before the extra 37 // VarScope emitExtraBodyVarScope(); 38 // 39 // // Emit new scope 40 // ae.prepareForBody(); 41 // 42 // // Emit body of the Function. 43 // ... 44 // 45 // ae.emitEndFunction(); 46 // 47 // Complex case - For a function with expression or destructuring parameters: 48 // `async function f(<expression>) {<body>}`, 49 // AsyncEmitter ae(this); 50 // 51 // ae.prepareForParamsWithExpressionOrDestructuring(); 52 // 53 // // Emit Params. 54 // ... 55 // ae.paramsEpilogue(); // We need to emit the epilogue before the extra 56 // // VarScope 57 // emitExtraBodyVarScope(); 58 // 59 // // Emit new scope 60 // ae.prepareForBody(); 61 // 62 // // Emit body of the Function. 63 // ... 64 // 65 // // The final yield is emitted in FunctionScriptEmitter::emitEndBody(). 66 // ae.emitEndFunction(); 67 // 68 // 69 // Async Module case - For a module with `await` in the top level: 70 // AsyncEmitter ae(this); 71 // ae.prepareForModule(); // prepareForModule is used to setup the generator 72 // // for the async module. 73 // switchToMain(); 74 // ... 75 // 76 // // Emit new scope 77 // ae.prepareForBody(); 78 // 79 // // Emit body of the Script. 80 // 81 // ae.emitEndModule(); 82 // 83 84 class MOZ_STACK_CLASS AsyncEmitter { 85 private: 86 BytecodeEmitter* bce_; 87 88 // try-catch block for async function parameter and body. 89 mozilla::Maybe<TryEmitter> rejectTryCatch_; 90 91 #ifdef DEBUG 92 // The state of this emitter. 93 // 94 // +-------+ 95 // | Start |-+ 96 // +-------+ | 97 // | 98 // +----------+ 99 // | 100 // | [Parameters with Expression or Destructuring] 101 // | prepareForParamsWithExpressionOrDestructuring +------------+ 102 // +----------------------------------------------------| Parameters |-->+ 103 // | +------------+ | 104 // | | 105 // | [Parameters Without Expression or Destructuring] | 106 // | prepareForParamsWithoutExpressionOrDestructuring +------------+ | 107 // +----------------------------------------------------| Parameters |-->+ 108 // | +------------+ | 109 // | [Modules] | 110 // | prepareForModule +----------------+ | 111 // +-------------------->| ModulePrologue |--+ | 112 // +----------------+ | | 113 // | | 114 // | | 115 // +-----------------------------------------+ | 116 // | | 117 // | | 118 // V +------------+ paramsEpilogue | 119 // +<--------------------| PostParams |<---------------------------------+ 120 // | +------------+ 121 // | 122 // | [Script body] 123 // | prepareForBody +---------+ 124 // +-------------------->| Body |--------+ 125 // +---------+ | <emit script body> 126 // +----------------------------------------+ 127 // | 128 // | [Functions] 129 // | emitEndFunction +-----+ 130 // +--------------------->| End | 131 // | +-----+ 132 // | 133 // | [Modules] 134 // | emitEndModule +-----+ 135 // +--------------------->| End | 136 // +-----+ 137 138 enum class State { 139 // The initial state. 140 Start, 141 142 Parameters, 143 144 ModulePrologue, 145 146 PostParams, 147 148 Body, 149 150 End, 151 }; 152 153 State state_ = State::Start; 154 #endif 155 156 [[nodiscard]] bool emitRejectCatch(); 157 [[nodiscard]] bool emitFinalYield(); 158 159 public: 160 explicit AsyncEmitter(BytecodeEmitter* bce) : bce_(bce) {}; 161 162 [[nodiscard]] bool prepareForParamsWithoutExpressionOrDestructuring(); 163 [[nodiscard]] bool prepareForParamsWithExpressionOrDestructuring(); 164 [[nodiscard]] bool prepareForModule(); 165 [[nodiscard]] bool emitParamsEpilogue(); 166 [[nodiscard]] bool prepareForBody(); 167 [[nodiscard]] bool emitEndFunction(); 168 [[nodiscard]] bool emitEndModule(); 169 }; 170 171 } /* namespace frontend */ 172 } /* namespace js */ 173 174 #endif /* frontend_AsyncEmitter_h */