/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * 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 jsiter_h #define jsiter_h /* * JavaScript iterators. */ #include "mozilla/MemoryReporting.h" #include "jscntxt.h" #include "gc/Barrier.h" #include "vm/ReceiverGuard.h" #include "vm/Stack.h" /* * For cacheable native iterators, whether the iterator is currently active. * Not serialized by XDR. */ #define JSITER_ACTIVE 0x1000 #define JSITER_UNREUSABLE 0x2000 namespace js { class PropertyIteratorObject; struct NativeIterator { GCPtrObject obj; // Object being iterated. JSObject* iterObj_; // Internal iterator object. GCPtrFlatString* props_array; GCPtrFlatString* props_cursor; GCPtrFlatString* props_end; HeapReceiverGuard* guard_array; uint32_t guard_length; uint32_t guard_key; uint32_t flags; private: /* While in compartment->enumerators, these form a doubly linked list. */ NativeIterator* next_; NativeIterator* prev_; public: bool isKeyIter() const { return (flags & JSITER_FOREACH) == 0; } inline GCPtrFlatString* begin() const { return props_array; } inline GCPtrFlatString* end() const { return props_end; } size_t numKeys() const { return end() - begin(); } JSObject* iterObj() const { return iterObj_; } GCPtrFlatString* current() const { MOZ_ASSERT(props_cursor < props_end); return props_cursor; } NativeIterator* next() { return next_; } static inline size_t offsetOfNext() { return offsetof(NativeIterator, next_); } static inline size_t offsetOfPrev() { return offsetof(NativeIterator, prev_); } void incCursor() { props_cursor = props_cursor + 1; } void link(NativeIterator* other) { /* A NativeIterator cannot appear in the enumerator list twice. */ MOZ_ASSERT(!next_ && !prev_); MOZ_ASSERT(flags & JSITER_ENUMERATE); this->next_ = other; this->prev_ = other->prev_; other->prev_->next_ = this; other->prev_ = this; } void unlink() { MOZ_ASSERT(flags & JSITER_ENUMERATE); next_->prev_ = prev_; prev_->next_ = next_; next_ = nullptr; prev_ = nullptr; } static NativeIterator* allocateSentinel(JSContext* maybecx); static NativeIterator* allocateIterator(JSContext* cx, uint32_t slength, uint32_t plength); void init(JSObject* obj, JSObject* iterObj, unsigned flags, uint32_t slength, uint32_t key); bool initProperties(JSContext* cx, Handle obj, const js::AutoIdVector& props); void trace(JSTracer* trc); static void destroy(NativeIterator* iter) { js_free(iter); } }; class PropertyIteratorObject : public NativeObject { static const ClassOps classOps_; public: static const Class class_; NativeIterator* getNativeIterator() const { return static_cast(getPrivate()); } void setNativeIterator(js::NativeIterator* ni) { setPrivate(ni); } size_t sizeOfMisc(mozilla::MallocSizeOf mallocSizeOf) const; private: static void trace(JSTracer* trc, JSObject* obj); static void finalize(FreeOp* fop, JSObject* obj); }; class ArrayIteratorObject : public JSObject { public: static const Class class_; }; class StringIteratorObject : public JSObject { public: static const Class class_; }; class RegExpStringIteratorObject : public JSObject { public: static const Class class_; }; bool GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleObject objp); JSObject* GetIteratorObject(JSContext* cx, HandleObject obj, unsigned flags); /* * Creates either a key or value iterator, depending on flags. For a value * iterator, performs value-lookup to convert the given list of jsids. */ bool EnumeratedIdVectorToIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVector& props, MutableHandleObject objp); bool NewEmptyPropertyIterator(JSContext* cx, unsigned flags, MutableHandleObject objp); /* * Convert the value stored in *vp to its iteration object. The flags should * contain JSITER_ENUMERATE if js::ValueToIterator is called when enumerating * for-in semantics are required, and when the caller can guarantee that the * iterator will never be exposed to scripts. */ JSObject* ValueToIterator(JSContext* cx, unsigned flags, HandleValue vp); bool CloseIterator(JSContext* cx, HandleObject iterObj); bool UnwindIteratorForException(JSContext* cx, HandleObject obj); bool IteratorCloseForException(JSContext* cx, HandleObject obj); void UnwindIteratorForUncatchableException(JSContext* cx, JSObject* obj); bool IteratorConstructor(JSContext* cx, unsigned argc, Value* vp); extern bool SuppressDeletedProperty(JSContext* cx, HandleObject obj, jsid id); extern bool SuppressDeletedElement(JSContext* cx, HandleObject obj, uint32_t index); /* * IteratorMore() returns the next iteration value. If no value is available, * MagicValue(JS_NO_ITER_VALUE) is returned. */ extern bool IteratorMore(JSContext* cx, HandleObject iterobj, MutableHandleValue rval); extern bool ThrowStopIteration(JSContext* cx); /* * Create an object of the form { value: VALUE, done: DONE }. * ES 2017 draft 7.4.7. */ extern JSObject* CreateIterResultObject(JSContext* cx, HandleValue value, bool done); extern JSObject* InitLegacyIteratorClass(JSContext* cx, HandleObject obj); extern JSObject* InitStopIterationClass(JSContext* cx, HandleObject obj); } /* namespace js */ #endif /* jsiter_h */