UsingEmitter.h (7899B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifndef frontend_UsingEmitter_h 6 #define frontend_UsingEmitter_h 7 8 #include "mozilla/Attributes.h" 9 10 #include "frontend/TryEmitter.h" 11 #include "js/UniquePtr.h" 12 #include "vm/UsingHint.h" 13 14 namespace js::frontend { 15 16 struct BytecodeEmitter; 17 class EmitterScope; 18 19 // This enum simply refers to the kind of block we are operating in. The present 20 // use case of this is for disposal related code to special case the handling of 21 // disposals in different blocks. 22 enum class BlockKind : uint8_t { 23 ForOf, 24 25 // Other here refers to any generic block which doesnt require any 26 // special handling. 27 Other 28 }; 29 30 // Class for emitting bytecode for disposal loops. 31 // https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-disposeresources 32 // 33 // Usage: (check for the return value is omitted for simplicity) 34 // 35 // at the point where the disposal loop is needed 36 // DisposalEmitter de(bce, hasAsyncDisposables, initialCompletion); 37 // de.prepareForDisposeCapability(); 38 // emit_DisposeCapability(); 39 // de.emitEnd(es); 40 // 41 class MOZ_STACK_CLASS DisposalEmitter { 42 private: 43 BytecodeEmitter* bce_; 44 bool hasAsyncDisposables_; 45 46 #ifdef DEBUG 47 // The state of this emitter. 48 // 49 // +-------+ prepareForDisposeCapability +-----------------------------+ 50 // | Start |------------------------------>| prepareForDisposeCapability |--+ 51 // +-------+ +-----------------------------+ | 52 // | 53 // +----------------------------------------------------------------------+ 54 // | 55 // | emitEnd +-----+ 56 // +---------->| End | 57 // +-----+ 58 enum class State { 59 // The initial state. 60 Start, 61 62 // After calling prepareForDisposeCapability. 63 DisposeCapability, 64 65 // After calling emitEnd. 66 End 67 }; 68 State state_ = State::Start; 69 #endif 70 71 [[nodiscard]] bool emitResourcePropertyAccess(TaggedParserAtomIndex prop, 72 unsigned resourcesFromTop = 1); 73 74 public: 75 DisposalEmitter(BytecodeEmitter* bce, bool hasAsyncDisposables) 76 : bce_(bce), hasAsyncDisposables_(hasAsyncDisposables) {} 77 78 [[nodiscard]] bool prepareForDisposeCapability(); 79 80 [[nodiscard]] bool emitEnd(EmitterScope& es); 81 }; 82 83 // Class for emitting bytecode for using declarations. 84 // 85 // Usage: (check for the return value is omitted for simplicity) 86 // 87 // at the point of scope start 88 // UsingEmitter ue(bce); 89 // ue.prepareForDisposableScopeBody(); 90 // 91 // at the point of using decl assignment, e.g. `using x = y;` 92 // ue.prepareForAssignment(UsingHint::Normal); 93 // emit_Assignment(); 94 // 95 // at points requiring non-local jumps, like break, continue 96 // ue.emitNonLocalJump(¤tScope); 97 // 98 // at the point of scope end 99 // ue.emitEnd(); 100 class MOZ_STACK_CLASS UsingEmitter { 101 private: 102 js::UniquePtr<TryEmitter> tryEmitter_; 103 104 bool hasAwaitUsing_ = false; 105 106 #ifdef DEBUG 107 // The state of this emitter. 108 // 109 // +-------+ prepareForDisposableScopeBody 110 // | Start |---------------------------------+ 111 // +-------+ | 112 // | 113 // +---------------------------------------+ 114 // | 115 // | +---------------------+ emitEnd +-----+ 116 // +-->+-->| DisposableScopeBody |--+----------->| End | 117 // ^ +---------------------+ | +-----+ 118 // | | 119 // | prepareForAssignment | 120 // +<---------------------------+ 121 // ^ | 122 // | emitNonLocalJump | 123 // +----------------------------+ 124 // 125 enum class State { 126 // The initial state. 127 Start, 128 129 // After calling prepareForDisposableScopeBody. 130 DisposableScopeBody, 131 132 // After calling emitEnd. 133 End 134 }; 135 State state_ = State::Start; 136 #endif 137 138 [[nodiscard]] bool emitGetDisposeMethod(UsingHint hint); 139 140 [[nodiscard]] bool emitCreateDisposableResource(UsingHint hint); 141 142 [[nodiscard]] bool emitTakeDisposeCapability(); 143 144 protected: 145 BytecodeEmitter* bce_; 146 147 [[nodiscard]] bool emitThrowIfException(); 148 149 [[nodiscard]] bool emitDisposeResourcesForEnvironment(EmitterScope& es); 150 151 public: 152 explicit UsingEmitter(BytecodeEmitter* bce); 153 154 bool hasAwaitUsing() const { return hasAwaitUsing_; } 155 156 void setHasAwaitUsing(bool hasAwaitUsing) { hasAwaitUsing_ = hasAwaitUsing; } 157 158 [[nodiscard]] bool prepareForDisposableScopeBody(BlockKind blockKind); 159 160 [[nodiscard]] bool prepareForAssignment(UsingHint hint); 161 162 [[nodiscard]] bool emitEnd(); 163 }; 164 165 // This is a version of UsingEmitter specialized to help emit code for 166 // using declarations in for-of loop heads e.g.: `for (using x of y) {}`. 167 // 168 // Usage: (check for the return value is omitted for simplicity) 169 // 170 // at the point of the for-of loop head 171 // ForOfDisposalEmitter disposeBeforeIter(bce, hasAwaitUsing); 172 // disposeBeforeIter.prepareForForOfLoopIteration(); 173 // emit_Loop(); 174 // 175 // at the point of loop end 176 // prepare_IteratorClose(); 177 // disposeBeforeIter.emitEnd(); 178 // 179 class MOZ_STACK_CLASS ForOfDisposalEmitter : protected UsingEmitter { 180 private: 181 #ifdef DEBUG 182 // The state of this emitter. 183 // 184 // +-------+ prepareForForOfLoopIteration +-----------+ 185 // | Start |-------------------------------->| Iteration |--+ 186 // +-------+ +-----------+ | 187 // | 188 // +------------------------------------------------------+ 189 // | 190 // | emitEnd +-----+ 191 // +---------->| End | 192 // +-----+ 193 enum class State { 194 // The initial state. 195 Start, 196 197 // After calling prepareForForOfLoopIteration. 198 Iteration, 199 200 // After calling emitEnd. 201 End 202 }; 203 State state_ = State::Start; 204 #endif 205 public: 206 explicit ForOfDisposalEmitter(BytecodeEmitter* bce, bool hasAwaitUsing) 207 : UsingEmitter(bce) { 208 setHasAwaitUsing(hasAwaitUsing); 209 } 210 211 [[nodiscard]] bool prepareForForOfLoopIteration(); 212 213 [[nodiscard]] bool emitEnd(); 214 }; 215 216 // This is a version of UsingEmitter specialized to help emit code for 217 // non-local jumps in for-of loops for closing iterators. 218 // 219 // Usage: (check for the return value is omitted for simplicity) 220 // 221 // at the point of IteratorClose inside non-local jump 222 // NonLocalIteratorCloseUsingEmitter disposeBeforeIterClose(bce); 223 // disposeBeforeIterClose.prepareForIteratorClose(¤tScope); 224 // emit_IteratorClose(); 225 // disposeBeforeIterClose.emitEnd(¤tScope); 226 // 227 class MOZ_STACK_CLASS NonLocalIteratorCloseUsingEmitter 228 : protected UsingEmitter { 229 private: 230 js::UniquePtr<TryEmitter> tryClosingIterator_; 231 232 #ifdef DEBUG 233 // The state of this emitter. 234 // 235 // +-------+ prepareForIteratorClose +-------------------------+ 236 // | Start |-------------------------->| prepareForIteratorClose |--+ 237 // +-------+ +-------------------------+ | 238 // | 239 // +--------------------------------------------------------------+ 240 // | 241 // | emitEnd +-----+ 242 // +---------->| End | 243 // +-----+ 244 enum class State { 245 // The initial state. 246 Start, 247 248 // After calling prepareForIteratorClose. 249 IteratorClose, 250 251 // After calling emitEnd. 252 End 253 }; 254 State state_ = State::Start; 255 #endif 256 257 public: 258 explicit NonLocalIteratorCloseUsingEmitter(BytecodeEmitter* bce) 259 : UsingEmitter(bce) {} 260 261 [[nodiscard]] bool prepareForIteratorClose(EmitterScope& es); 262 263 [[nodiscard]] bool emitEnd(); 264 }; 265 266 } // namespace js::frontend 267 268 #endif // frontend_UsingEmitter_h