1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/PIC.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,276 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef vm_PIC_h 1.11 +#define vm_PIC_h 1.12 + 1.13 +#include "jsapi.h" 1.14 +#include "jscntxt.h" 1.15 +#include "jsfriendapi.h" 1.16 +#include "jsobj.h" 1.17 + 1.18 +#include "gc/Barrier.h" 1.19 +#include "gc/Heap.h" 1.20 +#include "gc/Marking.h" 1.21 + 1.22 +#include "js/Value.h" 1.23 +#include "vm/GlobalObject.h" 1.24 + 1.25 +namespace js { 1.26 + 1.27 +class Shape; 1.28 + 1.29 +template <typename Category> class PICChain; 1.30 + 1.31 +/* 1.32 + * The basic PICStub just has a pointer to the next stub. 1.33 + */ 1.34 +template <typename Category> 1.35 +class PICStub 1.36 +{ 1.37 + friend class PICChain<Category>; 1.38 + private: 1.39 + typedef typename Category::Stub CatStub; 1.40 + typedef typename Category::Chain CatChain; 1.41 + 1.42 + protected: 1.43 + CatStub *next_; 1.44 + 1.45 + PICStub() : next_(nullptr) {} 1.46 + PICStub(const CatStub *next) : next_(next) { 1.47 + JS_ASSERT(next_); 1.48 + } 1.49 + PICStub(const CatStub &other) : next_(other.next_) {} 1.50 + 1.51 + public: 1.52 + CatStub *next() const { 1.53 + return next_; 1.54 + } 1.55 + 1.56 + protected: 1.57 + void append(CatStub *stub) { 1.58 + JS_ASSERT(!next_); 1.59 + JS_ASSERT(!stub->next_); 1.60 + next_ = stub; 1.61 + } 1.62 +}; 1.63 + 1.64 +/* 1.65 + * The basic PIC just has a pointer to the list of stubs. 1.66 + */ 1.67 +template <typename Category> 1.68 +class PICChain 1.69 +{ 1.70 + private: 1.71 + typedef typename Category::Stub CatStub; 1.72 + typedef typename Category::Chain CatChain; 1.73 + 1.74 + protected: 1.75 + CatStub *stubs_; 1.76 + 1.77 + PICChain() : stubs_(nullptr) {} 1.78 + // PICs should never be copy constructed. 1.79 + PICChain(const PICChain<Category> &other) MOZ_DELETE; 1.80 + 1.81 + public: 1.82 + CatStub *stubs() const { 1.83 + return stubs_; 1.84 + } 1.85 + 1.86 + void addStub(CatStub *stub) { 1.87 + JS_ASSERT(stub); 1.88 + JS_ASSERT(!stub->next()); 1.89 + if (!stubs_) { 1.90 + stubs_ = stub; 1.91 + return; 1.92 + } 1.93 + 1.94 + CatStub *cur = stubs_; 1.95 + while (cur->next()) 1.96 + cur = cur->next(); 1.97 + cur->append(stub); 1.98 + } 1.99 + 1.100 + unsigned numStubs() const { 1.101 + unsigned count = 0; 1.102 + for (CatStub *stub = stubs_; stub; stub = stub->next()) 1.103 + count++; 1.104 + return count; 1.105 + } 1.106 + 1.107 + void removeStub(CatStub *stub, CatStub *previous) { 1.108 + if (previous) { 1.109 + JS_ASSERT(previous->next() == stub); 1.110 + previous->next_ = stub->next(); 1.111 + } else { 1.112 + JS_ASSERT(stub == stubs_); 1.113 + stubs_ = stub->next(); 1.114 + } 1.115 + js_delete(stub); 1.116 + } 1.117 +}; 1.118 + 1.119 +/* 1.120 + * ForOfPIC defines a PIC category for optimizing for-of operations. 1.121 + */ 1.122 +struct ForOfPIC 1.123 +{ 1.124 + /* Forward declarations so template-substitution works. */ 1.125 + class Stub; 1.126 + class Chain; 1.127 + 1.128 + ForOfPIC() MOZ_DELETE; 1.129 + ForOfPIC(const ForOfPIC &other) MOZ_DELETE; 1.130 + 1.131 + typedef PICStub<ForOfPIC> BaseStub; 1.132 + typedef PICChain<ForOfPIC> BaseChain; 1.133 + 1.134 + /* 1.135 + * A ForOfPIC has only one kind of stub for now: one that holds the shape 1.136 + * of an array object that does not override its '@@iterator' property. 1.137 + */ 1.138 + class Stub : public BaseStub 1.139 + { 1.140 + private: 1.141 + // Shape of matching array object. 1.142 + Shape *shape_; 1.143 + 1.144 + public: 1.145 + Stub(Shape *shape) 1.146 + : BaseStub(), 1.147 + shape_(shape) 1.148 + { 1.149 + JS_ASSERT(shape_); 1.150 + } 1.151 + 1.152 + Shape *shape() { 1.153 + return shape_; 1.154 + } 1.155 + }; 1.156 + 1.157 + /* 1.158 + * A ForOfPIC chain holds the following: 1.159 + * 1.160 + * Array.prototype (arrayProto_) 1.161 + * To ensure that the incoming array has the standard proto. 1.162 + * 1.163 + * Array.prototype's shape (arrayProtoShape_) 1.164 + * To ensure that Array.prototype has not been modified. 1.165 + * 1.166 + * ArrayIterator.prototype (arrayIteratorProto_) 1.167 + * ArrayIterator.prototype's shape (arrayIteratorProtoShape_) 1.168 + * To ensure that an ArrayIterator.prototype has not been modified. 1.169 + * 1.170 + * Array.prototype's slot number for '@@iterator' (arrayProtoIteratorSlot_) 1.171 + * Array.prototype's canonical value for '@@iterator' (canonicalIteratorFunc_) 1.172 + * To quickly retreive and ensure that the iterator constructor 1.173 + * stored in the slot has not changed. 1.174 + * 1.175 + * ArrayIterator.prototype's slot number for 'next' (arrayIteratorProtoNextSlot_) 1.176 + * ArrayIterator.prototype's canonical value for 'next' (canonicalNextFunc_) 1.177 + * To quickly retreive and ensure that the 'next' method for ArrayIterator 1.178 + * objects has not changed. 1.179 + */ 1.180 + class Chain : public BaseChain 1.181 + { 1.182 + private: 1.183 + // Pointer to canonical Array.prototype and ArrayIterator.prototype 1.184 + HeapPtrObject arrayProto_; 1.185 + HeapPtrObject arrayIteratorProto_; 1.186 + 1.187 + // Shape of matching Array.prototype object, and slot containing 1.188 + // the '@@iterator' for it, and the canonical value. 1.189 + HeapPtrShape arrayProtoShape_; 1.190 + uint32_t arrayProtoIteratorSlot_; 1.191 + HeapValue canonicalIteratorFunc_; 1.192 + 1.193 + // Shape of matching ArrayIteratorProto, and slot containing 1.194 + // the 'next' property, and the canonical value. 1.195 + HeapPtrShape arrayIteratorProtoShape_; 1.196 + uint32_t arrayIteratorProtoNextSlot_; 1.197 + HeapValue canonicalNextFunc_; 1.198 + 1.199 + // Initialization flag marking lazy initialization of above fields. 1.200 + bool initialized_; 1.201 + 1.202 + // Disabled flag is set when we don't want to try optimizing anymore 1.203 + // because core objects were changed. 1.204 + bool disabled_; 1.205 + 1.206 + static const unsigned MAX_STUBS = 10; 1.207 + 1.208 + public: 1.209 + Chain() 1.210 + : BaseChain(), 1.211 + arrayProto_(nullptr), 1.212 + arrayIteratorProto_(nullptr), 1.213 + arrayProtoShape_(nullptr), 1.214 + arrayProtoIteratorSlot_(-1), 1.215 + canonicalIteratorFunc_(UndefinedValue()), 1.216 + arrayIteratorProtoShape_(nullptr), 1.217 + arrayIteratorProtoNextSlot_(-1), 1.218 + initialized_(false), 1.219 + disabled_(false) 1.220 + {} 1.221 + 1.222 + // Initialize the canonical iterator function. 1.223 + bool initialize(JSContext *cx); 1.224 + 1.225 + // Check if a given array object is optimized by this PIC. 1.226 + Stub *isArrayOptimized(ArrayObject *obj); 1.227 + 1.228 + // Try to optimize this chain for an object. 1.229 + bool tryOptimizeArray(JSContext *cx, HandleObject array, bool *optimized); 1.230 + 1.231 + // Check if the global array-related objects have not been messed with 1.232 + // in a way that would disable this PIC. 1.233 + bool isArrayStateStillSane(); 1.234 + 1.235 + // Check if ArrayIterator.next is still optimizable. 1.236 + inline bool isArrayNextStillSane() { 1.237 + return (arrayIteratorProto_->lastProperty() == arrayIteratorProtoShape_) && 1.238 + (arrayIteratorProto_->getSlot(arrayIteratorProtoNextSlot_) == canonicalNextFunc_); 1.239 + } 1.240 + 1.241 + void mark(JSTracer *trc); 1.242 + void sweep(FreeOp *fop); 1.243 + 1.244 + private: 1.245 + // Get a matching optimized stub for the given object. 1.246 + Stub *getMatchingStub(JSObject *obj); 1.247 + 1.248 + // Check if the given object is for-of optimizable with this PIC. 1.249 + bool isOptimizableArray(JSObject *obj); 1.250 + 1.251 + // Reset the PIC and all info associated with it. 1.252 + void reset(JSContext *cx); 1.253 + 1.254 + // Erase the stub chain. 1.255 + void eraseChain(); 1.256 + }; 1.257 + 1.258 + // Class for object that holds ForOfPIC chain. 1.259 + static const Class jsclass; 1.260 + 1.261 + static JSObject *createForOfPICObject(JSContext *cx, Handle<GlobalObject *> global); 1.262 + 1.263 + static inline Chain *fromJSObject(JSObject *obj) { 1.264 + JS_ASSERT(js::GetObjectClass(obj) == &ForOfPIC::jsclass); 1.265 + return (ForOfPIC::Chain *) obj->getPrivate(); 1.266 + } 1.267 + static inline Chain *getOrCreate(JSContext *cx) { 1.268 + JSObject *obj = cx->global()->getForOfPICObject(); 1.269 + if (obj) 1.270 + return fromJSObject(obj); 1.271 + return create(cx); 1.272 + } 1.273 + static Chain *create(JSContext *cx); 1.274 +}; 1.275 + 1.276 + 1.277 +} // namespace js 1.278 + 1.279 +#endif /* vm_PIC_h */