|
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 vm_PIC_h |
|
8 #define vm_PIC_h |
|
9 |
|
10 #include "jsapi.h" |
|
11 #include "jscntxt.h" |
|
12 #include "jsfriendapi.h" |
|
13 #include "jsobj.h" |
|
14 |
|
15 #include "gc/Barrier.h" |
|
16 #include "gc/Heap.h" |
|
17 #include "gc/Marking.h" |
|
18 |
|
19 #include "js/Value.h" |
|
20 #include "vm/GlobalObject.h" |
|
21 |
|
22 namespace js { |
|
23 |
|
24 class Shape; |
|
25 |
|
26 template <typename Category> class PICChain; |
|
27 |
|
28 /* |
|
29 * The basic PICStub just has a pointer to the next stub. |
|
30 */ |
|
31 template <typename Category> |
|
32 class PICStub |
|
33 { |
|
34 friend class PICChain<Category>; |
|
35 private: |
|
36 typedef typename Category::Stub CatStub; |
|
37 typedef typename Category::Chain CatChain; |
|
38 |
|
39 protected: |
|
40 CatStub *next_; |
|
41 |
|
42 PICStub() : next_(nullptr) {} |
|
43 PICStub(const CatStub *next) : next_(next) { |
|
44 JS_ASSERT(next_); |
|
45 } |
|
46 PICStub(const CatStub &other) : next_(other.next_) {} |
|
47 |
|
48 public: |
|
49 CatStub *next() const { |
|
50 return next_; |
|
51 } |
|
52 |
|
53 protected: |
|
54 void append(CatStub *stub) { |
|
55 JS_ASSERT(!next_); |
|
56 JS_ASSERT(!stub->next_); |
|
57 next_ = stub; |
|
58 } |
|
59 }; |
|
60 |
|
61 /* |
|
62 * The basic PIC just has a pointer to the list of stubs. |
|
63 */ |
|
64 template <typename Category> |
|
65 class PICChain |
|
66 { |
|
67 private: |
|
68 typedef typename Category::Stub CatStub; |
|
69 typedef typename Category::Chain CatChain; |
|
70 |
|
71 protected: |
|
72 CatStub *stubs_; |
|
73 |
|
74 PICChain() : stubs_(nullptr) {} |
|
75 // PICs should never be copy constructed. |
|
76 PICChain(const PICChain<Category> &other) MOZ_DELETE; |
|
77 |
|
78 public: |
|
79 CatStub *stubs() const { |
|
80 return stubs_; |
|
81 } |
|
82 |
|
83 void addStub(CatStub *stub) { |
|
84 JS_ASSERT(stub); |
|
85 JS_ASSERT(!stub->next()); |
|
86 if (!stubs_) { |
|
87 stubs_ = stub; |
|
88 return; |
|
89 } |
|
90 |
|
91 CatStub *cur = stubs_; |
|
92 while (cur->next()) |
|
93 cur = cur->next(); |
|
94 cur->append(stub); |
|
95 } |
|
96 |
|
97 unsigned numStubs() const { |
|
98 unsigned count = 0; |
|
99 for (CatStub *stub = stubs_; stub; stub = stub->next()) |
|
100 count++; |
|
101 return count; |
|
102 } |
|
103 |
|
104 void removeStub(CatStub *stub, CatStub *previous) { |
|
105 if (previous) { |
|
106 JS_ASSERT(previous->next() == stub); |
|
107 previous->next_ = stub->next(); |
|
108 } else { |
|
109 JS_ASSERT(stub == stubs_); |
|
110 stubs_ = stub->next(); |
|
111 } |
|
112 js_delete(stub); |
|
113 } |
|
114 }; |
|
115 |
|
116 /* |
|
117 * ForOfPIC defines a PIC category for optimizing for-of operations. |
|
118 */ |
|
119 struct ForOfPIC |
|
120 { |
|
121 /* Forward declarations so template-substitution works. */ |
|
122 class Stub; |
|
123 class Chain; |
|
124 |
|
125 ForOfPIC() MOZ_DELETE; |
|
126 ForOfPIC(const ForOfPIC &other) MOZ_DELETE; |
|
127 |
|
128 typedef PICStub<ForOfPIC> BaseStub; |
|
129 typedef PICChain<ForOfPIC> BaseChain; |
|
130 |
|
131 /* |
|
132 * A ForOfPIC has only one kind of stub for now: one that holds the shape |
|
133 * of an array object that does not override its '@@iterator' property. |
|
134 */ |
|
135 class Stub : public BaseStub |
|
136 { |
|
137 private: |
|
138 // Shape of matching array object. |
|
139 Shape *shape_; |
|
140 |
|
141 public: |
|
142 Stub(Shape *shape) |
|
143 : BaseStub(), |
|
144 shape_(shape) |
|
145 { |
|
146 JS_ASSERT(shape_); |
|
147 } |
|
148 |
|
149 Shape *shape() { |
|
150 return shape_; |
|
151 } |
|
152 }; |
|
153 |
|
154 /* |
|
155 * A ForOfPIC chain holds the following: |
|
156 * |
|
157 * Array.prototype (arrayProto_) |
|
158 * To ensure that the incoming array has the standard proto. |
|
159 * |
|
160 * Array.prototype's shape (arrayProtoShape_) |
|
161 * To ensure that Array.prototype has not been modified. |
|
162 * |
|
163 * ArrayIterator.prototype (arrayIteratorProto_) |
|
164 * ArrayIterator.prototype's shape (arrayIteratorProtoShape_) |
|
165 * To ensure that an ArrayIterator.prototype has not been modified. |
|
166 * |
|
167 * Array.prototype's slot number for '@@iterator' (arrayProtoIteratorSlot_) |
|
168 * Array.prototype's canonical value for '@@iterator' (canonicalIteratorFunc_) |
|
169 * To quickly retreive and ensure that the iterator constructor |
|
170 * stored in the slot has not changed. |
|
171 * |
|
172 * ArrayIterator.prototype's slot number for 'next' (arrayIteratorProtoNextSlot_) |
|
173 * ArrayIterator.prototype's canonical value for 'next' (canonicalNextFunc_) |
|
174 * To quickly retreive and ensure that the 'next' method for ArrayIterator |
|
175 * objects has not changed. |
|
176 */ |
|
177 class Chain : public BaseChain |
|
178 { |
|
179 private: |
|
180 // Pointer to canonical Array.prototype and ArrayIterator.prototype |
|
181 HeapPtrObject arrayProto_; |
|
182 HeapPtrObject arrayIteratorProto_; |
|
183 |
|
184 // Shape of matching Array.prototype object, and slot containing |
|
185 // the '@@iterator' for it, and the canonical value. |
|
186 HeapPtrShape arrayProtoShape_; |
|
187 uint32_t arrayProtoIteratorSlot_; |
|
188 HeapValue canonicalIteratorFunc_; |
|
189 |
|
190 // Shape of matching ArrayIteratorProto, and slot containing |
|
191 // the 'next' property, and the canonical value. |
|
192 HeapPtrShape arrayIteratorProtoShape_; |
|
193 uint32_t arrayIteratorProtoNextSlot_; |
|
194 HeapValue canonicalNextFunc_; |
|
195 |
|
196 // Initialization flag marking lazy initialization of above fields. |
|
197 bool initialized_; |
|
198 |
|
199 // Disabled flag is set when we don't want to try optimizing anymore |
|
200 // because core objects were changed. |
|
201 bool disabled_; |
|
202 |
|
203 static const unsigned MAX_STUBS = 10; |
|
204 |
|
205 public: |
|
206 Chain() |
|
207 : BaseChain(), |
|
208 arrayProto_(nullptr), |
|
209 arrayIteratorProto_(nullptr), |
|
210 arrayProtoShape_(nullptr), |
|
211 arrayProtoIteratorSlot_(-1), |
|
212 canonicalIteratorFunc_(UndefinedValue()), |
|
213 arrayIteratorProtoShape_(nullptr), |
|
214 arrayIteratorProtoNextSlot_(-1), |
|
215 initialized_(false), |
|
216 disabled_(false) |
|
217 {} |
|
218 |
|
219 // Initialize the canonical iterator function. |
|
220 bool initialize(JSContext *cx); |
|
221 |
|
222 // Check if a given array object is optimized by this PIC. |
|
223 Stub *isArrayOptimized(ArrayObject *obj); |
|
224 |
|
225 // Try to optimize this chain for an object. |
|
226 bool tryOptimizeArray(JSContext *cx, HandleObject array, bool *optimized); |
|
227 |
|
228 // Check if the global array-related objects have not been messed with |
|
229 // in a way that would disable this PIC. |
|
230 bool isArrayStateStillSane(); |
|
231 |
|
232 // Check if ArrayIterator.next is still optimizable. |
|
233 inline bool isArrayNextStillSane() { |
|
234 return (arrayIteratorProto_->lastProperty() == arrayIteratorProtoShape_) && |
|
235 (arrayIteratorProto_->getSlot(arrayIteratorProtoNextSlot_) == canonicalNextFunc_); |
|
236 } |
|
237 |
|
238 void mark(JSTracer *trc); |
|
239 void sweep(FreeOp *fop); |
|
240 |
|
241 private: |
|
242 // Get a matching optimized stub for the given object. |
|
243 Stub *getMatchingStub(JSObject *obj); |
|
244 |
|
245 // Check if the given object is for-of optimizable with this PIC. |
|
246 bool isOptimizableArray(JSObject *obj); |
|
247 |
|
248 // Reset the PIC and all info associated with it. |
|
249 void reset(JSContext *cx); |
|
250 |
|
251 // Erase the stub chain. |
|
252 void eraseChain(); |
|
253 }; |
|
254 |
|
255 // Class for object that holds ForOfPIC chain. |
|
256 static const Class jsclass; |
|
257 |
|
258 static JSObject *createForOfPICObject(JSContext *cx, Handle<GlobalObject *> global); |
|
259 |
|
260 static inline Chain *fromJSObject(JSObject *obj) { |
|
261 JS_ASSERT(js::GetObjectClass(obj) == &ForOfPIC::jsclass); |
|
262 return (ForOfPIC::Chain *) obj->getPrivate(); |
|
263 } |
|
264 static inline Chain *getOrCreate(JSContext *cx) { |
|
265 JSObject *obj = cx->global()->getForOfPICObject(); |
|
266 if (obj) |
|
267 return fromJSObject(obj); |
|
268 return create(cx); |
|
269 } |
|
270 static Chain *create(JSContext *cx); |
|
271 }; |
|
272 |
|
273 |
|
274 } // namespace js |
|
275 |
|
276 #endif /* vm_PIC_h */ |