Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
7 #ifndef vm_PIC_h
8 #define vm_PIC_h
10 #include "jsapi.h"
11 #include "jscntxt.h"
12 #include "jsfriendapi.h"
13 #include "jsobj.h"
15 #include "gc/Barrier.h"
16 #include "gc/Heap.h"
17 #include "gc/Marking.h"
19 #include "js/Value.h"
20 #include "vm/GlobalObject.h"
22 namespace js {
24 class Shape;
26 template <typename Category> class PICChain;
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;
39 protected:
40 CatStub *next_;
42 PICStub() : next_(nullptr) {}
43 PICStub(const CatStub *next) : next_(next) {
44 JS_ASSERT(next_);
45 }
46 PICStub(const CatStub &other) : next_(other.next_) {}
48 public:
49 CatStub *next() const {
50 return next_;
51 }
53 protected:
54 void append(CatStub *stub) {
55 JS_ASSERT(!next_);
56 JS_ASSERT(!stub->next_);
57 next_ = stub;
58 }
59 };
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;
71 protected:
72 CatStub *stubs_;
74 PICChain() : stubs_(nullptr) {}
75 // PICs should never be copy constructed.
76 PICChain(const PICChain<Category> &other) MOZ_DELETE;
78 public:
79 CatStub *stubs() const {
80 return stubs_;
81 }
83 void addStub(CatStub *stub) {
84 JS_ASSERT(stub);
85 JS_ASSERT(!stub->next());
86 if (!stubs_) {
87 stubs_ = stub;
88 return;
89 }
91 CatStub *cur = stubs_;
92 while (cur->next())
93 cur = cur->next();
94 cur->append(stub);
95 }
97 unsigned numStubs() const {
98 unsigned count = 0;
99 for (CatStub *stub = stubs_; stub; stub = stub->next())
100 count++;
101 return count;
102 }
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 };
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;
125 ForOfPIC() MOZ_DELETE;
126 ForOfPIC(const ForOfPIC &other) MOZ_DELETE;
128 typedef PICStub<ForOfPIC> BaseStub;
129 typedef PICChain<ForOfPIC> BaseChain;
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_;
141 public:
142 Stub(Shape *shape)
143 : BaseStub(),
144 shape_(shape)
145 {
146 JS_ASSERT(shape_);
147 }
149 Shape *shape() {
150 return shape_;
151 }
152 };
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_;
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_;
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_;
196 // Initialization flag marking lazy initialization of above fields.
197 bool initialized_;
199 // Disabled flag is set when we don't want to try optimizing anymore
200 // because core objects were changed.
201 bool disabled_;
203 static const unsigned MAX_STUBS = 10;
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 {}
219 // Initialize the canonical iterator function.
220 bool initialize(JSContext *cx);
222 // Check if a given array object is optimized by this PIC.
223 Stub *isArrayOptimized(ArrayObject *obj);
225 // Try to optimize this chain for an object.
226 bool tryOptimizeArray(JSContext *cx, HandleObject array, bool *optimized);
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();
232 // Check if ArrayIterator.next is still optimizable.
233 inline bool isArrayNextStillSane() {
234 return (arrayIteratorProto_->lastProperty() == arrayIteratorProtoShape_) &&
235 (arrayIteratorProto_->getSlot(arrayIteratorProtoNextSlot_) == canonicalNextFunc_);
236 }
238 void mark(JSTracer *trc);
239 void sweep(FreeOp *fop);
241 private:
242 // Get a matching optimized stub for the given object.
243 Stub *getMatchingStub(JSObject *obj);
245 // Check if the given object is for-of optimizable with this PIC.
246 bool isOptimizableArray(JSObject *obj);
248 // Reset the PIC and all info associated with it.
249 void reset(JSContext *cx);
251 // Erase the stub chain.
252 void eraseChain();
253 };
255 // Class for object that holds ForOfPIC chain.
256 static const Class jsclass;
258 static JSObject *createForOfPICObject(JSContext *cx, Handle<GlobalObject *> global);
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 };
274 } // namespace js
276 #endif /* vm_PIC_h */