ForOfLoopControl.h (4036B)
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_ForOfLoopControl_h 8 #define frontend_ForOfLoopControl_h 9 10 #include "mozilla/Maybe.h" // mozilla::Maybe 11 12 #include <stdint.h> // int32_t, uint32_t 13 14 #include "frontend/BytecodeControlStructures.h" // NestableControl, LoopControl 15 #include "frontend/IteratorKind.h" // IteratorKind 16 #include "frontend/SelfHostedIter.h" // SelfHostedIter 17 #include "frontend/TryEmitter.h" // TryEmitter 18 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 19 # include "frontend/UsingEmitter.h" // ForOfDisposalEmitter 20 #endif 21 #include "vm/CompletionKind.h" // CompletionKind 22 23 namespace js { 24 namespace frontend { 25 26 struct BytecodeEmitter; 27 class BytecodeOffset; 28 class EmitterScope; 29 30 class ForOfLoopControl : public LoopControl { 31 // The stack depth of the iterator. 32 int32_t iterDepth_; 33 34 // For-of loops, when throwing from non-iterator code (i.e. from the body 35 // or from evaluating the LHS of the loop condition), need to call 36 // IteratorClose. This is done by enclosing the body of the loop with 37 // try-catch and calling IteratorClose in the `catch` block. 38 // 39 // If IteratorClose itself throws, we must not re-call 40 // IteratorClose. Since non-local jumps like break and return call 41 // IteratorClose, whenever a non-local jump is emitted, we must 42 // prevent the catch block from catching any exception thrown from 43 // IteratorClose. We do this by wrapping the non-local jump in a 44 // ForOfIterClose try-note. 45 // 46 // for (x of y) { 47 // // Operations for iterator (IteratorNext etc) are outside of 48 // // try-block. 49 // try { 50 // ... 51 // if (...) { 52 // // Before non-local jump, close iterator. 53 // CloseIter(iter, CompletionKind::Return); // Covered by 54 // return; // trynote 55 // } 56 // ... 57 // } catch (e) { 58 // // When propagating an exception, we swallow any exceptions 59 // // thrown while closing the iterator. 60 // CloseIter(iter, CompletionKind::Throw); 61 // throw e; 62 // } 63 // } 64 mozilla::Maybe<TryEmitter> tryCatch_; 65 66 // Used to track if any yields were emitted between calls to to 67 // emitBeginCodeNeedingIteratorClose and emitEndCodeNeedingIteratorClose. 68 uint32_t numYieldsAtBeginCodeNeedingIterClose_; 69 70 SelfHostedIter selfHostedIter_; 71 72 IteratorKind iterKind_; 73 74 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 75 mozilla::Maybe<ForOfDisposalEmitter> forOfDisposalEmitter_; 76 #endif 77 78 public: 79 ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, 80 SelfHostedIter selfHostedIter, IteratorKind iterKind); 81 82 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 83 [[nodiscard]] bool prepareForForOfLoopIteration( 84 BytecodeEmitter* bce, const EmitterScope* headLexicalEmitterScope, 85 bool hasAwaitUsing); 86 #endif 87 88 [[nodiscard]] bool emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce); 89 [[nodiscard]] bool emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce); 90 91 [[nodiscard]] bool emitIteratorCloseInInnermostScopeWithTryNote( 92 BytecodeEmitter* bce, CompletionKind completionKind); 93 [[nodiscard]] bool emitIteratorCloseInScope(BytecodeEmitter* bce, 94 EmitterScope& currentScope, 95 CompletionKind completionKind); 96 97 [[nodiscard]] bool emitPrepareForNonLocalJumpFromScope( 98 BytecodeEmitter* bce, EmitterScope& currentScope, bool isTarget, 99 BytecodeOffset* tryNoteStart); 100 }; 101 template <> 102 inline bool NestableControl::is<ForOfLoopControl>() const { 103 return kind_ == StatementKind::ForOfLoop; 104 } 105 106 } /* namespace frontend */ 107 } /* namespace js */ 108 109 #endif /* frontend_ForOfLoopControl_h */