diff options
Diffstat (limited to 'js/src/frontend/ForOfLoopControl.h')
-rw-r--r-- | js/src/frontend/ForOfLoopControl.h | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/js/src/frontend/ForOfLoopControl.h b/js/src/frontend/ForOfLoopControl.h new file mode 100644 index 0000000000..5ffda9a8ba --- /dev/null +++ b/js/src/frontend/ForOfLoopControl.h @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef frontend_ForOfLoopControl_h +#define frontend_ForOfLoopControl_h + +#include "mozilla/Maybe.h" // mozilla::Maybe + +#include <stdint.h> // int32_t, uint32_t + +#include "frontend/BytecodeControlStructures.h" // NestableControl, LoopControl +#include "frontend/IteratorKind.h" // IteratorKind +#include "frontend/SelfHostedIter.h" // SelfHostedIter +#include "frontend/TryEmitter.h" // TryEmitter +#include "vm/CompletionKind.h" // CompletionKind + +namespace js { +namespace frontend { + +struct BytecodeEmitter; +class BytecodeOffset; +class EmitterScope; + +class ForOfLoopControl : public LoopControl { + // The stack depth of the iterator. + int32_t iterDepth_; + + // For-of loops, when throwing from non-iterator code (i.e. from the body + // or from evaluating the LHS of the loop condition), need to call + // IteratorClose. This is done by enclosing the body of the loop with + // try-catch and calling IteratorClose in the `catch` block. + // + // If IteratorClose itself throws, we must not re-call + // IteratorClose. Since non-local jumps like break and return call + // IteratorClose, whenever a non-local jump is emitted, we must + // prevent the catch block from catching any exception thrown from + // IteratorClose. We do this by wrapping the non-local jump in a + // ForOfIterClose try-note. + // + // for (x of y) { + // // Operations for iterator (IteratorNext etc) are outside of + // // try-block. + // try { + // ... + // if (...) { + // // Before non-local jump, close iterator. + // CloseIter(iter, CompletionKind::Return); // Covered by + // return; // trynote + // } + // ... + // } catch (e) { + // // When propagating an exception, we swallow any exceptions + // // thrown while closing the iterator. + // CloseIter(iter, CompletionKind::Throw); + // throw e; + // } + // } + mozilla::Maybe<TryEmitter> tryCatch_; + + // Used to track if any yields were emitted between calls to to + // emitBeginCodeNeedingIteratorClose and emitEndCodeNeedingIteratorClose. + uint32_t numYieldsAtBeginCodeNeedingIterClose_; + + SelfHostedIter selfHostedIter_; + + IteratorKind iterKind_; + + public: + ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, + SelfHostedIter selfHostedIter, IteratorKind iterKind); + + [[nodiscard]] bool emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce); + [[nodiscard]] bool emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce); + + [[nodiscard]] bool emitIteratorCloseInInnermostScopeWithTryNote( + BytecodeEmitter* bce, + CompletionKind completionKind = CompletionKind::Normal); + [[nodiscard]] bool emitIteratorCloseInScope( + BytecodeEmitter* bce, EmitterScope& currentScope, + CompletionKind completionKind = CompletionKind::Normal); + + [[nodiscard]] bool emitPrepareForNonLocalJumpFromScope( + BytecodeEmitter* bce, EmitterScope& currentScope, bool isTarget, + BytecodeOffset* tryNoteStart); +}; +template <> +inline bool NestableControl::is<ForOfLoopControl>() const { + return kind_ == StatementKind::ForOfLoop; +} + +} /* namespace frontend */ +} /* namespace js */ + +#endif /* frontend_ForOfLoopControl_h */ |