/* -*- 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/Attributes.h" // MOZ_MUST_USE #include "mozilla/Maybe.h" // mozilla::Maybe #include // int32_t, uint32_t #include "jsapi.h" // CompletionKind #include "frontend/BytecodeControlStructures.h" // NestableControl, LoopControl #include "frontend/BytecodeOffset.h" // BytecodeOffset #include "frontend/IteratorKind.h" // IteratorKind #include "frontend/TryEmitter.h" // TryEmitter namespace js { namespace frontend { struct BytecodeEmitter; 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 non-iterator code with // try-catch and call IteratorClose in `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 tell catch block not to perform // IteratorClose. // // for (x of y) { // // Operations for iterator (IteratorNext etc) are outside of // // try-block. // try { // ... // if (...) { // // Before non-local jump, clear iterator on the stack to tell // // catch block not to perform IteratorClose. // tmpIterator = iterator; // iterator = undefined; // IteratorClose(tmpIterator, { break }); // break; // } // ... // } catch (e) { // // Just throw again when iterator is cleared by non-local jump. // if (iterator === undefined) // throw e; // IteratorClose(iterator, { throw, e }); // } // } mozilla::Maybe tryCatch_; // Used to track if any yields were emitted between calls to to // emitBeginCodeNeedingIteratorClose and emitEndCodeNeedingIteratorClose. uint32_t numYieldsAtBeginCodeNeedingIterClose_; bool allowSelfHosted_; IteratorKind iterKind_; public: ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted, IteratorKind iterKind); MOZ_MUST_USE bool emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce); MOZ_MUST_USE bool emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce); MOZ_MUST_USE bool emitIteratorCloseInInnermostScopeWithTryNote( BytecodeEmitter* bce, CompletionKind completionKind = CompletionKind::Normal); MOZ_MUST_USE bool emitIteratorCloseInScope( BytecodeEmitter* bce, EmitterScope& currentScope, CompletionKind completionKind = CompletionKind::Normal); MOZ_MUST_USE bool emitPrepareForNonLocalJumpFromScope( BytecodeEmitter* bce, EmitterScope& currentScope, bool isTarget, BytecodeOffset* tryNoteStart); }; template <> inline bool NestableControl::is() const { return kind_ == StatementKind::ForOfLoop; } } /* namespace frontend */ } /* namespace js */ #endif /* frontend_ForOfLoopControl_h */