1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/. */
10 #include "vm/GlobalObject.h"
11 #include "vm/NativeObject.h"
17 template <typename Category
>
21 * The basic PICStub just has a pointer to the next stub.
23 template <typename Category
>
25 friend class PICChain
<Category
>;
28 using CatStub
= typename
Category::Stub
;
29 using CatChain
= typename
Category::Chain
;
34 PICStub() : next_(nullptr) {}
35 explicit PICStub(const CatStub
* next
) : next_(next
) { MOZ_ASSERT(next_
); }
36 explicit PICStub(const CatStub
& other
) : next_(other
.next_
) {}
39 CatStub
* next() const { return next_
; }
42 void append(CatStub
* stub
) {
44 MOZ_ASSERT(!stub
->next_
);
50 * The basic PIC just has a pointer to the list of stubs.
52 template <typename Category
>
55 using CatStub
= typename
Category::Stub
;
56 using CatChain
= typename
Category::Chain
;
61 PICChain() : stubs_(nullptr) {}
62 // PICs should never be copy constructed.
63 PICChain(const PICChain
<Category
>& other
) = delete;
66 CatStub
* stubs() const { return stubs_
; }
68 void addStub(JSObject
* obj
, CatStub
* stub
);
70 unsigned numStubs() const {
72 for (CatStub
* stub
= stubs_
; stub
; stub
= stub
->next()) {
79 // Class for object that holds ForOfPIC chain.
80 class ForOfPICObject
: public NativeObject
{
82 enum { ChainSlot
, SlotCount
};
84 static const JSClass class_
;
88 * ForOfPIC defines a PIC category for optimizing for-of operations.
91 /* Forward declarations so template-substitution works. */
96 ForOfPIC(const ForOfPIC
& other
) = delete;
98 using BaseStub
= PICStub
<ForOfPIC
>;
99 using BaseChain
= PICChain
<ForOfPIC
>;
102 * A ForOfPIC has only one kind of stub for now: one that holds the shape
103 * of an array object that does not override its @@iterator property.
105 class Stub
: public BaseStub
{
107 // Shape of matching array object.
108 const HeapPtr
<Shape
*> shape_
;
111 explicit Stub(Shape
* shape
) : shape_(shape
) { MOZ_ASSERT(shape_
); }
113 Shape
* shape() { return shape_
; }
115 void trace(JSTracer
* trc
);
119 * A ForOfPIC chain holds the following:
121 * Array.prototype (arrayProto_)
122 * To ensure that the incoming array has the standard proto.
124 * Array.prototype's shape (arrayProtoShape_)
125 * To ensure that Array.prototype has not been modified.
127 * ArrayIterator.prototype
128 * ArrayIterator.prototype's shape
129 * (arrayIteratorProto_, arrayIteratorProtoShape_)
130 * To ensure that an ArrayIterator.prototype has not been modified.
132 * Array.prototype's slot number for @@iterator
133 * Array.prototype's canonical value for @@iterator
134 * (arrayProtoIteratorSlot_, canonicalIteratorFunc_)
135 * To quickly retrieve and ensure that the iterator constructor
136 * stored in the slot has not changed.
138 * ArrayIterator.prototype's slot number for 'next'
139 * ArrayIterator.prototype's canonical value for 'next'
140 * (arrayIteratorProtoNextSlot_, canonicalNextFunc_)
141 * To quickly retrieve and ensure that the 'next' method for
142 * ArrayIterator objects has not changed.
144 class Chain
: public BaseChain
{
146 // Pointer to owning JSObject for memory accounting purposes.
147 const GCPtr
<JSObject
*> picObject_
;
149 // Pointer to canonical Array.prototype, ArrayIterator.prototype,
150 // Iterator.prototype, and Object.prototype
151 GCPtr
<NativeObject
*> arrayProto_
;
152 GCPtr
<NativeObject
*> arrayIteratorProto_
;
153 GCPtr
<NativeObject
*> iteratorProto_
;
154 GCPtr
<NativeObject
*> objectProto_
;
156 // Shape of matching Array.prototype object, and slot containing
157 // the @@iterator for it, and the canonical value.
158 GCPtr
<Shape
*> arrayProtoShape_
;
159 uint32_t arrayProtoIteratorSlot_
;
160 GCPtr
<Value
> canonicalIteratorFunc_
;
162 // Shape of matching ArrayIteratorProto, and slot containing
163 // the 'next' property, and the canonical value.
164 GCPtr
<Shape
*> arrayIteratorProtoShape_
;
165 uint32_t arrayIteratorProtoNextSlot_
;
166 GCPtr
<Value
> canonicalNextFunc_
;
168 // Shape of matching Iterator.prototype object.
169 GCPtr
<Shape
*> iteratorProtoShape_
;
170 // Shape of matching Object.prototype object.
171 GCPtr
<Shape
*> objectProtoShape_
;
173 // Initialization flag marking lazy initialization of above fields.
176 // Disabled flag is set when we don't want to try optimizing anymore
177 // because core objects were changed.
180 static const unsigned MAX_STUBS
= 10;
183 explicit Chain(JSObject
* picObject
)
184 : picObject_(picObject
),
185 arrayProto_(nullptr),
186 arrayIteratorProto_(nullptr),
187 arrayProtoShape_(nullptr),
188 arrayProtoIteratorSlot_(-1),
189 canonicalIteratorFunc_(UndefinedValue()),
190 arrayIteratorProtoShape_(nullptr),
191 arrayIteratorProtoNextSlot_(-1),
195 // Initialize the canonical iterator function.
196 bool initialize(JSContext
* cx
);
198 // Try to optimize this chain for a newly allocated array.
199 bool tryOptimizeArray(JSContext
* cx
, bool* optimized
);
201 // Try to optimize this chain for an object.
202 bool tryOptimizeArray(JSContext
* cx
, Handle
<ArrayObject
*> array
,
205 // Check if %ArrayIteratorPrototype% still uses the default "next" method.
206 bool tryOptimizeArrayIteratorNext(JSContext
* cx
, bool* optimized
);
208 void trace(JSTracer
* trc
);
209 void finalize(JS::GCContext
* gcx
, JSObject
* obj
);
211 void freeAllStubs(JS::GCContext
* gcx
);
214 // Check if the global array-related objects have not been messed with
215 // in a way that would disable this PIC.
216 bool isArrayStateStillSane();
218 // Check if ArrayIterator.next and ArrayIterator.return are still
220 inline bool isArrayIteratorStateStillSane() {
221 // Ensure the prototype chain is intact, which will ensure that "return"
222 // has not been defined.
223 if (arrayIteratorProto_
->shape() != arrayIteratorProtoShape_
) {
227 if (iteratorProto_
->shape() != iteratorProtoShape_
) {
231 if (objectProto_
->shape() != objectProtoShape_
) {
235 return arrayIteratorProto_
->getSlot(arrayIteratorProtoNextSlot_
) ==
239 // Check if a matching optimized stub for the given object exists.
240 bool hasMatchingStub(ArrayObject
* obj
);
242 // Reset the PIC and all info associated with it.
243 void reset(JSContext
* cx
);
245 // Erase the stub chain.
246 void eraseChain(JSContext
* cx
);
249 static NativeObject
* createForOfPICObject(JSContext
* cx
,
250 Handle
<GlobalObject
*> global
);
252 static inline Chain
* fromJSObject(NativeObject
* obj
) {
253 MOZ_ASSERT(obj
->is
<ForOfPICObject
>());
254 return obj
->maybePtrFromReservedSlot
<Chain
>(ForOfPICObject::ChainSlot
);
256 static inline Chain
* getOrCreate(JSContext
* cx
) {
257 NativeObject
* obj
= cx
->global()->getForOfPICObject();
259 return fromJSObject(obj
);
263 static Chain
* create(JSContext
* cx
);
268 #endif /* vm_PIC_h */