Bug 1885337 - Part 1: Implement to/from hex methods. r=dminor
[gecko.git] / js / src / vm / PIC.h
blob4f1258dd58a6d0b0bc17b9402c85232108103890
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/. */
7 #ifndef vm_PIC_h
8 #define vm_PIC_h
10 #include "vm/GlobalObject.h"
11 #include "vm/NativeObject.h"
13 namespace js {
15 class Shape;
17 template <typename Category>
18 class PICChain;
21 * The basic PICStub just has a pointer to the next stub.
23 template <typename Category>
24 class PICStub {
25 friend class PICChain<Category>;
27 private:
28 using CatStub = typename Category::Stub;
29 using CatChain = typename Category::Chain;
31 protected:
32 CatStub* next_;
34 PICStub() : next_(nullptr) {}
35 explicit PICStub(const CatStub* next) : next_(next) { MOZ_ASSERT(next_); }
36 explicit PICStub(const CatStub& other) : next_(other.next_) {}
38 public:
39 CatStub* next() const { return next_; }
41 protected:
42 void append(CatStub* stub) {
43 MOZ_ASSERT(!next_);
44 MOZ_ASSERT(!stub->next_);
45 next_ = stub;
50 * The basic PIC just has a pointer to the list of stubs.
52 template <typename Category>
53 class PICChain {
54 private:
55 using CatStub = typename Category::Stub;
56 using CatChain = typename Category::Chain;
58 protected:
59 CatStub* stubs_;
61 PICChain() : stubs_(nullptr) {}
62 // PICs should never be copy constructed.
63 PICChain(const PICChain<Category>& other) = delete;
65 public:
66 CatStub* stubs() const { return stubs_; }
68 void addStub(JSObject* obj, CatStub* stub);
70 unsigned numStubs() const {
71 unsigned count = 0;
72 for (CatStub* stub = stubs_; stub; stub = stub->next()) {
73 count++;
75 return count;
79 // Class for object that holds ForOfPIC chain.
80 class ForOfPICObject : public NativeObject {
81 public:
82 enum { ChainSlot, SlotCount };
84 static const JSClass class_;
88 * ForOfPIC defines a PIC category for optimizing for-of operations.
90 struct ForOfPIC {
91 /* Forward declarations so template-substitution works. */
92 class Stub;
93 class Chain;
95 ForOfPIC() = delete;
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 {
106 private:
107 // Shape of matching array object.
108 const HeapPtr<Shape*> shape_;
110 public:
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 {
145 private:
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.
174 bool initialized_;
176 // Disabled flag is set when we don't want to try optimizing anymore
177 // because core objects were changed.
178 bool disabled_;
180 static const unsigned MAX_STUBS = 10;
182 public:
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),
192 initialized_(false),
193 disabled_(false) {}
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,
203 bool* optimized);
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);
213 private:
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
219 // optimizable.
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_) {
224 return false;
227 if (iteratorProto_->shape() != iteratorProtoShape_) {
228 return false;
231 if (objectProto_->shape() != objectProtoShape_) {
232 return false;
235 return arrayIteratorProto_->getSlot(arrayIteratorProtoNextSlot_) ==
236 canonicalNextFunc_;
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();
258 if (obj) {
259 return fromJSObject(obj);
261 return create(cx);
263 static Chain* create(JSContext* cx);
266 } // namespace js
268 #endif /* vm_PIC_h */