summaryrefslogtreecommitdiffstats
path: root/js/src/vm/PIC.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm/PIC.h')
-rw-r--r--js/src/vm/PIC.h276
1 files changed, 276 insertions, 0 deletions
diff --git a/js/src/vm/PIC.h b/js/src/vm/PIC.h
new file mode 100644
index 000000000..a24321514
--- /dev/null
+++ b/js/src/vm/PIC.h
@@ -0,0 +1,276 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_PIC_h
+#define vm_PIC_h
+
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jsfriendapi.h"
+#include "jsobj.h"
+
+#include "gc/Barrier.h"
+#include "gc/Heap.h"
+#include "gc/Marking.h"
+
+#include "js/Value.h"
+#include "vm/GlobalObject.h"
+
+namespace js {
+
+class Shape;
+
+template <typename Category> class PICChain;
+
+/*
+ * The basic PICStub just has a pointer to the next stub.
+ */
+template <typename Category>
+class PICStub
+{
+ friend class PICChain<Category>;
+ private:
+ typedef typename Category::Stub CatStub;
+ typedef typename Category::Chain CatChain;
+
+ protected:
+ CatStub* next_;
+
+ PICStub() : next_(nullptr) {}
+ explicit PICStub(const CatStub* next) : next_(next) {
+ MOZ_ASSERT(next_);
+ }
+ explicit PICStub(const CatStub& other) : next_(other.next_) {}
+
+ public:
+ CatStub* next() const {
+ return next_;
+ }
+
+ protected:
+ void append(CatStub* stub) {
+ MOZ_ASSERT(!next_);
+ MOZ_ASSERT(!stub->next_);
+ next_ = stub;
+ }
+};
+
+/*
+ * The basic PIC just has a pointer to the list of stubs.
+ */
+template <typename Category>
+class PICChain
+{
+ private:
+ typedef typename Category::Stub CatStub;
+ typedef typename Category::Chain CatChain;
+
+ protected:
+ CatStub* stubs_;
+
+ PICChain() : stubs_(nullptr) {}
+ // PICs should never be copy constructed.
+ PICChain(const PICChain<Category>& other) = delete;
+
+ public:
+ CatStub* stubs() const {
+ return stubs_;
+ }
+
+ void addStub(CatStub* stub) {
+ MOZ_ASSERT(stub);
+ MOZ_ASSERT(!stub->next());
+ if (!stubs_) {
+ stubs_ = stub;
+ return;
+ }
+
+ CatStub* cur = stubs_;
+ while (cur->next())
+ cur = cur->next();
+ cur->append(stub);
+ }
+
+ unsigned numStubs() const {
+ unsigned count = 0;
+ for (CatStub* stub = stubs_; stub; stub = stub->next())
+ count++;
+ return count;
+ }
+
+ void removeStub(CatStub* stub, CatStub* previous) {
+ if (previous) {
+ MOZ_ASSERT(previous->next() == stub);
+ previous->next_ = stub->next();
+ } else {
+ MOZ_ASSERT(stub == stubs_);
+ stubs_ = stub->next();
+ }
+ js_delete(stub);
+ }
+};
+
+/*
+ * ForOfPIC defines a PIC category for optimizing for-of operations.
+ */
+struct ForOfPIC
+{
+ /* Forward declarations so template-substitution works. */
+ class Stub;
+ class Chain;
+
+ ForOfPIC() = delete;
+ ForOfPIC(const ForOfPIC& other) = delete;
+
+ typedef PICStub<ForOfPIC> BaseStub;
+ typedef PICChain<ForOfPIC> BaseChain;
+
+ /*
+ * A ForOfPIC has only one kind of stub for now: one that holds the shape
+ * of an array object that does not override its @@iterator property.
+ */
+ class Stub : public BaseStub
+ {
+ private:
+ // Shape of matching array object.
+ Shape* shape_;
+
+ public:
+ explicit Stub(Shape* shape)
+ : BaseStub(),
+ shape_(shape)
+ {
+ MOZ_ASSERT(shape_);
+ }
+
+ Shape* shape() {
+ return shape_;
+ }
+ };
+
+ /*
+ * A ForOfPIC chain holds the following:
+ *
+ * Array.prototype (arrayProto_)
+ * To ensure that the incoming array has the standard proto.
+ *
+ * Array.prototype's shape (arrayProtoShape_)
+ * To ensure that Array.prototype has not been modified.
+ *
+ * ArrayIterator.prototype (arrayIteratorProto_)
+ * ArrayIterator.prototype's shape (arrayIteratorProtoShape_)
+ * To ensure that an ArrayIterator.prototype has not been modified.
+ *
+ * Array.prototype's slot number for @@iterator (arrayProtoIteratorSlot_)
+ * Array.prototype's canonical value for @@iterator (canonicalIteratorFunc_)
+ * To quickly retrieve and ensure that the iterator constructor
+ * stored in the slot has not changed.
+ *
+ * ArrayIterator.prototype's slot number for 'next' (arrayIteratorProtoNextSlot_)
+ * ArrayIterator.prototype's canonical value for 'next' (canonicalNextFunc_)
+ * To quickly retrieve and ensure that the 'next' method for ArrayIterator
+ * objects has not changed.
+ */
+ class Chain : public BaseChain
+ {
+ private:
+ // Pointer to canonical Array.prototype and ArrayIterator.prototype
+ GCPtrNativeObject arrayProto_;
+ GCPtrNativeObject arrayIteratorProto_;
+
+ // Shape of matching Array.prototype object, and slot containing
+ // the @@iterator for it, and the canonical value.
+ GCPtrShape arrayProtoShape_;
+ uint32_t arrayProtoIteratorSlot_;
+ GCPtrValue canonicalIteratorFunc_;
+
+ // Shape of matching ArrayIteratorProto, and slot containing
+ // the 'next' property, and the canonical value.
+ GCPtrShape arrayIteratorProtoShape_;
+ uint32_t arrayIteratorProtoNextSlot_;
+ GCPtrValue canonicalNextFunc_;
+
+ // Initialization flag marking lazy initialization of above fields.
+ bool initialized_;
+
+ // Disabled flag is set when we don't want to try optimizing anymore
+ // because core objects were changed.
+ bool disabled_;
+
+ static const unsigned MAX_STUBS = 10;
+
+ public:
+ Chain()
+ : BaseChain(),
+ arrayProto_(nullptr),
+ arrayIteratorProto_(nullptr),
+ arrayProtoShape_(nullptr),
+ arrayProtoIteratorSlot_(-1),
+ canonicalIteratorFunc_(UndefinedValue()),
+ arrayIteratorProtoShape_(nullptr),
+ arrayIteratorProtoNextSlot_(-1),
+ initialized_(false),
+ disabled_(false)
+ {}
+
+ // Initialize the canonical iterator function.
+ bool initialize(JSContext* cx);
+
+ // Check if a given array object is optimized by this PIC.
+ Stub* isArrayOptimized(ArrayObject* obj);
+
+ // Try to optimize this chain for an object.
+ bool tryOptimizeArray(JSContext* cx, HandleArrayObject array, bool* optimized);
+
+ // Check if the global array-related objects have not been messed with
+ // in a way that would disable this PIC.
+ bool isArrayStateStillSane();
+
+ // Check if ArrayIterator.next is still optimizable.
+ inline bool isArrayNextStillSane() {
+ return (arrayIteratorProto_->lastProperty() == arrayIteratorProtoShape_) &&
+ (arrayIteratorProto_->getSlot(arrayIteratorProtoNextSlot_) == canonicalNextFunc_);
+ }
+
+ void mark(JSTracer* trc);
+ void sweep(FreeOp* fop);
+
+ private:
+ // Get a matching optimized stub for the given object.
+ Stub* getMatchingStub(JSObject* obj);
+
+ // Check if the given object is for-of optimizable with this PIC.
+ bool isOptimizableArray(JSObject* obj);
+
+ // Reset the PIC and all info associated with it.
+ void reset(JSContext* cx);
+
+ // Erase the stub chain.
+ void eraseChain();
+ };
+
+ // Class for object that holds ForOfPIC chain.
+ static const Class class_;
+
+ static NativeObject* createForOfPICObject(JSContext* cx, Handle<GlobalObject*> global);
+
+ static inline Chain* fromJSObject(NativeObject* obj) {
+ MOZ_ASSERT(js::GetObjectClass(obj) == &ForOfPIC::class_);
+ return (ForOfPIC::Chain*) obj->getPrivate();
+ }
+ static inline Chain* getOrCreate(JSContext* cx) {
+ NativeObject* obj = cx->global()->getForOfPICObject();
+ if (obj)
+ return fromJSObject(obj);
+ return create(cx);
+ }
+ static Chain* create(JSContext* cx);
+};
+
+
+} // namespace js
+
+#endif /* vm_PIC_h */