Line data Source code
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 18 : PICStub() : next_(nullptr) {}
43 : explicit PICStub(const CatStub* next) : next_(next) {
44 : MOZ_ASSERT(next_);
45 : }
46 : explicit PICStub(const CatStub& other) : next_(other.next_) {}
47 :
48 : public:
49 18 : CatStub* next() const {
50 18 : return next_;
51 : }
52 :
53 : protected:
54 0 : void append(CatStub* stub) {
55 0 : MOZ_ASSERT(!next_);
56 0 : MOZ_ASSERT(!stub->next_);
57 0 : next_ = stub;
58 0 : }
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 18 : PICChain() : stubs_(nullptr) {}
75 : // PICs should never be copy constructed.
76 : PICChain(const PICChain<Category>& other) = delete;
77 :
78 : public:
79 55 : CatStub* stubs() const {
80 55 : return stubs_;
81 : }
82 :
83 18 : void addStub(CatStub* stub) {
84 18 : MOZ_ASSERT(stub);
85 18 : MOZ_ASSERT(!stub->next());
86 18 : if (!stubs_) {
87 18 : stubs_ = stub;
88 18 : return;
89 : }
90 :
91 0 : CatStub* cur = stubs_;
92 0 : while (cur->next())
93 0 : cur = cur->next();
94 0 : cur->append(stub);
95 : }
96 :
97 18 : unsigned numStubs() const {
98 18 : unsigned count = 0;
99 18 : for (CatStub* stub = stubs_; stub; stub = stub->next())
100 0 : count++;
101 18 : return count;
102 : }
103 :
104 0 : void removeStub(CatStub* stub, CatStub* previous) {
105 0 : if (previous) {
106 0 : MOZ_ASSERT(previous->next() == stub);
107 0 : previous->next_ = stub->next();
108 : } else {
109 0 : MOZ_ASSERT(stub == stubs_);
110 0 : stubs_ = stub->next();
111 : }
112 0 : js_delete(stub);
113 0 : }
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() = delete;
126 : ForOfPIC(const ForOfPIC& other) = 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 18 : explicit Stub(Shape* shape)
143 18 : : BaseStub(),
144 18 : shape_(shape)
145 : {
146 18 : MOZ_ASSERT(shape_);
147 18 : }
148 :
149 37 : Shape* shape() {
150 37 : 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 retrieve 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 retrieve and ensure that the 'next' method for ArrayIterator
175 : * objects has not changed.
176 : */
177 0 : class Chain : public BaseChain
178 : {
179 : private:
180 : // Pointer to canonical Array.prototype and ArrayIterator.prototype
181 : GCPtrNativeObject arrayProto_;
182 : GCPtrNativeObject arrayIteratorProto_;
183 :
184 : // Shape of matching Array.prototype object, and slot containing
185 : // the @@iterator for it, and the canonical value.
186 : GCPtrShape arrayProtoShape_;
187 : uint32_t arrayProtoIteratorSlot_;
188 : GCPtrValue canonicalIteratorFunc_;
189 :
190 : // Shape of matching ArrayIteratorProto, and slot containing
191 : // the 'next' property, and the canonical value.
192 : GCPtrShape arrayIteratorProtoShape_;
193 : uint32_t arrayIteratorProtoNextSlot_;
194 : GCPtrValue 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 18 : Chain()
207 18 : : BaseChain(),
208 : arrayProto_(nullptr),
209 : arrayIteratorProto_(nullptr),
210 : arrayProtoShape_(nullptr),
211 : arrayProtoIteratorSlot_(-1),
212 36 : canonicalIteratorFunc_(UndefinedValue()),
213 : arrayIteratorProtoShape_(nullptr),
214 : arrayIteratorProtoNextSlot_(-1),
215 : initialized_(false),
216 54 : disabled_(false)
217 18 : {}
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, HandleArrayObject 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 137 : inline bool isArrayNextStillSane() {
234 548 : return (arrayIteratorProto_->lastProperty() == arrayIteratorProtoShape_) &&
235 411 : (arrayIteratorProto_->getSlot(arrayIteratorProtoNextSlot_) == canonicalNextFunc_);
236 : }
237 :
238 : void trace(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 class_;
257 :
258 : static NativeObject* createForOfPICObject(JSContext* cx, Handle<GlobalObject*> global);
259 :
260 63 : static inline Chain* fromJSObject(NativeObject* obj) {
261 63 : MOZ_ASSERT(js::GetObjectClass(obj) == &ForOfPIC::class_);
262 63 : return (ForOfPIC::Chain*) obj->getPrivate();
263 : }
264 63 : static inline Chain* getOrCreate(JSContext* cx) {
265 63 : NativeObject* obj = cx->global()->getForOfPICObject();
266 63 : if (obj)
267 45 : return fromJSObject(obj);
268 18 : return create(cx);
269 : }
270 : static Chain* create(JSContext* cx);
271 : };
272 :
273 :
274 : } // namespace js
275 :
276 : #endif /* vm_PIC_h */
|