|
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/Stack.h" |
|
20 |
|
21 /* |
|
22 * For cacheable native iterators, whether the iterator is currently active. |
|
23 * Not serialized by XDR. |
|
24 */ |
|
25 #define JSITER_ACTIVE 0x1000 |
|
26 #define JSITER_UNREUSABLE 0x2000 |
|
27 |
|
28 namespace js { |
|
29 |
|
30 struct NativeIterator |
|
31 { |
|
32 HeapPtrObject obj; // Object being iterated. |
|
33 JSObject *iterObj_; // Internal iterator object. |
|
34 HeapPtr<JSFlatString> *props_array; |
|
35 HeapPtr<JSFlatString> *props_cursor; |
|
36 HeapPtr<JSFlatString> *props_end; |
|
37 Shape **shapes_array; |
|
38 uint32_t shapes_length; |
|
39 uint32_t shapes_key; |
|
40 uint32_t flags; |
|
41 |
|
42 private: |
|
43 /* While in compartment->enumerators, these form a doubly linked list. */ |
|
44 NativeIterator *next_; |
|
45 NativeIterator *prev_; |
|
46 |
|
47 public: |
|
48 bool isKeyIter() const { |
|
49 return (flags & JSITER_FOREACH) == 0; |
|
50 } |
|
51 |
|
52 inline HeapPtr<JSFlatString> *begin() const { |
|
53 return props_array; |
|
54 } |
|
55 |
|
56 inline HeapPtr<JSFlatString> *end() const { |
|
57 return props_end; |
|
58 } |
|
59 |
|
60 size_t numKeys() const { |
|
61 return end() - begin(); |
|
62 } |
|
63 |
|
64 JSObject *iterObj() const { |
|
65 return iterObj_; |
|
66 } |
|
67 HeapPtr<JSFlatString> *current() const { |
|
68 JS_ASSERT(props_cursor < props_end); |
|
69 return props_cursor; |
|
70 } |
|
71 |
|
72 NativeIterator *next() { |
|
73 return next_; |
|
74 } |
|
75 |
|
76 static inline size_t offsetOfNext() { |
|
77 return offsetof(NativeIterator, next_); |
|
78 } |
|
79 static inline size_t offsetOfPrev() { |
|
80 return offsetof(NativeIterator, prev_); |
|
81 } |
|
82 |
|
83 void incCursor() { |
|
84 props_cursor = props_cursor + 1; |
|
85 } |
|
86 void link(NativeIterator *other) { |
|
87 /* A NativeIterator cannot appear in the enumerator list twice. */ |
|
88 JS_ASSERT(!next_ && !prev_); |
|
89 JS_ASSERT(flags & JSITER_ENUMERATE); |
|
90 |
|
91 this->next_ = other; |
|
92 this->prev_ = other->prev_; |
|
93 other->prev_->next_ = this; |
|
94 other->prev_ = this; |
|
95 } |
|
96 void unlink() { |
|
97 JS_ASSERT(flags & JSITER_ENUMERATE); |
|
98 |
|
99 next_->prev_ = prev_; |
|
100 prev_->next_ = next_; |
|
101 next_ = nullptr; |
|
102 prev_ = nullptr; |
|
103 } |
|
104 |
|
105 static NativeIterator *allocateSentinel(JSContext *cx); |
|
106 static NativeIterator *allocateIterator(JSContext *cx, uint32_t slength, |
|
107 const js::AutoIdVector &props); |
|
108 void init(JSObject *obj, JSObject *iterObj, unsigned flags, uint32_t slength, uint32_t key); |
|
109 |
|
110 void mark(JSTracer *trc); |
|
111 |
|
112 static void destroy(NativeIterator *iter) { |
|
113 js_free(iter); |
|
114 } |
|
115 }; |
|
116 |
|
117 class PropertyIteratorObject : public JSObject |
|
118 { |
|
119 public: |
|
120 static const Class class_; |
|
121 |
|
122 NativeIterator *getNativeIterator() const { |
|
123 return static_cast<js::NativeIterator *>(getPrivate()); |
|
124 } |
|
125 void setNativeIterator(js::NativeIterator *ni) { |
|
126 setPrivate(ni); |
|
127 } |
|
128 |
|
129 size_t sizeOfMisc(mozilla::MallocSizeOf mallocSizeOf) const; |
|
130 |
|
131 private: |
|
132 static void trace(JSTracer *trc, JSObject *obj); |
|
133 static void finalize(FreeOp *fop, JSObject *obj); |
|
134 }; |
|
135 |
|
136 class ArrayIteratorObject : public JSObject |
|
137 { |
|
138 public: |
|
139 static const Class class_; |
|
140 }; |
|
141 |
|
142 class StringIteratorObject : public JSObject |
|
143 { |
|
144 public: |
|
145 static const Class class_; |
|
146 }; |
|
147 |
|
148 bool |
|
149 VectorToIdArray(JSContext *cx, AutoIdVector &props, JSIdArray **idap); |
|
150 |
|
151 bool |
|
152 GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleValue vp); |
|
153 |
|
154 JSObject * |
|
155 GetIteratorObject(JSContext *cx, HandleObject obj, unsigned flags); |
|
156 |
|
157 bool |
|
158 VectorToKeyIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props, |
|
159 MutableHandleValue vp); |
|
160 |
|
161 bool |
|
162 VectorToValueIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props, |
|
163 MutableHandleValue vp); |
|
164 |
|
165 /* |
|
166 * Creates either a key or value iterator, depending on flags. For a value |
|
167 * iterator, performs value-lookup to convert the given list of jsids. |
|
168 */ |
|
169 bool |
|
170 EnumeratedIdVectorToIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props, |
|
171 MutableHandleValue vp); |
|
172 |
|
173 /* |
|
174 * Convert the value stored in *vp to its iteration object. The flags should |
|
175 * contain JSITER_ENUMERATE if js::ValueToIterator is called when enumerating |
|
176 * for-in semantics are required, and when the caller can guarantee that the |
|
177 * iterator will never be exposed to scripts. |
|
178 */ |
|
179 bool |
|
180 ValueToIterator(JSContext *cx, unsigned flags, MutableHandleValue vp); |
|
181 |
|
182 bool |
|
183 CloseIterator(JSContext *cx, HandleObject iterObj); |
|
184 |
|
185 bool |
|
186 UnwindIteratorForException(JSContext *cx, js::HandleObject obj); |
|
187 |
|
188 void |
|
189 UnwindIteratorForUncatchableException(JSContext *cx, JSObject *obj); |
|
190 |
|
191 bool |
|
192 IteratorConstructor(JSContext *cx, unsigned argc, Value *vp); |
|
193 |
|
194 } /* namespace js */ |
|
195 |
|
196 extern bool |
|
197 js_SuppressDeletedProperty(JSContext *cx, js::HandleObject obj, jsid id); |
|
198 |
|
199 extern bool |
|
200 js_SuppressDeletedElement(JSContext *cx, js::HandleObject obj, uint32_t index); |
|
201 |
|
202 extern bool |
|
203 js_SuppressDeletedElements(JSContext *cx, js::HandleObject obj, uint32_t begin, uint32_t end); |
|
204 |
|
205 /* |
|
206 * IteratorMore() indicates whether another value is available. It might |
|
207 * internally call iterobj.next() and then cache the value until its |
|
208 * picked up by IteratorNext(). The value is cached in the current context. |
|
209 */ |
|
210 extern bool |
|
211 js_IteratorMore(JSContext *cx, js::HandleObject iterobj, js::MutableHandleValue rval); |
|
212 |
|
213 extern bool |
|
214 js_IteratorNext(JSContext *cx, js::HandleObject iterobj, js::MutableHandleValue rval); |
|
215 |
|
216 extern bool |
|
217 js_ThrowStopIteration(JSContext *cx); |
|
218 |
|
219 namespace js { |
|
220 |
|
221 /* |
|
222 * Create an object of the form { value: VALUE, done: DONE }. |
|
223 * ES6 draft from 2013-09-05, section 25.4.3.4. |
|
224 */ |
|
225 extern JSObject * |
|
226 CreateItrResultObject(JSContext *cx, js::HandleValue value, bool done); |
|
227 |
|
228 } /* namespace js */ |
|
229 |
|
230 /* |
|
231 * Generator state codes. |
|
232 */ |
|
233 enum JSGeneratorState |
|
234 { |
|
235 JSGEN_NEWBORN, /* not yet started */ |
|
236 JSGEN_OPEN, /* started by a .next() or .send(undefined) call */ |
|
237 JSGEN_RUNNING, /* currently executing via .next(), etc., call */ |
|
238 JSGEN_CLOSING, /* close method is doing asynchronous return */ |
|
239 JSGEN_CLOSED /* closed, cannot be started or closed again */ |
|
240 }; |
|
241 |
|
242 struct JSGenerator |
|
243 { |
|
244 js::HeapPtrObject obj; |
|
245 JSGeneratorState state; |
|
246 js::InterpreterRegs regs; |
|
247 JSGenerator *prevGenerator; |
|
248 js::InterpreterFrame *fp; |
|
249 js::HeapValue stackSnapshot[1]; |
|
250 }; |
|
251 |
|
252 extern JSObject * |
|
253 js_NewGenerator(JSContext *cx, const js::InterpreterRegs ®s); |
|
254 |
|
255 extern JSObject * |
|
256 js_InitIteratorClasses(JSContext *cx, js::HandleObject obj); |
|
257 |
|
258 #endif /* jsiter_h */ |