michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jsiter_h michael@0: #define jsiter_h michael@0: michael@0: /* michael@0: * JavaScript iterators. michael@0: */ michael@0: michael@0: #include "mozilla/MemoryReporting.h" michael@0: michael@0: #include "jscntxt.h" michael@0: michael@0: #include "gc/Barrier.h" michael@0: #include "vm/Stack.h" michael@0: michael@0: /* michael@0: * For cacheable native iterators, whether the iterator is currently active. michael@0: * Not serialized by XDR. michael@0: */ michael@0: #define JSITER_ACTIVE 0x1000 michael@0: #define JSITER_UNREUSABLE 0x2000 michael@0: michael@0: namespace js { michael@0: michael@0: struct NativeIterator michael@0: { michael@0: HeapPtrObject obj; // Object being iterated. michael@0: JSObject *iterObj_; // Internal iterator object. michael@0: HeapPtr *props_array; michael@0: HeapPtr *props_cursor; michael@0: HeapPtr *props_end; michael@0: Shape **shapes_array; michael@0: uint32_t shapes_length; michael@0: uint32_t shapes_key; michael@0: uint32_t flags; michael@0: michael@0: private: michael@0: /* While in compartment->enumerators, these form a doubly linked list. */ michael@0: NativeIterator *next_; michael@0: NativeIterator *prev_; michael@0: michael@0: public: michael@0: bool isKeyIter() const { michael@0: return (flags & JSITER_FOREACH) == 0; michael@0: } michael@0: michael@0: inline HeapPtr *begin() const { michael@0: return props_array; michael@0: } michael@0: michael@0: inline HeapPtr *end() const { michael@0: return props_end; michael@0: } michael@0: michael@0: size_t numKeys() const { michael@0: return end() - begin(); michael@0: } michael@0: michael@0: JSObject *iterObj() const { michael@0: return iterObj_; michael@0: } michael@0: HeapPtr *current() const { michael@0: JS_ASSERT(props_cursor < props_end); michael@0: return props_cursor; michael@0: } michael@0: michael@0: NativeIterator *next() { michael@0: return next_; michael@0: } michael@0: michael@0: static inline size_t offsetOfNext() { michael@0: return offsetof(NativeIterator, next_); michael@0: } michael@0: static inline size_t offsetOfPrev() { michael@0: return offsetof(NativeIterator, prev_); michael@0: } michael@0: michael@0: void incCursor() { michael@0: props_cursor = props_cursor + 1; michael@0: } michael@0: void link(NativeIterator *other) { michael@0: /* A NativeIterator cannot appear in the enumerator list twice. */ michael@0: JS_ASSERT(!next_ && !prev_); michael@0: JS_ASSERT(flags & JSITER_ENUMERATE); michael@0: michael@0: this->next_ = other; michael@0: this->prev_ = other->prev_; michael@0: other->prev_->next_ = this; michael@0: other->prev_ = this; michael@0: } michael@0: void unlink() { michael@0: JS_ASSERT(flags & JSITER_ENUMERATE); michael@0: michael@0: next_->prev_ = prev_; michael@0: prev_->next_ = next_; michael@0: next_ = nullptr; michael@0: prev_ = nullptr; michael@0: } michael@0: michael@0: static NativeIterator *allocateSentinel(JSContext *cx); michael@0: static NativeIterator *allocateIterator(JSContext *cx, uint32_t slength, michael@0: const js::AutoIdVector &props); michael@0: void init(JSObject *obj, JSObject *iterObj, unsigned flags, uint32_t slength, uint32_t key); michael@0: michael@0: void mark(JSTracer *trc); michael@0: michael@0: static void destroy(NativeIterator *iter) { michael@0: js_free(iter); michael@0: } michael@0: }; michael@0: michael@0: class PropertyIteratorObject : public JSObject michael@0: { michael@0: public: michael@0: static const Class class_; michael@0: michael@0: NativeIterator *getNativeIterator() const { michael@0: return static_cast(getPrivate()); michael@0: } michael@0: void setNativeIterator(js::NativeIterator *ni) { michael@0: setPrivate(ni); michael@0: } michael@0: michael@0: size_t sizeOfMisc(mozilla::MallocSizeOf mallocSizeOf) const; michael@0: michael@0: private: michael@0: static void trace(JSTracer *trc, JSObject *obj); michael@0: static void finalize(FreeOp *fop, JSObject *obj); michael@0: }; michael@0: michael@0: class ArrayIteratorObject : public JSObject michael@0: { michael@0: public: michael@0: static const Class class_; michael@0: }; michael@0: michael@0: class StringIteratorObject : public JSObject michael@0: { michael@0: public: michael@0: static const Class class_; michael@0: }; michael@0: michael@0: bool michael@0: VectorToIdArray(JSContext *cx, AutoIdVector &props, JSIdArray **idap); michael@0: michael@0: bool michael@0: GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleValue vp); michael@0: michael@0: JSObject * michael@0: GetIteratorObject(JSContext *cx, HandleObject obj, unsigned flags); michael@0: michael@0: bool michael@0: VectorToKeyIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props, michael@0: MutableHandleValue vp); michael@0: michael@0: bool michael@0: VectorToValueIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props, michael@0: MutableHandleValue vp); michael@0: michael@0: /* michael@0: * Creates either a key or value iterator, depending on flags. For a value michael@0: * iterator, performs value-lookup to convert the given list of jsids. michael@0: */ michael@0: bool michael@0: EnumeratedIdVectorToIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props, michael@0: MutableHandleValue vp); michael@0: michael@0: /* michael@0: * Convert the value stored in *vp to its iteration object. The flags should michael@0: * contain JSITER_ENUMERATE if js::ValueToIterator is called when enumerating michael@0: * for-in semantics are required, and when the caller can guarantee that the michael@0: * iterator will never be exposed to scripts. michael@0: */ michael@0: bool michael@0: ValueToIterator(JSContext *cx, unsigned flags, MutableHandleValue vp); michael@0: michael@0: bool michael@0: CloseIterator(JSContext *cx, HandleObject iterObj); michael@0: michael@0: bool michael@0: UnwindIteratorForException(JSContext *cx, js::HandleObject obj); michael@0: michael@0: void michael@0: UnwindIteratorForUncatchableException(JSContext *cx, JSObject *obj); michael@0: michael@0: bool michael@0: IteratorConstructor(JSContext *cx, unsigned argc, Value *vp); michael@0: michael@0: } /* namespace js */ michael@0: michael@0: extern bool michael@0: js_SuppressDeletedProperty(JSContext *cx, js::HandleObject obj, jsid id); michael@0: michael@0: extern bool michael@0: js_SuppressDeletedElement(JSContext *cx, js::HandleObject obj, uint32_t index); michael@0: michael@0: extern bool michael@0: js_SuppressDeletedElements(JSContext *cx, js::HandleObject obj, uint32_t begin, uint32_t end); michael@0: michael@0: /* michael@0: * IteratorMore() indicates whether another value is available. It might michael@0: * internally call iterobj.next() and then cache the value until its michael@0: * picked up by IteratorNext(). The value is cached in the current context. michael@0: */ michael@0: extern bool michael@0: js_IteratorMore(JSContext *cx, js::HandleObject iterobj, js::MutableHandleValue rval); michael@0: michael@0: extern bool michael@0: js_IteratorNext(JSContext *cx, js::HandleObject iterobj, js::MutableHandleValue rval); michael@0: michael@0: extern bool michael@0: js_ThrowStopIteration(JSContext *cx); michael@0: michael@0: namespace js { michael@0: michael@0: /* michael@0: * Create an object of the form { value: VALUE, done: DONE }. michael@0: * ES6 draft from 2013-09-05, section 25.4.3.4. michael@0: */ michael@0: extern JSObject * michael@0: CreateItrResultObject(JSContext *cx, js::HandleValue value, bool done); michael@0: michael@0: } /* namespace js */ michael@0: michael@0: /* michael@0: * Generator state codes. michael@0: */ michael@0: enum JSGeneratorState michael@0: { michael@0: JSGEN_NEWBORN, /* not yet started */ michael@0: JSGEN_OPEN, /* started by a .next() or .send(undefined) call */ michael@0: JSGEN_RUNNING, /* currently executing via .next(), etc., call */ michael@0: JSGEN_CLOSING, /* close method is doing asynchronous return */ michael@0: JSGEN_CLOSED /* closed, cannot be started or closed again */ michael@0: }; michael@0: michael@0: struct JSGenerator michael@0: { michael@0: js::HeapPtrObject obj; michael@0: JSGeneratorState state; michael@0: js::InterpreterRegs regs; michael@0: JSGenerator *prevGenerator; michael@0: js::InterpreterFrame *fp; michael@0: js::HeapValue stackSnapshot[1]; michael@0: }; michael@0: michael@0: extern JSObject * michael@0: js_NewGenerator(JSContext *cx, const js::InterpreterRegs ®s); michael@0: michael@0: extern JSObject * michael@0: js_InitIteratorClasses(JSContext *cx, js::HandleObject obj); michael@0: michael@0: #endif /* jsiter_h */