mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-06-01 17:41:34 +00:00
277 lines
7.8 KiB
C++
277 lines
7.8 KiB
C++
/* -*- 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
|
|
HeapPtrNativeObject arrayProto_;
|
|
HeapPtrNativeObject arrayIteratorProto_;
|
|
|
|
// Shape of matching Array.prototype object, and slot containing
|
|
// the @@iterator for it, and the canonical value.
|
|
HeapPtrShape arrayProtoShape_;
|
|
uint32_t arrayProtoIteratorSlot_;
|
|
HeapValue canonicalIteratorFunc_;
|
|
|
|
// Shape of matching ArrayIteratorProto, and slot containing
|
|
// the 'next' property, and the canonical value.
|
|
HeapPtrShape arrayIteratorProtoShape_;
|
|
uint32_t arrayIteratorProtoNextSlot_;
|
|
HeapValue 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 jsclass;
|
|
|
|
static NativeObject* createForOfPICObject(JSContext* cx, Handle<GlobalObject*> global);
|
|
|
|
static inline Chain* fromJSObject(NativeObject* obj) {
|
|
MOZ_ASSERT(js::GetObjectClass(obj) == &ForOfPIC::jsclass);
|
|
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 */
|