summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/ForOfLoopControl.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend/ForOfLoopControl.h')
-rw-r--r--js/src/frontend/ForOfLoopControl.h97
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 */