Remove JSObject::capacity and JSObject::initializedLength, split JSObject::slots into slots and elements, bug 693221.
This commit is contained in:
@@ -279,7 +279,7 @@ JSObject::willBeSparseDenseArray(uintN requiredCapacity, uintN newElementsHint)
|
||||
JS_ASSERT(isDenseArray());
|
||||
JS_ASSERT(requiredCapacity > MIN_SPARSE_INDEX);
|
||||
|
||||
uintN cap = numSlots();
|
||||
uintN cap = getDenseArrayCapacity();
|
||||
JS_ASSERT(requiredCapacity >= cap);
|
||||
|
||||
if (requiredCapacity >= JSObject::NSLOTS_LIMIT)
|
||||
@@ -631,13 +631,10 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value
|
||||
*/
|
||||
jsuint oldcap = obj->getDenseArrayCapacity();
|
||||
if (oldcap > newlen)
|
||||
obj->shrinkDenseArrayElements(cx, newlen);
|
||||
obj->shrinkElements(cx, newlen);
|
||||
jsuint oldinit = obj->getDenseArrayInitializedLength();
|
||||
if (oldinit > newlen) {
|
||||
if (oldinit > newlen)
|
||||
obj->setDenseArrayInitializedLength(newlen);
|
||||
if (!cx->typeInferenceEnabled())
|
||||
obj->backfillDenseArrayHoles(cx);
|
||||
}
|
||||
} else if (oldlen - newlen < (1 << 24)) {
|
||||
do {
|
||||
--oldlen;
|
||||
@@ -1206,7 +1203,7 @@ array_fix(JSContext *cx, JSObject *obj, bool *success, AutoIdVector *props)
|
||||
|
||||
Class js::ArrayClass = {
|
||||
"Array",
|
||||
Class::NON_NATIVE | JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
|
||||
Class::NON_NATIVE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_PropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
@@ -1273,12 +1270,36 @@ Class js::SlowArrayClass = {
|
||||
JS_ConvertStub
|
||||
};
|
||||
|
||||
bool
|
||||
JSObject::allocateSlowArrayElements(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(hasClass(&js::SlowArrayClass));
|
||||
JS_ASSERT(elements == emptyObjectElements);
|
||||
|
||||
ObjectElements *header = cx->new_<ObjectElements>(0);
|
||||
if (!header)
|
||||
return false;
|
||||
|
||||
elements = header->elements();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
AddLengthProperty(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
/*
|
||||
* Add the 'length' property for a newly created or converted slow array,
|
||||
* and update the elements to be an empty array owned by the object.
|
||||
* The shared emptyObjectElements singleton cannot be used for slow arrays,
|
||||
* as accesses to 'length' will use the elements header.
|
||||
*/
|
||||
|
||||
const jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
||||
JS_ASSERT(!obj->nativeLookup(cx, lengthId));
|
||||
|
||||
if (!obj->allocateSlowArrayElements(cx))
|
||||
return false;
|
||||
|
||||
return obj->addProperty(cx, lengthId, array_length_getter, array_length_setter,
|
||||
SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0);
|
||||
}
|
||||
@@ -1294,21 +1315,18 @@ JSObject::makeDenseArraySlow(JSContext *cx)
|
||||
MarkTypeObjectFlags(cx, this,
|
||||
OBJECT_FLAG_NON_PACKED_ARRAY |
|
||||
OBJECT_FLAG_NON_DENSE_ARRAY);
|
||||
markDenseArrayNotPacked(cx);
|
||||
backfillDenseArrayHoles(cx);
|
||||
|
||||
uint32 arrayCapacity = getDenseArrayCapacity();
|
||||
uint32 arrayInitialized = getDenseArrayInitializedLength();
|
||||
|
||||
/*
|
||||
* Adjust the slots to account for the different layout between dense
|
||||
* arrays and other objects. The slots must be dynamic, and the fixed slots
|
||||
* are now available for newly added properties.
|
||||
* Get an allocated array of the existing elements, evicting from the fixed
|
||||
* slots if necessary.
|
||||
*/
|
||||
if (denseArrayHasInlineSlots()) {
|
||||
if (!allocSlots(cx, numSlots()))
|
||||
if (!hasDynamicElements()) {
|
||||
if (!growElements(cx, arrayCapacity))
|
||||
return false;
|
||||
JS_ASSERT(!denseArrayHasInlineSlots());
|
||||
JS_ASSERT(hasDynamicElements());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1316,32 +1334,31 @@ JSObject::makeDenseArraySlow(JSContext *cx)
|
||||
* on error. This is gross, but a better way is not obvious. Note: the
|
||||
* exact contents of the array are not preserved on error.
|
||||
*/
|
||||
js::Shape *oldMap = lastProp;
|
||||
js::Shape *oldShape = lastProperty();
|
||||
shape_ = NULL;
|
||||
|
||||
/* Create a native scope. */
|
||||
gc::AllocKind kind = getAllocKind();
|
||||
if (!InitScopeForObject(cx, this, &SlowArrayClass, getProto()->getNewType(cx), kind))
|
||||
if (!InitScopeForObject(cx, this, &SlowArrayClass, getProto()->getNewType(cx), kind)) {
|
||||
setLastPropertyInfallible(oldShape);
|
||||
return false;
|
||||
}
|
||||
|
||||
capacity = numFixedSlots() + arrayCapacity;
|
||||
/* Take ownership of the dense elements, reset to an empty dense array. */
|
||||
Value *elems = elements;
|
||||
elements = emptyObjectElements;
|
||||
|
||||
/*
|
||||
* Root all values in the array during conversion, as SlowArrayClass only
|
||||
* protects up to its slot span.
|
||||
*/
|
||||
AutoValueArray autoArray(cx, slots, arrayInitialized);
|
||||
|
||||
/* The initialized length is used iff this is a dense array. */
|
||||
initializedLength = 0;
|
||||
/* Root all values in the array during conversion. */
|
||||
AutoValueArray autoArray(cx, elements, arrayInitialized);
|
||||
|
||||
/*
|
||||
* Begin with the length property to share more of the property tree.
|
||||
* The getter/setter here will directly access the object's private value.
|
||||
*/
|
||||
if (!AddLengthProperty(cx, this)) {
|
||||
setMap(oldMap);
|
||||
capacity = arrayCapacity;
|
||||
initializedLength = arrayInitialized;
|
||||
setLastPropertyInfallible(oldShape);
|
||||
cx->free_(getElementsHeader());
|
||||
elements = elems;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1350,27 +1367,30 @@ JSObject::makeDenseArraySlow(JSContext *cx)
|
||||
* remove holes, so that shapes use successive slots (as for other objects).
|
||||
*/
|
||||
uint32 next = 0;
|
||||
for (uint32 i = 0; i < arrayCapacity; i++) {
|
||||
for (uint32 i = 0; i < arrayInitialized; i++) {
|
||||
/* Dense array indexes can always fit in a jsid. */
|
||||
jsid id;
|
||||
JS_ALWAYS_TRUE(ValueToId(cx, Int32Value(i), &id));
|
||||
|
||||
if (slots[i].isMagic(JS_ARRAY_HOLE))
|
||||
if (elems[i].isMagic(JS_ARRAY_HOLE))
|
||||
continue;
|
||||
|
||||
setSlot(next, slots[i]);
|
||||
|
||||
if (!addDataProperty(cx, id, next, JSPROP_ENUMERATE)) {
|
||||
setMap(oldMap);
|
||||
capacity = arrayCapacity;
|
||||
initializedLength = arrayInitialized;
|
||||
JS_ALWAYS_TRUE(setLastProperty(cx, oldShape));
|
||||
cx->free_(getElementsHeader());
|
||||
elements = elems;
|
||||
return false;
|
||||
}
|
||||
|
||||
setSlot(next, elems[i]);
|
||||
|
||||
next++;
|
||||
}
|
||||
|
||||
clearSlotRange(next, capacity - next);
|
||||
ObjectElements *oldheader = ObjectElements::fromElements(elems);
|
||||
|
||||
getElementsHeader()->length = oldheader->length;
|
||||
cx->free_(oldheader);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1796,13 +1816,10 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector
|
||||
return false;
|
||||
|
||||
/* Avoid ensureDenseArrayElements to skip sparse array checks there. */
|
||||
if (!obj->ensureSlots(cx, length))
|
||||
if (!obj->ensureElements(cx, length))
|
||||
return false;
|
||||
|
||||
if (cx->typeInferenceEnabled())
|
||||
obj->setDenseArrayInitializedLength(length);
|
||||
else
|
||||
obj->backfillDenseArrayHoles(cx);
|
||||
obj->setDenseArrayInitializedLength(length);
|
||||
|
||||
bool hole = false;
|
||||
for (jsuint i = 0; i < length; i++) {
|
||||
@@ -2445,11 +2462,10 @@ NewbornArrayPushImpl(JSContext *cx, JSObject *obj, const Value &v)
|
||||
JS_ASSERT(obj->isDenseArray());
|
||||
JS_ASSERT(length <= obj->getDenseArrayCapacity());
|
||||
|
||||
if (length == obj->getDenseArrayCapacity() && !obj->ensureSlots(cx, length + 1))
|
||||
if (!obj->ensureElements(cx, length + 1))
|
||||
return false;
|
||||
|
||||
if (cx->typeInferenceEnabled())
|
||||
obj->setDenseArrayInitializedLength(length + 1);
|
||||
obj->setDenseArrayInitializedLength(length + 1);
|
||||
obj->setDenseArrayLength(length + 1);
|
||||
obj->setDenseArrayElementWithType(cx, length, v);
|
||||
return true;
|
||||
@@ -2531,7 +2547,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, Value *vp)
|
||||
if (!hole && DeleteArrayElement(cx, obj, index, true) < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
if (cx->typeInferenceEnabled() && obj->getDenseArrayInitializedLength() > index)
|
||||
if (obj->getDenseArrayInitializedLength() > index)
|
||||
obj->setDenseArrayInitializedLength(index);
|
||||
obj->setArrayLength(cx, index);
|
||||
return JS_TRUE;
|
||||
@@ -2571,10 +2587,7 @@ array_shift(JSContext *cx, uintN argc, Value *vp)
|
||||
if (vp->isMagic(JS_ARRAY_HOLE))
|
||||
vp->setUndefined();
|
||||
obj->moveDenseArrayElements(0, 1, length);
|
||||
if (cx->typeInferenceEnabled())
|
||||
obj->setDenseArrayInitializedLength(obj->getDenseArrayInitializedLength() - 1);
|
||||
else
|
||||
obj->setDenseArrayElement(length, MagicValue(JS_ARRAY_HOLE));
|
||||
obj->setDenseArrayInitializedLength(obj->getDenseArrayInitializedLength() - 1);
|
||||
obj->setArrayLength(cx, length);
|
||||
if (!js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(length)))
|
||||
return JS_FALSE;
|
||||
@@ -2861,8 +2874,6 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
|
||||
return JS_FALSE;
|
||||
TryReuseArrayType(aobj, nobj);
|
||||
nobj->setArrayLength(cx, length);
|
||||
if (!aobj->isPackedDenseArray())
|
||||
nobj->markDenseArrayNotPacked(cx);
|
||||
vp->setObject(*nobj);
|
||||
if (argc == 0)
|
||||
return JS_TRUE;
|
||||
@@ -2968,8 +2979,6 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
|
||||
if (!nobj)
|
||||
return JS_FALSE;
|
||||
TryReuseArrayType(obj, nobj);
|
||||
if (!obj->isPackedDenseArray())
|
||||
nobj->markDenseArrayNotPacked(cx);
|
||||
vp->setObject(*nobj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
@@ -3477,19 +3486,14 @@ NewArray(JSContext *cx, jsuint length, JSObject *proto)
|
||||
{
|
||||
JS_ASSERT_IF(proto, proto->isArray());
|
||||
|
||||
gc::AllocKind kind = GuessObjectGCKind(length, true);
|
||||
gc::AllocKind kind = GuessArrayGCKind(length);
|
||||
JSObject *obj = detail::NewObject<WithProto::Class, false>(cx, &ArrayClass, proto, NULL, kind);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
obj->setArrayLength(cx, length);
|
||||
|
||||
if (!cx->typeInferenceEnabled()) {
|
||||
obj->markDenseArrayNotPacked(cx);
|
||||
obj->backfillDenseArrayHoles(cx);
|
||||
}
|
||||
|
||||
if (allocateCapacity && !obj->ensureSlots(cx, length))
|
||||
if (allocateCapacity && !obj->ensureElements(cx, length))
|
||||
return NULL;
|
||||
|
||||
return obj;
|
||||
@@ -3542,8 +3546,7 @@ NewDenseCopiedArray(JSContext *cx, uintN length, const Value *vp, JSObject *prot
|
||||
|
||||
JS_ASSERT(obj->getDenseArrayCapacity() >= length);
|
||||
|
||||
if (cx->typeInferenceEnabled())
|
||||
obj->setDenseArrayInitializedLength(vp ? length : 0);
|
||||
obj->setDenseArrayInitializedLength(vp ? length : 0);
|
||||
|
||||
if (vp)
|
||||
obj->copyDenseArrayElements(0, vp, length);
|
||||
|
||||
Reference in New Issue
Block a user