1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * vim: set ts=8 sts=4 et sw=4 tw=99: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jsiter_h 8 #define jsiter_h 9 10 /* 11 * JavaScript iterators. 12 */ 13 14 #include "mozilla/MemoryReporting.h" 15 16 #include "jscntxt.h" 17 18 #include "gc/Barrier.h" 19 #include "vm/ReceiverGuard.h" 20 #include "vm/Stack.h" 21 22 /* 23 * For cacheable native iterators, whether the iterator is currently active. 24 * Not serialized by XDR. 25 */ 26 #define JSITER_ACTIVE 0x1000 27 #define JSITER_UNREUSABLE 0x2000 28 29 namespace js { 30 31 struct NativeIterator 32 { 33 HeapPtrObject obj; // Object being iterated. 34 JSObject* iterObj_; // Internal iterator object. 35 HeapPtrFlatString* props_array; 36 HeapPtrFlatString* props_cursor; 37 HeapPtrFlatString* props_end; 38 HeapReceiverGuard* guard_array; 39 uint32_t guard_length; 40 uint32_t guard_key; 41 uint32_t flags; 42 43 private: 44 /* While in compartment->enumerators, these form a doubly linked list. */ 45 NativeIterator* next_; 46 NativeIterator* prev_; 47 48 public: isKeyIterNativeIterator49 bool isKeyIter() const { 50 return (flags & JSITER_FOREACH) == 0; 51 } 52 beginNativeIterator53 inline HeapPtrFlatString* begin() const { 54 return props_array; 55 } 56 endNativeIterator57 inline HeapPtrFlatString* end() const { 58 return props_end; 59 } 60 numKeysNativeIterator61 size_t numKeys() const { 62 return end() - begin(); 63 } 64 iterObjNativeIterator65 JSObject* iterObj() const { 66 return iterObj_; 67 } currentNativeIterator68 HeapPtrFlatString* current() const { 69 MOZ_ASSERT(props_cursor < props_end); 70 return props_cursor; 71 } 72 nextNativeIterator73 NativeIterator* next() { 74 return next_; 75 } 76 offsetOfNextNativeIterator77 static inline size_t offsetOfNext() { 78 return offsetof(NativeIterator, next_); 79 } offsetOfPrevNativeIterator80 static inline size_t offsetOfPrev() { 81 return offsetof(NativeIterator, prev_); 82 } 83 incCursorNativeIterator84 void incCursor() { 85 props_cursor = props_cursor + 1; 86 } linkNativeIterator87 void link(NativeIterator* other) { 88 /* A NativeIterator cannot appear in the enumerator list twice. */ 89 MOZ_ASSERT(!next_ && !prev_); 90 MOZ_ASSERT(flags & JSITER_ENUMERATE); 91 92 this->next_ = other; 93 this->prev_ = other->prev_; 94 other->prev_->next_ = this; 95 other->prev_ = this; 96 } unlinkNativeIterator97 void unlink() { 98 MOZ_ASSERT(flags & JSITER_ENUMERATE); 99 100 next_->prev_ = prev_; 101 prev_->next_ = next_; 102 next_ = nullptr; 103 prev_ = nullptr; 104 } 105 106 static NativeIterator* allocateSentinel(JSContext* maybecx); 107 static NativeIterator* allocateIterator(JSContext* cx, uint32_t slength, 108 const js::AutoIdVector& props); 109 void init(JSObject* obj, JSObject* iterObj, unsigned flags, uint32_t slength, uint32_t key); 110 111 void mark(JSTracer* trc); 112 destroyNativeIterator113 static void destroy(NativeIterator* iter) { 114 js_free(iter); 115 } 116 }; 117 118 class PropertyIteratorObject : public NativeObject 119 { 120 public: 121 static const Class class_; 122 getNativeIterator()123 NativeIterator* getNativeIterator() const { 124 return static_cast<js::NativeIterator*>(getPrivate()); 125 } setNativeIterator(js::NativeIterator * ni)126 void setNativeIterator(js::NativeIterator* ni) { 127 setPrivate(ni); 128 } 129 130 size_t sizeOfMisc(mozilla::MallocSizeOf mallocSizeOf) const; 131 132 private: 133 static void trace(JSTracer* trc, JSObject* obj); 134 static void finalize(FreeOp* fop, JSObject* obj); 135 }; 136 137 class ArrayIteratorObject : public JSObject 138 { 139 public: 140 static const Class class_; 141 }; 142 143 class StringIteratorObject : public JSObject 144 { 145 public: 146 static const Class class_; 147 }; 148 149 class ListIteratorObject : public JSObject 150 { 151 public: 152 static const Class class_; 153 }; 154 155 bool 156 GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleObject objp); 157 158 JSObject* 159 GetIteratorObject(JSContext* cx, HandleObject obj, unsigned flags); 160 161 /* 162 * Creates either a key or value iterator, depending on flags. For a value 163 * iterator, performs value-lookup to convert the given list of jsids. 164 */ 165 bool 166 EnumeratedIdVectorToIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVector& props, 167 MutableHandleObject objp); 168 169 bool 170 NewEmptyPropertyIterator(JSContext* cx, unsigned flags, MutableHandleObject objp); 171 172 /* 173 * Convert the value stored in *vp to its iteration object. The flags should 174 * contain JSITER_ENUMERATE if js::ValueToIterator is called when enumerating 175 * for-in semantics are required, and when the caller can guarantee that the 176 * iterator will never be exposed to scripts. 177 */ 178 bool 179 ValueToIterator(JSContext* cx, unsigned flags, MutableHandleValue vp); 180 181 bool 182 CloseIterator(JSContext* cx, HandleObject iterObj); 183 184 bool 185 UnwindIteratorForException(JSContext* cx, HandleObject obj); 186 187 void 188 UnwindIteratorForUncatchableException(JSContext* cx, JSObject* obj); 189 190 bool 191 IteratorConstructor(JSContext* cx, unsigned argc, Value* vp); 192 193 extern bool 194 SuppressDeletedProperty(JSContext* cx, HandleObject obj, jsid id); 195 196 extern bool 197 SuppressDeletedElement(JSContext* cx, HandleObject obj, uint32_t index); 198 199 /* 200 * IteratorMore() returns the next iteration value. If no value is available, 201 * MagicValue(JS_NO_ITER_VALUE) is returned. 202 */ 203 extern bool 204 IteratorMore(JSContext* cx, HandleObject iterobj, MutableHandleValue rval); 205 206 extern bool 207 ThrowStopIteration(JSContext* cx); 208 209 /* 210 * Create an object of the form { value: VALUE, done: DONE }. 211 * ES6 draft from 2013-09-05, section 25.4.3.4. 212 */ 213 extern JSObject* 214 CreateItrResultObject(JSContext* cx, HandleValue value, bool done); 215 216 extern JSObject* 217 InitLegacyIteratorClass(JSContext* cx, HandleObject obj); 218 219 extern JSObject* 220 InitStopIterationClass(JSContext* cx, HandleObject obj); 221 222 } /* namespace js */ 223 224 #endif /* jsiter_h */ 225