зеркало из https://github.com/mozilla/gecko-dev.git
Move fixed slot count from JSObject to Shape, bug 594561.
This commit is contained in:
Родитель
83de21de11
Коммит
52d3c3bbb6
|
@ -282,7 +282,7 @@ JSObject::willBeSparseDenseArray(uintN requiredCapacity, uintN newElementsHint)
|
|||
uintN cap = getDenseArrayCapacity();
|
||||
JS_ASSERT(requiredCapacity >= cap);
|
||||
|
||||
if (requiredCapacity >= JSObject::NSLOTS_LIMIT)
|
||||
if (requiredCapacity >= JSObject::NELEMENTS_LIMIT)
|
||||
return true;
|
||||
|
||||
uintN minimalDenseCount = requiredCapacity / 4;
|
||||
|
@ -3491,6 +3491,7 @@ NewArray(JSContext *cx, jsuint length, JSObject *proto)
|
|||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
obj->initDenseArray();
|
||||
obj->setArrayLength(cx, length);
|
||||
|
||||
if (allocateCapacity && !obj->ensureElements(cx, length))
|
||||
|
|
|
@ -489,7 +489,7 @@ struct JS_FRIEND_API(JSCompartment) {
|
|||
|
||||
struct BaseShapeEntry {
|
||||
js::UnownedBaseShape *base;
|
||||
js::Shape *shape;
|
||||
js::ShapeKindArray *shapes;
|
||||
|
||||
typedef const js::BaseShape *Lookup;
|
||||
|
||||
|
|
|
@ -185,19 +185,21 @@ struct BaseShape {
|
|||
|
||||
struct Shape {
|
||||
BaseShape *base;
|
||||
jsid _1;
|
||||
uint32 slotInfo;
|
||||
|
||||
static const uint32 FIXED_SLOTS_SHIFT = 27;
|
||||
};
|
||||
|
||||
struct Object {
|
||||
Shape *shape;
|
||||
TypeObject *type;
|
||||
uint32 flags;
|
||||
uint32 _1;
|
||||
uint32 _2;
|
||||
js::Value *slots;
|
||||
js::Value *_1;
|
||||
js::Value *_3;
|
||||
|
||||
static const uint32 FIXED_SLOTS_SHIFT = 27;
|
||||
|
||||
size_t numFixedSlots() const { return flags >> FIXED_SLOTS_SHIFT; }
|
||||
size_t numFixedSlots() const { return shape->slotInfo >> Shape::FIXED_SLOTS_SHIFT; }
|
||||
Value *fixedSlots() const {
|
||||
return (Value *)((jsuword) this + sizeof(shadow::Object));
|
||||
}
|
||||
|
|
|
@ -205,7 +205,8 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
|
|||
|
||||
bool strict = callee.toFunction()->inStrictMode();
|
||||
Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass;
|
||||
Shape *emptyArgumentsShape = BaseShape::lookupInitialShape(cx, clasp, proto->getParent());
|
||||
Shape *emptyArgumentsShape = BaseShape::lookupInitialShape(cx, clasp, proto->getParent(),
|
||||
FINALIZE_OBJECT4);
|
||||
if (!emptyArgumentsShape)
|
||||
return NULL;
|
||||
|
||||
|
@ -216,7 +217,7 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
|
|||
SetValueRangeToUndefined(data->slots, argc);
|
||||
|
||||
/* Can't fail from here on, so initialize everything in argsobj. */
|
||||
obj->init(cx, type, false);
|
||||
obj->init(cx, type);
|
||||
obj->setInitialPropertyInfallible(emptyArgumentsShape);
|
||||
|
||||
ArgumentsObject *argsobj = obj->asArguments();
|
||||
|
@ -772,10 +773,11 @@ NewDeclEnvObject(JSContext *cx, StackFrame *fp)
|
|||
return NULL;
|
||||
|
||||
JSObject *parent = fp->scopeChain().getGlobal();
|
||||
Shape *emptyDeclEnvShape = BaseShape::lookupInitialShape(cx, &DeclEnvClass, parent);
|
||||
Shape *emptyDeclEnvShape = BaseShape::lookupInitialShape(cx, &DeclEnvClass, parent,
|
||||
FINALIZE_OBJECT2);
|
||||
if (!emptyDeclEnvShape)
|
||||
return NULL;
|
||||
envobj->init(cx, type, false);
|
||||
envobj->init(cx, type);
|
||||
envobj->setInitialPropertyInfallible(emptyDeclEnvShape);
|
||||
envobj->setPrivate(fp);
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ GetGCArrayKind(size_t numSlots)
|
|||
* unused.
|
||||
*/
|
||||
JS_STATIC_ASSERT(sizeof(ObjectElements) == 2 * sizeof(Value));
|
||||
if (numSlots > JSObject::NSLOTS_LIMIT || numSlots + 2 >= SLOTS_TO_THING_KIND_LIMIT)
|
||||
if (numSlots > JSObject::NELEMENTS_LIMIT || numSlots + 2 >= SLOTS_TO_THING_KIND_LIMIT)
|
||||
return FINALIZE_OBJECT2;
|
||||
return slotsToThingKind[numSlots + 2];
|
||||
}
|
||||
|
@ -174,6 +174,17 @@ GetGCKindSlots(AllocKind thingKind)
|
|||
}
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
GetGCKindSlots(AllocKind thingKind, Class *clasp)
|
||||
{
|
||||
size_t nslots = GetGCKindSlots(thingKind);
|
||||
if (clasp->flags & JSCLASS_HAS_PRIVATE) {
|
||||
JS_ASSERT(nslots > 0);
|
||||
nslots--;
|
||||
}
|
||||
return nslots;
|
||||
}
|
||||
|
||||
static inline void
|
||||
GCPoke(JSContext *cx, Value oldval)
|
||||
{
|
||||
|
@ -384,7 +395,7 @@ js_NewGCObject(JSContext *cx, js::gc::AllocKind kind)
|
|||
JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_FUNCTION);
|
||||
JSObject *obj = NewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
|
||||
if (obj)
|
||||
obj->earlyInit(js::gc::GetGCKindSlots(kind));
|
||||
obj->earlyInit();
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
|
@ -900,9 +900,10 @@ ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
|
|||
}
|
||||
|
||||
if (type->emptyShapes) {
|
||||
for (size_t i = 0; i < TYPE_OBJECT_EMPTY_SHAPE_COUNT; i++) {
|
||||
if (type->emptyShapes[i])
|
||||
PushMarkStack(gcmarker, type->emptyShapes[i]);
|
||||
for (unsigned i = 0; i < ShapeKindArray::SHAPE_COUNT; i++) {
|
||||
Shape *shape = type->emptyShapes->getIndex(i);
|
||||
if (shape)
|
||||
PushMarkStack(gcmarker, shape);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -939,9 +940,10 @@ MarkChildren(JSTracer *trc, types::TypeObject *type)
|
|||
}
|
||||
|
||||
if (type->emptyShapes) {
|
||||
for (size_t i = 0; i < TYPE_OBJECT_EMPTY_SHAPE_COUNT; i++) {
|
||||
if (type->emptyShapes[i])
|
||||
MarkShape(trc, type->emptyShapes[i], "empty_shape");
|
||||
for (unsigned i = 0; i < ShapeKindArray::SHAPE_COUNT; i++) {
|
||||
Shape *shape = type->emptyShapes->getIndex(i);
|
||||
if (shape)
|
||||
MarkShape(trc, shape, "empty_shape");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -719,7 +719,7 @@ struct TypeObject : gc::Cell
|
|||
JSObject *singleton;
|
||||
|
||||
/* Lazily filled array of empty shapes for each size of objects with this type. */
|
||||
js::EmptyShape **emptyShapes;
|
||||
js::ShapeKindArray *emptyShapes;
|
||||
|
||||
/* Flags for this object. */
|
||||
TypeObjectFlags flags;
|
||||
|
|
|
@ -413,11 +413,12 @@ NewIteratorObject(JSContext *cx, uintN flags)
|
|||
if (!type)
|
||||
return NULL;
|
||||
|
||||
Shape *emptyEnumeratorShape = BaseShape::lookupInitialShape(cx, &IteratorClass, NULL);
|
||||
Shape *emptyEnumeratorShape = BaseShape::lookupInitialShape(cx, &IteratorClass, NULL,
|
||||
FINALIZE_OBJECT2);
|
||||
if (!emptyEnumeratorShape)
|
||||
return NULL;
|
||||
|
||||
obj->init(cx, type, false);
|
||||
obj->init(cx, type);
|
||||
obj->setInitialPropertyInfallible(emptyEnumeratorShape);
|
||||
|
||||
JS_ASSERT(obj->numFixedSlots() == JSObject::ITER_CLASS_NFIXED_SLOTS);
|
||||
|
|
139
js/src/jsobj.cpp
139
js/src/jsobj.cpp
|
@ -3463,9 +3463,11 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
|
|||
|
||||
StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
|
||||
|
||||
obj->init(cx, type, false);
|
||||
obj->init(cx, type);
|
||||
|
||||
Shape *emptyWithShape = BaseShape::lookupInitialShape(cx, &WithClass, parent->getGlobal());
|
||||
Shape *emptyWithShape = BaseShape::lookupInitialShape(cx, &WithClass,
|
||||
parent->getGlobal(),
|
||||
FINALIZE_OBJECT4);
|
||||
if (!emptyWithShape)
|
||||
return NULL;
|
||||
|
||||
|
@ -3501,11 +3503,12 @@ js_NewBlockObject(JSContext *cx)
|
|||
if (!type)
|
||||
return NULL;
|
||||
|
||||
Shape *emptyBlockShape = BaseShape::lookupInitialShape(cx, &BlockClass, NULL);
|
||||
Shape *emptyBlockShape = BaseShape::lookupInitialShape(cx, &BlockClass, NULL,
|
||||
FINALIZE_OBJECT4);
|
||||
if (!emptyBlockShape)
|
||||
return NULL;
|
||||
|
||||
blockObj->init(cx, type, false);
|
||||
blockObj->init(cx, type);
|
||||
blockObj->setInitialPropertyInfallible(emptyBlockShape);
|
||||
|
||||
return blockObj;
|
||||
|
@ -3519,13 +3522,12 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, StackFrame *fp)
|
|||
JS_ASSERT(proto->isStaticBlock());
|
||||
|
||||
size_t count = OBJ_BLOCK_COUNT(cx, proto);
|
||||
gc::AllocKind kind = gc::GetGCObjectKind(count + BLOCK_RESERVED_SLOTS + 1);
|
||||
|
||||
TypeObject *type = proto->getNewType(cx);
|
||||
if (!type)
|
||||
return NULL;
|
||||
|
||||
JSObject *clone = js_NewGCObject(cx, kind);
|
||||
JSObject *clone = js_NewGCObject(cx, FINALIZE_OBJECT4);
|
||||
if (!clone)
|
||||
return NULL;
|
||||
|
||||
|
@ -3772,12 +3774,15 @@ struct JSObject::TradeGutsReserved {
|
|||
Vector<Value> bvals;
|
||||
int newafixed;
|
||||
int newbfixed;
|
||||
Shape *newashape;
|
||||
Shape *newbshape;
|
||||
Value *newaslots;
|
||||
Value *newbslots;
|
||||
|
||||
TradeGutsReserved(JSContext *cx)
|
||||
: cx(cx), avals(cx), bvals(cx),
|
||||
newafixed(0), newbfixed(0),
|
||||
newashape(NULL), newbshape(NULL),
|
||||
newaslots(NULL), newbslots(NULL)
|
||||
{}
|
||||
|
||||
|
@ -3800,18 +3805,33 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
|
|||
* swaps can be performed infallibly.
|
||||
*/
|
||||
|
||||
if (a->structSize() == b->structSize() && a->hasPrivate() == b->hasPrivate())
|
||||
if (a->structSize() == b->structSize())
|
||||
return true;
|
||||
|
||||
/*
|
||||
* If either object is native, it needs a new shape to preserve the
|
||||
* invariant that objects with the same shape have the same number of
|
||||
* inline slots.
|
||||
* inline slots. The fixed slots will be updated in place during TradeGuts.
|
||||
* Non-native objects need to be reshaped according to the new count.
|
||||
*/
|
||||
if (a->isNative() && !a->generateOwnShape(cx))
|
||||
return false;
|
||||
if (b->isNative() && !b->generateOwnShape(cx))
|
||||
return false;
|
||||
if (a->isNative()) {
|
||||
if (!a->generateOwnShape(cx))
|
||||
return false;
|
||||
} else {
|
||||
reserved.newbshape = BaseShape::lookupInitialShape(cx, a->getClass(), a->getParent(),
|
||||
b->getAllocKind());
|
||||
if (!reserved.newbshape)
|
||||
return false;
|
||||
}
|
||||
if (b->isNative()) {
|
||||
if (!b->generateOwnShape(cx))
|
||||
return false;
|
||||
} else {
|
||||
reserved.newashape = BaseShape::lookupInitialShape(cx, b->getClass(), b->getParent(),
|
||||
a->getAllocKind());
|
||||
if (!reserved.newashape)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The avals/bvals vectors hold all original values from the objects. */
|
||||
|
||||
|
@ -3869,12 +3889,6 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JSObject::updateFixedSlots(uintN fixed)
|
||||
{
|
||||
flags = (flags & ~FIXED_SLOTS_MASK) | (fixed << FIXED_SLOTS_SHIFT);
|
||||
}
|
||||
|
||||
void
|
||||
JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &reserved)
|
||||
{
|
||||
|
@ -3900,7 +3914,7 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
|
|||
|
||||
/* Trade the guts of the objects. */
|
||||
const size_t size = a->structSize();
|
||||
if (size == b->structSize() && a->hasPrivate() == b->hasPrivate()) {
|
||||
if (size == b->structSize()) {
|
||||
/*
|
||||
* If the objects are the same size, then we make no assumptions about
|
||||
* whether they have dynamically allocated slots and instead just copy
|
||||
|
@ -3942,13 +3956,21 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
|
|||
memcpy(a, b, sizeof tmp);
|
||||
memcpy(b, &tmp, sizeof tmp);
|
||||
|
||||
a->updateFixedSlots(reserved.newafixed);
|
||||
if (a->isNative())
|
||||
a->shape_->setNumFixedSlots(reserved.newafixed);
|
||||
else
|
||||
a->shape_ = reserved.newashape;
|
||||
|
||||
a->slots = reserved.newaslots;
|
||||
a->copySlotRange(0, reserved.bvals.begin(), bcap);
|
||||
if (a->hasPrivate())
|
||||
a->setPrivate(bpriv);
|
||||
|
||||
b->updateFixedSlots(reserved.newbfixed);
|
||||
if (b->isNative())
|
||||
b->shape_->setNumFixedSlots(reserved.newbfixed);
|
||||
else
|
||||
b->shape_ = reserved.newbshape;
|
||||
|
||||
b->slots = reserved.newbslots;
|
||||
b->copySlotRange(0, reserved.avals.begin(), acap);
|
||||
if (b->hasPrivate())
|
||||
|
@ -4521,18 +4543,23 @@ JSObject::updateSlotsForSpan(size_t oldSpan, size_t newSpan)
|
|||
invalidateSlotRange(newSpan, oldSpan - newSpan);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::initializePrivate()
|
||||
#ifdef DEBUG
|
||||
size_t
|
||||
JSObject::numFixedSlotsFromAllocationKind(Class *clasp) const
|
||||
{
|
||||
size_t nfixed = numFixedSlots();
|
||||
JS_ASSERT(nfixed != 0);
|
||||
|
||||
/* Remove a fixed slot, to make room for the private data. */
|
||||
flags = flags ^ (nfixed << FIXED_SLOTS_SHIFT);
|
||||
flags |= (nfixed - 1) << FIXED_SLOTS_SHIFT;
|
||||
|
||||
setPrivate(NULL);
|
||||
/*
|
||||
* For checking that the fixed slot information in a shape is consistent
|
||||
* with the allocation kind of this object.
|
||||
*/
|
||||
gc::AllocKind kind = getAllocKind();
|
||||
size_t slots = gc::GetGCKindSlots(kind);
|
||||
if (clasp->flags & JSCLASS_HAS_PRIVATE) {
|
||||
JS_ASSERT(slots > 0);
|
||||
slots--;
|
||||
}
|
||||
return slots;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
JSObject::setInitialProperty(JSContext *cx, const js::Shape *shape)
|
||||
|
@ -4540,23 +4567,22 @@ JSObject::setInitialProperty(JSContext *cx, const js::Shape *shape)
|
|||
JS_ASSERT(isNewborn());
|
||||
JS_ASSERT(shape->compartment() == compartment());
|
||||
JS_ASSERT(!shape->inDictionary());
|
||||
|
||||
if (shape->getObjectClass()->flags & JSCLASS_HAS_PRIVATE)
|
||||
initializePrivate();
|
||||
JS_ASSERT(numFixedSlotsFromAllocationKind(shape->getObjectClass()) == shape->numFixedSlots());
|
||||
|
||||
size_t span = shape->slotSpan();
|
||||
|
||||
if (!span) {
|
||||
shape_ = const_cast<js::Shape *>(shape);
|
||||
return true;
|
||||
if (span) {
|
||||
size_t count = dynamicSlotsCount(shape->numFixedSlots(), span);
|
||||
if (count && !growSlots(cx, 0, count))
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t count = dynamicSlotsCount(numFixedSlots(), span);
|
||||
if (count && !growSlots(cx, 0, count))
|
||||
return false;
|
||||
|
||||
shape_ = const_cast<js::Shape *>(shape);
|
||||
updateSlotsForSpan(0, span);
|
||||
if (hasPrivate())
|
||||
setPrivate(NULL);
|
||||
|
||||
if (span)
|
||||
updateSlotsForSpan(0, span);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -4567,13 +4593,13 @@ JSObject::setInitialPropertyInfallible(const js::Shape *shape)
|
|||
JS_ASSERT(isNewborn());
|
||||
JS_ASSERT(shape->compartment() == compartment());
|
||||
JS_ASSERT(!shape->inDictionary());
|
||||
JS_ASSERT(numFixedSlotsFromAllocationKind(shape->getObjectClass()) == shape->numFixedSlots());
|
||||
|
||||
if (shape->getObjectClass()->flags & JSCLASS_HAS_PRIVATE)
|
||||
initializePrivate();
|
||||
|
||||
JS_ASSERT(dynamicSlotsCount(numFixedSlots(), shape->slotSpan()) == 0);
|
||||
JS_ASSERT(dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan()) == 0);
|
||||
|
||||
shape_ = const_cast<js::Shape *>(shape);
|
||||
if (hasPrivate())
|
||||
setPrivate(NULL);
|
||||
|
||||
size_t span = shape->slotSpan();
|
||||
if (span)
|
||||
|
@ -4587,6 +4613,7 @@ JSObject::setLastProperty(JSContext *cx, const js::Shape *shape)
|
|||
JS_ASSERT(!inDictionaryMode());
|
||||
JS_ASSERT(!shape->inDictionary());
|
||||
JS_ASSERT(shape->compartment() == compartment());
|
||||
JS_ASSERT(shape->numFixedSlots() == numFixedSlots());
|
||||
|
||||
size_t oldSpan = lastProperty()->slotSpan();
|
||||
size_t newSpan = shape->slotSpan();
|
||||
|
@ -4644,11 +4671,12 @@ JSObject::growSlots(JSContext *cx, uint32 oldCount, uint32 newCount)
|
|||
*/
|
||||
JS_ASSERT_IF(!isNewborn() && isCall(), asCall().maybeStackFrame() != NULL);
|
||||
|
||||
/* Don't let nslots get close to wrapping around uint32. */
|
||||
if (newCount >= NSLOTS_LIMIT) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* Slot capacities are determined by the span of allocated objects. Due to
|
||||
* the limited number of bits to store shape slots, object growth is
|
||||
* throttled well before the slot capacity can overflow.
|
||||
*/
|
||||
JS_ASSERT(newCount < NELEMENTS_LIMIT);
|
||||
|
||||
size_t oldSize = Probes::objectResizeActive() ? slotsAndStructSize() : 0;
|
||||
size_t newSize = oldSize + (newCount - oldCount) * sizeof(Value);
|
||||
|
@ -4756,8 +4784,8 @@ JSObject::growElements(JSContext *cx, uintN newcap)
|
|||
else if (actualCapacity < SLOT_CAPACITY_MIN)
|
||||
actualCapacity = SLOT_CAPACITY_MIN;
|
||||
|
||||
/* Don't let nslots get close to wrapping around uint32. */
|
||||
if (actualCapacity >= NSLOTS_LIMIT || actualCapacity < oldcap || actualCapacity < newcap) {
|
||||
/* Don't let nelements get close to wrapping around uint32. */
|
||||
if (actualCapacity >= NELEMENTS_LIMIT || actualCapacity < oldcap || actualCapacity < newcap) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
@ -5115,6 +5143,11 @@ JSObject::allocSlot(JSContext *cx, uint32 *slotp)
|
|||
}
|
||||
}
|
||||
|
||||
if (slot >= SHAPE_MAXIMUM_SLOT) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
*slotp = slot;
|
||||
|
||||
if (inDictionaryMode() && !setSlotSpan(cx, slot + 1))
|
||||
|
|
|
@ -535,26 +535,16 @@ struct JSObject : js::gc::Cell
|
|||
SINGLETON_TYPE = 0x10000,
|
||||
LAZY_TYPE = 0x20000,
|
||||
|
||||
/* The top 5 bits of an object's flags are its number of fixed slots. */
|
||||
FIXED_SLOTS_SHIFT = 27,
|
||||
FIXED_SLOTS_MASK = 0x1f << FIXED_SLOTS_SHIFT,
|
||||
|
||||
UNUSED_FLAG_BITS = 0x07FC70A0
|
||||
};
|
||||
|
||||
/*
|
||||
* Impose a sane upper bound, originally checked only for dense arrays, on
|
||||
* number of slots in an object.
|
||||
*/
|
||||
enum {
|
||||
NSLOTS_BITS = 29,
|
||||
NSLOTS_LIMIT = JS_BIT(NSLOTS_BITS)
|
||||
};
|
||||
|
||||
uint32 flags; /* flags */
|
||||
|
||||
uint32 padding;
|
||||
|
||||
/* Upper bound on the number of elements in an object. */
|
||||
static const uint32 NELEMENTS_LIMIT = JS_BIT(29);
|
||||
|
||||
private:
|
||||
js::Value *slots; /* Slots for object properties. */
|
||||
js::Value *elements; /* Slots for object elements. */
|
||||
|
@ -671,6 +661,10 @@ struct JSObject : js::gc::Cell
|
|||
|
||||
inline size_t numFixedSlots() const;
|
||||
|
||||
#ifdef DEBUG
|
||||
size_t numFixedSlotsFromAllocationKind(js::Class *clasp) const;
|
||||
#endif
|
||||
|
||||
static const uint32 MAX_FIXED_SLOTS = 16;
|
||||
|
||||
private:
|
||||
|
@ -929,7 +923,6 @@ struct JSObject : js::gc::Cell
|
|||
bool isSealedOrFrozen(JSContext *cx, ImmutabilityType it, bool *resultp);
|
||||
|
||||
inline void *&privateAddress(uint32 nfixed) const;
|
||||
inline void initializePrivate();
|
||||
|
||||
public:
|
||||
bool isExtensible() const { return !(flags & NOT_EXTENSIBLE); }
|
||||
|
@ -1240,16 +1233,20 @@ struct JSObject : js::gc::Cell
|
|||
inline bool isCallable();
|
||||
|
||||
/* Do initialization required immediately after allocation. */
|
||||
void earlyInit(jsuword capacity)
|
||||
void earlyInit()
|
||||
{
|
||||
flags = capacity << FIXED_SLOTS_SHIFT;
|
||||
|
||||
/* Stops obj from being scanned until initializated. */
|
||||
shape_ = NULL;
|
||||
}
|
||||
|
||||
/* The last property is not initialized here and should be set separately. */
|
||||
void init(JSContext *cx, js::types::TypeObject *type, bool denseArray);
|
||||
void init(JSContext *cx, js::types::TypeObject *type);
|
||||
|
||||
/*
|
||||
* Finish initializing the elements in a dense array, after its initial
|
||||
* property has been set.
|
||||
*/
|
||||
void initDenseArray();
|
||||
|
||||
inline void finish(JSContext *cx);
|
||||
JS_ALWAYS_INLINE void finalize(JSContext *cx, bool background);
|
||||
|
@ -1314,8 +1311,6 @@ struct JSObject : js::gc::Cell
|
|||
static void TradeGuts(JSContext *cx, JSObject *a, JSObject *b,
|
||||
TradeGutsReserved &reserved);
|
||||
|
||||
void updateFixedSlots(uintN fixed);
|
||||
|
||||
public:
|
||||
/* Add a property whose id is not yet in this scope. */
|
||||
const js::Shape *addProperty(JSContext *cx, jsid id,
|
||||
|
@ -1443,11 +1438,9 @@ struct JSObject : js::gc::Cell
|
|||
JS_STATIC_ASSERT(sizeof(JSObject) % sizeof(js::Value) == 0);
|
||||
|
||||
JS_STATIC_ASSERT(offsetof(JSObject, shape_) == offsetof(js::shadow::Object, shape));
|
||||
JS_STATIC_ASSERT(offsetof(JSObject, flags) == offsetof(js::shadow::Object, flags));
|
||||
JS_STATIC_ASSERT(offsetof(JSObject, slots) == offsetof(js::shadow::Object, slots));
|
||||
JS_STATIC_ASSERT(offsetof(JSObject, type_) == offsetof(js::shadow::Object, type));
|
||||
JS_STATIC_ASSERT(sizeof(JSObject) == sizeof(js::shadow::Object));
|
||||
JS_STATIC_ASSERT(FIXED_SLOTS_SHIFT == js::shadow::Object::FIXED_SLOTS_SHIFT);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1476,7 +1469,7 @@ JSObject::fixedSlots() const {
|
|||
inline size_t
|
||||
JSObject::numFixedSlots() const
|
||||
{
|
||||
return flags >> FIXED_SLOTS_SHIFT;
|
||||
return reinterpret_cast<const js::shadow::Object *>(this)->numFixedSlots();
|
||||
}
|
||||
|
||||
/* static */ inline size_t
|
||||
|
|
|
@ -382,7 +382,7 @@ JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent
|
|||
if (!type)
|
||||
return false;
|
||||
|
||||
init(cx, type, false);
|
||||
init(cx, type);
|
||||
if (!setInitialProperty(cx, bindings.lastShape()))
|
||||
return false;
|
||||
|
||||
|
@ -419,7 +419,7 @@ JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent
|
|||
inline bool
|
||||
JSObject::initClonedBlock(JSContext *cx, js::types::TypeObject *type, js::StackFrame *frame)
|
||||
{
|
||||
init(cx, type, false);
|
||||
init(cx, type);
|
||||
|
||||
if (!setInitialProperty(cx, getProto()->lastProperty()))
|
||||
return false;
|
||||
|
@ -537,6 +537,7 @@ JSObject::setLastPropertyInfallible(const js::Shape *shape)
|
|||
JS_ASSERT(shape->compartment() == compartment());
|
||||
JS_ASSERT(!inDictionaryMode());
|
||||
JS_ASSERT(slotSpan() == shape->slotSpan());
|
||||
JS_ASSERT(numFixedSlots() == shape->numFixedSlots());
|
||||
|
||||
shape_ = const_cast<js::Shape *>(shape);
|
||||
}
|
||||
|
@ -1019,28 +1020,28 @@ JSObject::isQName() const
|
|||
}
|
||||
|
||||
inline void
|
||||
JSObject::init(JSContext *cx, js::types::TypeObject *type, bool denseArray)
|
||||
JSObject::init(JSContext *cx, js::types::TypeObject *type)
|
||||
{
|
||||
JS_STATIC_ASSERT(sizeof(js::ObjectElements) == 2 * sizeof(js::Value));
|
||||
|
||||
uint32 numSlots = numFixedSlots();
|
||||
|
||||
/*
|
||||
* Fill the fixed slots with undefined if needed. This object must
|
||||
* already have its numFixedSlots() filled in, as by js_NewGCObject.
|
||||
*/
|
||||
slots = NULL;
|
||||
if (denseArray) {
|
||||
JS_ASSERT(numSlots >= 2);
|
||||
elements = fixedElements();
|
||||
new (getElementsHeader()) js::ObjectElements(numSlots - 2);
|
||||
} else {
|
||||
elements = js::emptyObjectElements;
|
||||
}
|
||||
elements = js::emptyObjectElements;
|
||||
flags = 0;
|
||||
|
||||
setType(type);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::initDenseArray()
|
||||
{
|
||||
JS_ASSERT(hasClass(&js::ArrayClass));
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(js::ObjectElements) == 2 * sizeof(js::Value));
|
||||
JS_ASSERT(numFixedSlots() >= 2);
|
||||
|
||||
/* Fill in the object's inline elements header. */
|
||||
elements = fixedElements();
|
||||
new (getElementsHeader()) js::ObjectElements(numFixedSlots() - 2);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::finish(JSContext *cx)
|
||||
{
|
||||
|
@ -1057,7 +1058,7 @@ JSObject::initSharingEmptyShape(JSContext *cx,
|
|||
void *privateValue,
|
||||
js::gc::AllocKind kind)
|
||||
{
|
||||
init(cx, type, false);
|
||||
init(cx, type);
|
||||
|
||||
js::EmptyShape *empty = type->getEmptyShape(cx, aclasp, kind);
|
||||
if (!empty)
|
||||
|
@ -1438,7 +1439,7 @@ InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject *par
|
|||
if (type->canProvideEmptyShape(clasp) && parent == type->proto->getParent())
|
||||
empty = type->getEmptyShape(cx, clasp, kind);
|
||||
else
|
||||
empty = js::EmptyShape::create(cx, clasp, parent);
|
||||
empty = js::EmptyShape::create(cx, clasp, parent, gc::GetGCKindSlots(kind, clasp));
|
||||
if (!empty) {
|
||||
JS_ASSERT(obj->isNewborn());
|
||||
return false;
|
||||
|
@ -1448,11 +1449,12 @@ InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject *par
|
|||
}
|
||||
|
||||
static inline bool
|
||||
InitScopeForNonNativeObject(JSContext *cx, JSObject *obj, js::Class *clasp, JSObject *parent)
|
||||
InitScopeForNonNativeObject(JSContext *cx, JSObject *obj, js::Class *clasp, JSObject *parent,
|
||||
gc::AllocKind kind)
|
||||
{
|
||||
JS_ASSERT(!clasp->isNative());
|
||||
|
||||
const js::Shape *empty = js::BaseShape::lookupInitialShape(cx, clasp, parent);
|
||||
const js::Shape *empty = js::BaseShape::lookupInitialShape(cx, clasp, parent, kind);
|
||||
if (!empty)
|
||||
return false;
|
||||
JS_ASSERT(empty->isEmptyShape());
|
||||
|
@ -1510,8 +1512,7 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, gc::AllocKi
|
|||
* Default parent to the parent of the prototype, which was set from
|
||||
* the parent of the prototype's constructor.
|
||||
*/
|
||||
bool denseArray = (clasp == &ArrayClass);
|
||||
obj->init(cx, type, denseArray);
|
||||
obj->init(cx, type);
|
||||
|
||||
JS_ASSERT(type->canProvideEmptyShape(clasp));
|
||||
|
||||
|
@ -1666,7 +1667,7 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
|
|||
if (!obj)
|
||||
goto out;
|
||||
|
||||
obj->init(cx, type, clasp == &ArrayClass);
|
||||
obj->init(cx, type);
|
||||
|
||||
/*
|
||||
* Default parent to the parent of the prototype, which was set from
|
||||
|
@ -1677,7 +1678,7 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
|
|||
|
||||
if (clasp->isNative()
|
||||
? !InitScopeForObject(cx, obj, clasp, parent, type, kind)
|
||||
: !InitScopeForNonNativeObject(cx, obj, clasp, parent)) {
|
||||
: !InitScopeForNonNativeObject(cx, obj, clasp, parent, kind)) {
|
||||
obj = NULL;
|
||||
}
|
||||
|
||||
|
@ -1734,7 +1735,7 @@ NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::
|
|||
if (!obj)
|
||||
goto out;
|
||||
|
||||
obj->init(cx, type, false);
|
||||
obj->init(cx, type);
|
||||
|
||||
/*
|
||||
* Default parent to the parent of the prototype, which was set from
|
||||
|
|
|
@ -179,8 +179,8 @@ PropertyTree::getChild(JSContext *cx, Shape *parent, const Shape &child)
|
|||
|
||||
UnownedBaseShape *base = child.base()->unowned();
|
||||
|
||||
new (shape) Shape(base, child.propid_, child.slot_, child.attrs,
|
||||
child.flags, child.shortid_);
|
||||
new (shape) Shape(&child);
|
||||
shape->base_ = base;
|
||||
|
||||
if (!insertChild(cx, parent, shape))
|
||||
return NULL;
|
||||
|
|
|
@ -199,6 +199,7 @@ class BaseShape;
|
|||
class UnownedBaseShape;
|
||||
struct Shape;
|
||||
struct EmptyShape;
|
||||
class ShapeKindArray;
|
||||
class Bindings;
|
||||
|
||||
class MultiDeclRange;
|
||||
|
|
|
@ -741,6 +741,7 @@ inline bool
|
|||
JSObject::initRegExp(JSContext *cx, js::RegExp *re)
|
||||
{
|
||||
JS_ASSERT(isRegExp());
|
||||
JS_ASSERT(getAllocKind() == js::gc::FINALIZE_OBJECT8);
|
||||
|
||||
/*
|
||||
* It's currently possible to swap RegExp guts. In that case this object
|
||||
|
@ -748,14 +749,14 @@ JSObject::initRegExp(JSContext *cx, js::RegExp *re)
|
|||
*/
|
||||
if (nativeEmpty()) {
|
||||
const js::Shape *shape = js::BaseShape::lookupInitialShape(cx, getClass(), getParent(),
|
||||
lastProperty());
|
||||
js::gc::FINALIZE_OBJECT8, lastProperty());
|
||||
if (!shape)
|
||||
return false;
|
||||
if (shape == lastProperty()) {
|
||||
shape = assignInitialRegExpShape(cx);
|
||||
if (!shape)
|
||||
return false;
|
||||
js::BaseShape::insertInitialShape(cx, shape);
|
||||
js::BaseShape::insertInitialShape(cx, js::gc::FINALIZE_OBJECT8, shape);
|
||||
}
|
||||
setLastPropertyInfallible(shape);
|
||||
JS_ASSERT(!nativeEmpty());
|
||||
|
|
|
@ -313,6 +313,30 @@ Shape::getChildBinding(JSContext *cx, const js::Shape &child, Shape **lastBindin
|
|||
JS_ASSERT(shape->parent == this);
|
||||
JS_ASSERT(this == *lastBinding);
|
||||
*lastBinding = shape;
|
||||
|
||||
/*
|
||||
* Update the number of fixed slots which bindings of this shape will
|
||||
* have. Bindings are constructed as new properties come in, so the
|
||||
* call object allocation class is not known ahead of time. Compute
|
||||
* the fixed slot count here, which will feed into call objects created
|
||||
* off of the bindings.
|
||||
*/
|
||||
uint32 slots = child.slotSpan() + 1; /* Add one for private data. */
|
||||
gc::AllocKind kind = gc::GetGCObjectKind(slots);
|
||||
|
||||
/*
|
||||
* Make sure that the arguments and variables in the call object all
|
||||
* end up in a contiguous range of slots. We need this to be able to
|
||||
* embed the args/vars arrays in the TypeScriptNesting for the function
|
||||
* after the call object's frame has finished.
|
||||
*/
|
||||
uint32 nfixed = gc::GetGCKindSlots(kind);
|
||||
if (nfixed < slots) {
|
||||
nfixed = CallObject::RESERVED_SLOTS + 1;
|
||||
JS_ASSERT(gc::GetGCKindSlots(gc::GetGCObjectKind(nfixed)) == CallObject::RESERVED_SLOTS + 1);
|
||||
}
|
||||
|
||||
shape->setNumFixedSlots(nfixed - 1);
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
@ -355,13 +379,13 @@ JSObject::getChildProperty(JSContext *cx, Shape *parent, Shape &child)
|
|||
* JS_ClearScope call.
|
||||
*/
|
||||
if (!child.hasSlot()) {
|
||||
child.slot_ = parent->maybeSlot();
|
||||
child.setSlot(parent->maybeSlot());
|
||||
} else {
|
||||
if (child.hasMissingSlot()) {
|
||||
uint32 slot;
|
||||
if (!allocSlot(cx, &slot))
|
||||
return NULL;
|
||||
child.slot_ = slot;
|
||||
child.setSlot(slot);
|
||||
} else {
|
||||
/* Slots can only be allocated out of order on objects in dictionary mode. */
|
||||
JS_ASSERT(inDictionaryMode() ||
|
||||
|
@ -625,7 +649,7 @@ JSObject::addPropertyInternal(JSContext *cx, jsid id,
|
|||
if (!nbase)
|
||||
return NULL;
|
||||
|
||||
Shape child(nbase, id, slot, attrs, flags, shortid);
|
||||
Shape child(nbase, id, slot, numFixedSlots(), attrs, flags, shortid);
|
||||
shape = getChildProperty(cx, lastProperty(), child);
|
||||
}
|
||||
|
||||
|
@ -773,7 +797,7 @@ JSObject::putProperty(JSContext *cx, jsid id,
|
|||
else
|
||||
shape->base_ = nbase;
|
||||
|
||||
shape->slot_ = slot;
|
||||
shape->setSlot(slot);
|
||||
shape->attrs = uint8(attrs);
|
||||
shape->flags = flags | Shape::IN_DICTIONARY;
|
||||
shape->shortid_ = int16(shortid);
|
||||
|
@ -803,7 +827,7 @@ JSObject::putProperty(JSContext *cx, jsid id,
|
|||
JS_ASSERT(shape == lastProperty());
|
||||
|
||||
/* Find or create a property tree node labeled by our arguments. */
|
||||
Shape child(nbase, id, slot, attrs, flags, shortid);
|
||||
Shape child(nbase, id, slot, numFixedSlots(), attrs, flags, shortid);
|
||||
Shape *newShape = getChildProperty(cx, shape->parent, child);
|
||||
|
||||
if (!newShape) {
|
||||
|
@ -1178,7 +1202,7 @@ LookupBaseShape(JSContext *cx, const BaseShape &base)
|
|||
|
||||
JSCompartment::BaseShapeEntry entry;
|
||||
entry.base = static_cast<UnownedBaseShape *>(nbase);
|
||||
entry.shape = NULL;
|
||||
entry.shapes = NULL;
|
||||
|
||||
if (!table.relookupOrAdd(p, &base, entry))
|
||||
return NULL;
|
||||
|
@ -1194,32 +1218,41 @@ BaseShape::lookup(JSContext *cx, const BaseShape &base)
|
|||
}
|
||||
|
||||
/* static */ Shape *
|
||||
BaseShape::lookupInitialShape(JSContext *cx, Class *clasp, JSObject *parent, Shape *initial)
|
||||
BaseShape::lookupInitialShape(JSContext *cx, Class *clasp, JSObject *parent,
|
||||
AllocKind kind, Shape *initial)
|
||||
{
|
||||
js::BaseShape base(clasp, parent);
|
||||
JSCompartment::BaseShapeEntry *entry = LookupBaseShape(cx, base);
|
||||
if (!entry)
|
||||
return NULL;
|
||||
if (entry->shape)
|
||||
return entry->shape;
|
||||
|
||||
if (initial) {
|
||||
entry->shape = initial;
|
||||
return entry->shape;
|
||||
if (!entry->shapes) {
|
||||
entry->shapes = cx->new_<ShapeKindArray>();
|
||||
if (!entry->shapes)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entry->shape = JS_PROPERTY_TREE(cx).newShape(cx);
|
||||
if (!entry->shape)
|
||||
Shape *&shape = entry->shapes->get(kind);
|
||||
|
||||
if (shape)
|
||||
return shape;
|
||||
|
||||
if (initial) {
|
||||
shape = initial;
|
||||
return initial;
|
||||
}
|
||||
|
||||
shape = JS_PROPERTY_TREE(cx).newShape(cx);
|
||||
if (!shape)
|
||||
return NULL;
|
||||
return new (entry->shape) EmptyShape(entry->base);
|
||||
return new (shape) EmptyShape(entry->base, gc::GetGCKindSlots(kind, clasp));
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
BaseShape::insertInitialShape(JSContext *cx, const Shape *initial)
|
||||
BaseShape::insertInitialShape(JSContext *cx, AllocKind kind, const Shape *initial)
|
||||
{
|
||||
JSCompartment::BaseShapeEntry *entry = LookupBaseShape(cx, *initial->base());
|
||||
JS_ASSERT(entry && entry->base == initial->base());
|
||||
entry->shape = const_cast<Shape *>(initial);
|
||||
JS_ASSERT(entry && entry->base == initial->base() && entry->shapes);
|
||||
entry->shapes->get(kind) = const_cast<Shape *>(initial);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1229,10 +1262,17 @@ JSCompartment::sweepBaseShapeTable(JSContext *cx)
|
|||
for (BaseShapeSet::Enum e(baseShapes); !e.empty(); e.popFront()) {
|
||||
JSCompartment::BaseShapeEntry &entry =
|
||||
const_cast<JSCompartment::BaseShapeEntry &>(e.front());
|
||||
if (!entry.base->isMarked())
|
||||
if (!entry.base->isMarked()) {
|
||||
if (entry.shapes)
|
||||
cx->delete_(entry.shapes);
|
||||
e.removeFront();
|
||||
else if (entry.shape && !entry.shape->isMarked())
|
||||
entry.shape = NULL;
|
||||
} else if (entry.shapes) {
|
||||
for (size_t i = 0; i < ShapeKindArray::SHAPE_COUNT; i++) {
|
||||
Shape *&shape = entry.shapes->getIndex(i);
|
||||
if (shape && !shape->isMarked())
|
||||
shape = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
139
js/src/jsscope.h
139
js/src/jsscope.h
|
@ -197,22 +197,23 @@
|
|||
* scope->table isn't worth it. So instead of always allocating scope->table,
|
||||
* we leave it null while initializing all the other scope members as if it
|
||||
* were non-null and minimal-length. Until a scope is searched
|
||||
* MAX_LINEAR_SEARCHES times, we use linear search from obj->lastProp to find a
|
||||
* LINEAR_SEARCHES_MAX times, we use linear search from obj->lastProp to find a
|
||||
* given id, and save on the time and space overhead of creating a hash table.
|
||||
*/
|
||||
|
||||
#define SHAPE_INVALID_SLOT 0xffffffff
|
||||
|
||||
namespace js {
|
||||
|
||||
/* Limit on the number of slotful properties in an object. */
|
||||
static const uint32 SHAPE_INVALID_SLOT = JS_BIT(24) - 1;
|
||||
static const uint32 SHAPE_MAXIMUM_SLOT = JS_BIT(24) - 2;
|
||||
|
||||
/*
|
||||
* Shapes use multiplicative hashing, _a la_ jsdhash.[ch], but specialized to
|
||||
* minimize footprint. But if a Shape lineage has been searched fewer than
|
||||
* MAX_LINEAR_SEARCHES times, we use linear search and avoid allocating
|
||||
* LINEAR_SEARCHES_MAX times, we use linear search and avoid allocating
|
||||
* scope->table.
|
||||
*/
|
||||
struct PropertyTable {
|
||||
static const uint32 MAX_LINEAR_SEARCHES = 7;
|
||||
static const uint32 MIN_SIZE_LOG2 = 4;
|
||||
static const uint32 MIN_SIZE = JS_BIT(MIN_SIZE_LOG2);
|
||||
|
||||
|
@ -425,10 +426,10 @@ class BaseShape : public js::gc::Cell
|
|||
* if none was found.
|
||||
*/
|
||||
static Shape *lookupInitialShape(JSContext *cx, Class *clasp, JSObject *parent,
|
||||
Shape *initial = NULL);
|
||||
gc::AllocKind kind, Shape *initial = NULL);
|
||||
|
||||
/* Reinsert a possibly modified initial shape to the baseShapes table. */
|
||||
static void insertInitialShape(JSContext *cx, const Shape *initial);
|
||||
static void insertInitialShape(JSContext *cx, gc::AllocKind kind, const Shape *initial);
|
||||
|
||||
/* Get the canonical base shape. */
|
||||
inline UnownedBaseShape *unowned();
|
||||
|
@ -481,24 +482,32 @@ struct Shape : public js::gc::Cell
|
|||
BaseShape *base_;
|
||||
jsid propid_;
|
||||
|
||||
/*
|
||||
* numLinearSearches starts at zero and is incremented initially on each
|
||||
* search() call. Once numLinearSearches reaches MAX_LINEAR_SEARCHES
|
||||
* (which is a small integer), the table is created on the next search()
|
||||
* call. The table can also be created when hashifying for dictionary
|
||||
* mode.
|
||||
*/
|
||||
uint8 numLinearSearches:3;
|
||||
enum {
|
||||
/* Number of fixed slots in objects with this shape. */
|
||||
FIXED_SLOTS_MAX = 0x1f,
|
||||
FIXED_SLOTS_SHIFT = 27,
|
||||
FIXED_SLOTS_MASK = FIXED_SLOTS_MAX << FIXED_SLOTS_SHIFT,
|
||||
|
||||
/*
|
||||
* Index in object slots for shapes which hasSlot(). For !hasSlot() shapes
|
||||
* in the property tree with a parent, stores the parent's slot (which may
|
||||
* be invalid), and invalid for all other shapes.
|
||||
*/
|
||||
uint32 slot_:29;
|
||||
/*
|
||||
* numLinearSearches starts at zero and is incremented initially on
|
||||
* search() calls. Once numLinearSearches reaches LINEAR_SEARCHES_MAX,
|
||||
* the table is created on the next search() call. The table can also
|
||||
* be created when hashifying for dictionary mode.
|
||||
*/
|
||||
LINEAR_SEARCHES_MAX = 0x7,
|
||||
LINEAR_SEARCHES_SHIFT = 24,
|
||||
LINEAR_SEARCHES_MASK = LINEAR_SEARCHES_MAX << LINEAR_SEARCHES_SHIFT,
|
||||
|
||||
static const size_t SLOT_BITS = 29;
|
||||
/*
|
||||
* Mask to get the index in object slots for shapes which hasSlot().
|
||||
* For !hasSlot() shapes in the property tree with a parent, stores the
|
||||
* parent's slot index (which may be invalid), and invalid for all
|
||||
* other shapes.
|
||||
*/
|
||||
SLOT_MASK = JS_BIT(24) - 1
|
||||
};
|
||||
|
||||
uint32 slotInfo; /* mask of above info */
|
||||
uint8 attrs; /* attributes, see jsapi.h JSPROP_* */
|
||||
uint8 flags; /* flags, see below for defines */
|
||||
int16 shortid_; /* tinyid, or local arg/var index */
|
||||
|
@ -532,8 +541,10 @@ struct Shape : public js::gc::Cell
|
|||
void handoffTableTo(Shape *newShape);
|
||||
|
||||
void setParent(js::Shape *p) {
|
||||
JS_ASSERT_IF(p && !p->hasMissingSlot() && !inDictionary(), p->slot_ <= slot_);
|
||||
JS_ASSERT_IF(p && !inDictionary(), hasSlot() == (p->slot_ != slot_));
|
||||
JS_ASSERT_IF(p && !p->hasMissingSlot() && !inDictionary(),
|
||||
p->maybeSlot() <= maybeSlot());
|
||||
JS_ASSERT_IF(p && !inDictionary(),
|
||||
hasSlot() == (p->maybeSlot() != maybeSlot()));
|
||||
parent = p;
|
||||
}
|
||||
|
||||
|
@ -619,13 +630,13 @@ struct Shape : public js::gc::Cell
|
|||
UNUSED_BITS = 0x3C
|
||||
};
|
||||
|
||||
Shape(BaseShape *base, jsid id, uint32 slot, uintN attrs, uintN flags, intN shortid);
|
||||
Shape(BaseShape *base, jsid id, uint32 slot, uint32 nfixed, uintN attrs, uintN flags, intN shortid);
|
||||
|
||||
/* Get a shape identical to this one, without parent/kids information. */
|
||||
Shape(const Shape *other);
|
||||
|
||||
/* Used by EmptyShape (see jsscopeinlines.h). */
|
||||
Shape(BaseShape *base);
|
||||
Shape(BaseShape *base, uint32 nfixed);
|
||||
|
||||
/* Copy constructor disabled, to avoid misuse of the above form. */
|
||||
Shape(const Shape &other);
|
||||
|
@ -638,7 +649,7 @@ struct Shape : public js::gc::Cell
|
|||
* if the shape is being constructed and has not had a slot assigned yet.
|
||||
* After construction, hasSlot() implies !hasMissingSlot().
|
||||
*/
|
||||
bool hasMissingSlot() const { return slot_ == (SHAPE_INVALID_SLOT >> (32 - SLOT_BITS)); }
|
||||
bool hasMissingSlot() const { return maybeSlot() == SHAPE_INVALID_SLOT; }
|
||||
|
||||
public:
|
||||
/* Public bits stored in shape->flags. */
|
||||
|
@ -724,8 +735,8 @@ struct Shape : public js::gc::Cell
|
|||
BaseShape *base() const { return base_; }
|
||||
|
||||
bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; }
|
||||
uint32 slot() const { JS_ASSERT(hasSlot() && !hasMissingSlot()); return slot_; }
|
||||
uint32 maybeSlot() const { return hasMissingSlot() ? SHAPE_INVALID_SLOT : slot_; }
|
||||
uint32 slot() const { JS_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); }
|
||||
uint32 maybeSlot() const { return slotInfo & SLOT_MASK; }
|
||||
|
||||
bool isEmptyShape() const {
|
||||
JS_ASSERT_IF(JSID_IS_EMPTY(propid_), hasMissingSlot());
|
||||
|
@ -738,6 +749,33 @@ struct Shape : public js::gc::Cell
|
|||
return hasMissingSlot() ? free : Max(free, maybeSlot() + 1);
|
||||
}
|
||||
|
||||
void setSlot(uint32 slot) {
|
||||
JS_ASSERT(slot <= SHAPE_INVALID_SLOT);
|
||||
slotInfo = slotInfo & ~SLOT_MASK;
|
||||
slotInfo = slotInfo | slot;
|
||||
}
|
||||
|
||||
uint32 numFixedSlots() const {
|
||||
return (slotInfo >> FIXED_SLOTS_SHIFT);
|
||||
}
|
||||
|
||||
void setNumFixedSlots(uint32 nfixed) {
|
||||
JS_ASSERT(nfixed < FIXED_SLOTS_MAX);
|
||||
slotInfo = slotInfo & ~FIXED_SLOTS_MASK;
|
||||
slotInfo = slotInfo | (nfixed << FIXED_SLOTS_SHIFT);
|
||||
}
|
||||
|
||||
uint32 numLinearSearches() const {
|
||||
return (slotInfo & LINEAR_SEARCHES_MASK) >> LINEAR_SEARCHES_SHIFT;
|
||||
}
|
||||
|
||||
void incrementNumLinearSearches() {
|
||||
uint32 count = numLinearSearches();
|
||||
JS_ASSERT(count < LINEAR_SEARCHES_MAX);
|
||||
slotInfo = slotInfo & ~LINEAR_SEARCHES_MASK;
|
||||
slotInfo = slotInfo | ((count + 1) << LINEAR_SEARCHES_SHIFT);
|
||||
}
|
||||
|
||||
jsid propid() const { JS_ASSERT(!isEmptyShape()); return maybePropid(); }
|
||||
jsid maybePropid() const { JS_ASSERT(!JSID_IS_VOID(propid_)); return propid_; }
|
||||
|
||||
|
@ -852,14 +890,16 @@ struct Shape : public js::gc::Cell
|
|||
private:
|
||||
static void staticAsserts() {
|
||||
JS_STATIC_ASSERT(offsetof(Shape, base_) == offsetof(js::shadow::Shape, base));
|
||||
JS_STATIC_ASSERT(offsetof(Shape, slotInfo) == offsetof(js::shadow::Shape, slotInfo));
|
||||
JS_STATIC_ASSERT(FIXED_SLOTS_SHIFT == js::shadow::Shape::FIXED_SLOTS_SHIFT);
|
||||
}
|
||||
};
|
||||
|
||||
struct EmptyShape : public js::Shape
|
||||
{
|
||||
EmptyShape(BaseShape *base);
|
||||
EmptyShape(BaseShape *base, uint32 nfixed);
|
||||
|
||||
static EmptyShape *create(JSContext *cx, js::Class *clasp, JSObject *parent) {
|
||||
static EmptyShape *create(JSContext *cx, js::Class *clasp, JSObject *parent, uint32 nfixed) {
|
||||
BaseShape lookup(clasp, parent);
|
||||
BaseShape *base = BaseShape::lookup(cx, lookup);
|
||||
if (!base)
|
||||
|
@ -868,7 +908,37 @@ struct EmptyShape : public js::Shape
|
|||
js::Shape *eprop = JS_PROPERTY_TREE(cx).newShape(cx);
|
||||
if (!eprop)
|
||||
return NULL;
|
||||
return new (eprop) EmptyShape(base);
|
||||
return new (eprop) EmptyShape(base, nfixed);
|
||||
}
|
||||
};
|
||||
|
||||
/* Heap-allocated array of shapes for each object allocation size. */
|
||||
class ShapeKindArray
|
||||
{
|
||||
public:
|
||||
static const uint32 SHAPE_COUNT =
|
||||
((js::gc::FINALIZE_FUNCTION - js::gc::FINALIZE_OBJECT0) / 2) + 1;
|
||||
|
||||
ShapeKindArray() { PodZero(this); }
|
||||
|
||||
Shape *&get(gc::AllocKind kind) {
|
||||
JS_ASSERT(kind >= gc::FINALIZE_OBJECT0 &&
|
||||
kind <= gc::FINALIZE_FUNCTION_AND_OBJECT_LAST);
|
||||
int i = (kind - gc::FINALIZE_OBJECT0) / 2;
|
||||
return shapes[i];
|
||||
}
|
||||
|
||||
Shape *&getIndex(size_t i) {
|
||||
JS_ASSERT(i < SHAPE_COUNT);
|
||||
return shapes[i];
|
||||
}
|
||||
|
||||
private:
|
||||
Shape *shapes[SHAPE_COUNT];
|
||||
|
||||
void staticAsserts() {
|
||||
JS_STATIC_ASSERT(gc::FINALIZE_OBJECT0 % 2 == 0);
|
||||
JS_STATIC_ASSERT(gc::FINALIZE_FUNCTION == gc::FINALIZE_OBJECT_LAST + 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -902,14 +972,13 @@ Shape::search(JSContext *cx, js::Shape **pstart, jsid id, bool adding)
|
|||
if (start->hasTable())
|
||||
return start->table().search(id, adding);
|
||||
|
||||
if (start->numLinearSearches == PropertyTable::MAX_LINEAR_SEARCHES) {
|
||||
if (start->numLinearSearches() == LINEAR_SEARCHES_MAX) {
|
||||
if (start->hashify(cx))
|
||||
return start->table().search(id, adding);
|
||||
/* OOM! Don't increment numLinearSearches, to keep hasTable() false. */
|
||||
JS_ASSERT(!start->hasTable());
|
||||
} else {
|
||||
JS_ASSERT(start->numLinearSearches < PropertyTable::MAX_LINEAR_SEARCHES);
|
||||
start->numLinearSearches++;
|
||||
start->incrementNumLinearSearches();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -57,11 +57,6 @@
|
|||
#include "jsgcinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
JS_STATIC_ASSERT(js::gc::FINALIZE_OBJECT0 % 2 == 0);
|
||||
JS_STATIC_ASSERT(js::gc::FINALIZE_FUNCTION == js::gc::FINALIZE_OBJECT_LAST + 1);
|
||||
static const uint32 TYPE_OBJECT_EMPTY_SHAPE_COUNT =
|
||||
((js::gc::FINALIZE_FUNCTION - js::gc::FINALIZE_OBJECT0) / 2) + 1;
|
||||
|
||||
inline js::EmptyShape *
|
||||
js::types::TypeObject::getEmptyShape(JSContext *cx, js::Class *aclasp, gc::AllocKind kind)
|
||||
{
|
||||
|
@ -74,46 +69,40 @@ js::types::TypeObject::getEmptyShape(JSContext *cx, js::Class *aclasp, gc::Alloc
|
|||
*/
|
||||
JS_ASSERT(proto->hasNewType(this));
|
||||
|
||||
JS_ASSERT(kind >= gc::FINALIZE_OBJECT0 &&
|
||||
kind <= gc::FINALIZE_FUNCTION_AND_OBJECT_LAST);
|
||||
|
||||
JS_STATIC_ASSERT(gc::FINALIZE_OBJECT0 % 2 == 0);
|
||||
JS_STATIC_ASSERT(gc::FINALIZE_FUNCTION == gc::FINALIZE_OBJECT_LAST + 1);
|
||||
int i = (kind - gc::FINALIZE_OBJECT0) / 2;
|
||||
|
||||
if (!emptyShapes) {
|
||||
emptyShapes = (EmptyShape**)
|
||||
cx->calloc_(sizeof(EmptyShape*) * TYPE_OBJECT_EMPTY_SHAPE_COUNT);
|
||||
emptyShapes = cx->new_<ShapeKindArray>();
|
||||
if (!emptyShapes)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Always fill in emptyShapes[0], so canProvideEmptyShape works.
|
||||
* Always fill in the first empty shape, so canProvideEmptyShape works.
|
||||
* Other empty shapes are filled in lazily.
|
||||
*/
|
||||
emptyShapes[0] = EmptyShape::create(cx, aclasp, proto->getParent());
|
||||
if (!emptyShapes[0]) {
|
||||
cx->free_(emptyShapes);
|
||||
Shape *first = EmptyShape::create(cx, aclasp, proto->getParent(), 0);
|
||||
if (!first) {
|
||||
cx->delete_(emptyShapes);
|
||||
emptyShapes = NULL;
|
||||
return NULL;
|
||||
}
|
||||
emptyShapes->get(gc::FINALIZE_OBJECT0) = first;
|
||||
}
|
||||
|
||||
JS_ASSERT(aclasp == emptyShapes[0]->getObjectClass());
|
||||
JS_ASSERT(aclasp == emptyShapes->get(gc::FINALIZE_OBJECT0)->getObjectClass());
|
||||
|
||||
if (!emptyShapes[i]) {
|
||||
emptyShapes[i] = EmptyShape::create(cx, aclasp, proto->getParent());
|
||||
if (!emptyShapes[i])
|
||||
return NULL;
|
||||
Shape *&empty = emptyShapes->get(kind);
|
||||
if (!empty) {
|
||||
empty = EmptyShape::create(cx, aclasp, proto->getParent(),
|
||||
gc::GetGCKindSlots(kind, aclasp));
|
||||
}
|
||||
|
||||
return emptyShapes[i];
|
||||
return static_cast<EmptyShape *>(empty);
|
||||
}
|
||||
|
||||
inline bool
|
||||
js::types::TypeObject::canProvideEmptyShape(js::Class *aclasp)
|
||||
{
|
||||
return proto && !singleton && (!emptyShapes || emptyShapes[0]->getObjectClass() == aclasp);
|
||||
return proto && !singleton &&
|
||||
(!emptyShapes || emptyShapes->get(gc::FINALIZE_OBJECT0)->getObjectClass() == aclasp);
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -139,9 +128,10 @@ inline bool
|
|||
StringObject::init(JSContext *cx, JSString *str)
|
||||
{
|
||||
JS_ASSERT(nativeEmpty());
|
||||
JS_ASSERT(getAllocKind() == gc::FINALIZE_OBJECT2);
|
||||
|
||||
const js::Shape *shape = BaseShape::lookupInitialShape(cx, getClass(), getParent(),
|
||||
lastProperty());
|
||||
gc::FINALIZE_OBJECT2, lastProperty());
|
||||
if (!shape)
|
||||
return false;
|
||||
if (shape != lastProperty()) {
|
||||
|
@ -150,7 +140,7 @@ StringObject::init(JSContext *cx, JSString *str)
|
|||
shape = assignInitialShape(cx);
|
||||
if (!shape)
|
||||
return false;
|
||||
BaseShape::insertInitialShape(cx, shape);
|
||||
BaseShape::insertInitialShape(cx, gc::FINALIZE_OBJECT2, shape);
|
||||
}
|
||||
JS_ASSERT(!nativeEmpty());
|
||||
JS_ASSERT(nativeLookup(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom))->slot() == LENGTH_SLOT);
|
||||
|
@ -179,12 +169,11 @@ BaseShape::adoptUnowned(UnownedBaseShape *other)
|
|||
}
|
||||
|
||||
inline
|
||||
Shape::Shape(BaseShape *base, jsid propid, uint32 slot,
|
||||
Shape::Shape(BaseShape *base, jsid propid, uint32 slot, uint32 nfixed,
|
||||
uintN attrs, uintN flags, intN shortid)
|
||||
: base_(base),
|
||||
propid_(propid),
|
||||
numLinearSearches(0),
|
||||
slot_(slot),
|
||||
slotInfo(slot | (nfixed << FIXED_SLOTS_SHIFT)),
|
||||
attrs(uint8(attrs)),
|
||||
flags(uint8(flags)),
|
||||
shortid_(int16(shortid)),
|
||||
|
@ -200,8 +189,7 @@ inline
|
|||
Shape::Shape(const Shape *other)
|
||||
: base_(other->base()->unowned()),
|
||||
propid_(other->maybePropid()),
|
||||
numLinearSearches(0),
|
||||
slot_(other->maybeSlot()),
|
||||
slotInfo(other->slotInfo & ~LINEAR_SEARCHES_MASK),
|
||||
attrs(other->attrs),
|
||||
flags(other->flags),
|
||||
shortid_(other->maybeShortid()),
|
||||
|
@ -211,11 +199,10 @@ Shape::Shape(const Shape *other)
|
|||
}
|
||||
|
||||
inline
|
||||
Shape::Shape(BaseShape *base)
|
||||
Shape::Shape(BaseShape *base, uint32 nfixed)
|
||||
: base_(base),
|
||||
propid_(JSID_EMPTY),
|
||||
numLinearSearches(0),
|
||||
slot_(SHAPE_INVALID_SLOT >> (32 - SLOT_BITS)),
|
||||
slotInfo(SHAPE_INVALID_SLOT | (nfixed << FIXED_SLOTS_SHIFT)),
|
||||
attrs(JSPROP_SHARED),
|
||||
flags(0),
|
||||
shortid_(0),
|
||||
|
@ -234,7 +221,7 @@ Shape::hash() const
|
|||
hash = JS_ROTATE_LEFT32(hash, 4) ^ (flags & PUBLIC_FLAGS);
|
||||
hash = JS_ROTATE_LEFT32(hash, 4) ^ attrs;
|
||||
hash = JS_ROTATE_LEFT32(hash, 4) ^ shortid_;
|
||||
hash = JS_ROTATE_LEFT32(hash, 4) ^ slot_;
|
||||
hash = JS_ROTATE_LEFT32(hash, 4) ^ maybeSlot();
|
||||
hash = JS_ROTATE_LEFT32(hash, 4) ^ JSID_BITS(propid_);
|
||||
return hash;
|
||||
}
|
||||
|
@ -243,7 +230,7 @@ inline bool
|
|||
Shape::matches(const js::Shape *other) const
|
||||
{
|
||||
return propid_ == other->propid_ &&
|
||||
matchesParamsAfterId(other->base(), other->slot_, other->attrs,
|
||||
matchesParamsAfterId(other->base(), other->maybeSlot(), other->attrs,
|
||||
other->flags, other->shortid_);
|
||||
}
|
||||
|
||||
|
@ -252,7 +239,7 @@ Shape::matchesParamsAfterId(BaseShape *base, uint32 aslot,
|
|||
uintN aattrs, uintN aflags, intN ashortid) const
|
||||
{
|
||||
return base->unowned() == this->base()->unowned() &&
|
||||
slot_ == aslot &&
|
||||
maybeSlot() == aslot &&
|
||||
attrs == aattrs &&
|
||||
((flags ^ aflags) & PUBLIC_FLAGS) == 0 &&
|
||||
shortid_ == ashortid;
|
||||
|
@ -344,7 +331,8 @@ Shape::initDictionaryShape(const Shape &child, Shape **dictp)
|
|||
{
|
||||
UnownedBaseShape *base = child.base()->unowned();
|
||||
|
||||
new (this) Shape(base, child.maybePropid(), child.maybeSlot(), child.attrs,
|
||||
new (this) Shape(base, child.maybePropid(),
|
||||
child.maybeSlot(), child.numFixedSlots(), child.attrs,
|
||||
child.flags | IN_DICTIONARY, child.maybeShortid());
|
||||
|
||||
this->listp = NULL;
|
||||
|
@ -352,8 +340,8 @@ Shape::initDictionaryShape(const Shape &child, Shape **dictp)
|
|||
}
|
||||
|
||||
inline
|
||||
EmptyShape::EmptyShape(BaseShape *base)
|
||||
: js::Shape(base)
|
||||
EmptyShape::EmptyShape(BaseShape *base, uint32 nfixed)
|
||||
: js::Shape(base, nfixed)
|
||||
{
|
||||
/* Only empty shapes can be NON_NATIVE. */
|
||||
if (!getObjectClass()->isNative())
|
||||
|
|
|
@ -168,7 +168,7 @@ Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind)
|
|||
if (!nbase)
|
||||
return NULL;
|
||||
|
||||
Shape child(nbase, id, slot, attrs, Shape::HAS_SHORTID, *indexp);
|
||||
Shape child(nbase, id, slot, 0, attrs, Shape::HAS_SHORTID, *indexp);
|
||||
|
||||
/* Shapes in bindings cannot be dictionaries. */
|
||||
Shape *shape = lastBinding->getChildBinding(cx, child, &lastBinding);
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "jsregexp.h"
|
||||
#include "jsscript.h"
|
||||
#include "jsscope.h"
|
||||
#include "vm/CallObject.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
|
||||
#include "jsscopeinlines.h"
|
||||
|
@ -93,7 +94,11 @@ bool
|
|||
Bindings::ensureShape(JSContext *cx)
|
||||
{
|
||||
if (!lastBinding) {
|
||||
lastBinding = BaseShape::lookupInitialShape(cx, &CallClass, NULL);
|
||||
/* Get an allocation kind to match an empty call object. */
|
||||
gc::AllocKind kind = gc::FINALIZE_OBJECT4;
|
||||
JS_ASSERT(gc::GetGCKindSlots(kind) == CallObject::RESERVED_SLOTS + 1);
|
||||
|
||||
lastBinding = BaseShape::lookupInitialShape(cx, &CallClass, NULL, kind);
|
||||
if (!lastBinding)
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -11093,6 +11093,8 @@ TraceRecorder::record_JSOP_OBJTOP()
|
|||
RecordingStatus
|
||||
TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins)
|
||||
{
|
||||
JS_NOT_REACHED("FIXME");
|
||||
#if 0
|
||||
/*
|
||||
* This function requires that |ctor| be a built-in class function in order
|
||||
* to have an immutable |ctor.prototype| that can be burned into the trace
|
||||
|
@ -11134,12 +11136,15 @@ TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins)
|
|||
JS_ASSERT_IF(clasp != &ArrayClass, proto->getNewType(cx)->emptyShapes[0]->getObjectClass() == clasp);
|
||||
|
||||
proto_ins = w.immpObjGC(proto);
|
||||
#endif
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
RecordingStatus
|
||||
TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins)
|
||||
{
|
||||
JS_NOT_REACHED("FIXME");
|
||||
#if 0
|
||||
#ifdef DEBUG
|
||||
TraceMonitor &localtm = *traceMonitor;
|
||||
#endif
|
||||
|
@ -11163,6 +11168,7 @@ TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins)
|
|||
#endif
|
||||
|
||||
proto_ins = w.immpObjGC(proto);
|
||||
#endif
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -208,6 +208,7 @@ ArrayBuffer::create(JSContext *cx, int32 nbytes)
|
|||
JSObject *obj = NewBuiltinClassInstance(cx, &ArrayBuffer::slowClass);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->getAllocKind() == gc::FINALIZE_OBJECT16);
|
||||
|
||||
if (nbytes < 0) {
|
||||
/*
|
||||
|
@ -221,7 +222,8 @@ ArrayBuffer::create(JSContext *cx, int32 nbytes)
|
|||
|
||||
JS_ASSERT(obj->getClass() == &ArrayBuffer::slowClass);
|
||||
|
||||
js::Shape *empty = BaseShape::lookupInitialShape(cx, &ArrayBufferClass, obj->getParent());
|
||||
js::Shape *empty = BaseShape::lookupInitialShape(cx, &ArrayBufferClass, obj->getParent(),
|
||||
gc::FINALIZE_OBJECT16);
|
||||
if (!empty)
|
||||
return false;
|
||||
obj->setLastPropertyInfallible(empty);
|
||||
|
@ -1264,6 +1266,7 @@ class TypedArrayTemplate
|
|||
JSObject *obj = NewBuiltinClassInstance(cx, slowClass());
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->getAllocKind() == gc::FINALIZE_OBJECT8);
|
||||
|
||||
/*
|
||||
* Specialize the type of the object on the current scripted location,
|
||||
|
@ -1297,7 +1300,8 @@ class TypedArrayTemplate
|
|||
|
||||
JS_ASSERT(obj->getClass() == slowClass());
|
||||
|
||||
js::Shape *empty = BaseShape::lookupInitialShape(cx, fastClass(), obj->getParent());
|
||||
js::Shape *empty = BaseShape::lookupInitialShape(cx, fastClass(), obj->getParent(),
|
||||
gc::FINALIZE_OBJECT8);
|
||||
if (!empty)
|
||||
return false;
|
||||
obj->setLastPropertyInfallible(empty);
|
||||
|
|
|
@ -316,7 +316,7 @@ LoopState::entryRedundant(const InvariantEntry &e0, const InvariantEntry &e1)
|
|||
int32 c1 = e1.u.check.constant;
|
||||
|
||||
/*
|
||||
* initialized lengths are always <= JSObject::NSLOTS_LIMIT, check for
|
||||
* initialized lengths are always <= JSObject::NELEMENTS_LIMIT, check for
|
||||
* integer overflow checks redundant given initialized length checks.
|
||||
* If Y <= c0 and Y + c1 < initlen(array):
|
||||
*
|
||||
|
@ -331,7 +331,7 @@ LoopState::entryRedundant(const InvariantEntry &e0, const InvariantEntry &e1)
|
|||
constant = c0;
|
||||
else if (!SafeAdd(c0, c1, &constant))
|
||||
return false;
|
||||
return constant >= JSObject::NSLOTS_LIMIT;
|
||||
return constant >= (int32) JSObject::NELEMENTS_LIMIT;
|
||||
}
|
||||
|
||||
/* Look for matching tests that differ only in their constants. */
|
||||
|
|
|
@ -55,20 +55,7 @@ CallObject *
|
|||
CallObject::create(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *callee)
|
||||
{
|
||||
Bindings &bindings = script->bindings;
|
||||
size_t argsVars = bindings.countArgsAndVars();
|
||||
size_t slots = RESERVED_SLOTS + argsVars + 1; /* Add one for privateData. */
|
||||
gc::AllocKind kind = gc::GetGCObjectKind(slots);
|
||||
|
||||
/*
|
||||
* Make sure that the arguments and variables in the call object all end up
|
||||
* in a contiguous range of slots. We need this to be able to embed the
|
||||
* args/vars arrays in the TypeScriptNesting for the function, after the
|
||||
* call object's frame has finished.
|
||||
*/
|
||||
if (cx->typeInferenceEnabled() && gc::GetGCKindSlots(kind) < slots) {
|
||||
kind = gc::GetGCObjectKind(RESERVED_SLOTS + 1);
|
||||
JS_ASSERT(gc::GetGCKindSlots(kind) == RESERVED_SLOTS + 1);
|
||||
}
|
||||
gc::AllocKind kind = gc::GetGCObjectKind(bindings.lastShape()->numFixedSlots() + 1);
|
||||
|
||||
JSObject *obj = js_NewGCObject(cx, kind);
|
||||
if (!obj)
|
||||
|
|
Загрузка…
Ссылка в новой задаче