Bug 556187 - encapsulate JSSLOT_ARRAY_* within JSObject. r=brendan.

This commit is contained in:
Nicholas Nethercote
2010-04-05 18:32:16 -07:00
parent d912ae9572
commit 25fcbe355b
8 changed files with 189 additions and 107 deletions

View File

@@ -103,6 +103,7 @@
#include "jsvector.h"
#include "jsatominlines.h"
#include "jsobjinlines.h"
using namespace js;
@@ -122,7 +123,7 @@ INDEX_TOO_BIG(jsuint index)
#define INDEX_TOO_SPARSE(array, index) \
(INDEX_TOO_BIG(index) || \
((index) > js_DenseArrayCapacity(array) && (index) >= MIN_SPARSE_INDEX && \
(index) > (uint32)((array)->fslots[JSSLOT_ARRAY_COUNT] + 1) * 4))
(index) > ((array)->getArrayCount() + 1) * 4))
JS_STATIC_ASSERT(sizeof(JSScopeProperty) > 4 * sizeof(jsval));
@@ -227,7 +228,7 @@ JSBool
js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
{
if (obj->isArray()) {
*lengthp = obj->fslots[JSSLOT_ARRAY_LENGTH];
*lengthp = obj->getArrayLength();
return true;
}
@@ -497,10 +498,10 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, jsval v)
JS_ASSERT(idx + 1 > idx);
if (!EnsureCapacity(cx, obj, idx + 1))
return JS_FALSE;
if (idx >= uint32(obj->fslots[JSSLOT_ARRAY_LENGTH]))
obj->fslots[JSSLOT_ARRAY_LENGTH] = idx + 1;
if (idx >= obj->getArrayLength())
obj->setArrayLength(idx + 1);
if (obj->dslots[idx] == JSVAL_HOLE)
obj->fslots[JSSLOT_ARRAY_COUNT]++;
obj->incArrayCountBy(1);
obj->dslots[idx] = v;
return JS_TRUE;
}
@@ -528,7 +529,7 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index)
jsuint idx = jsuint(index);
if (!INDEX_TOO_SPARSE(obj, idx) && idx < js_DenseArrayCapacity(obj)) {
if (obj->dslots[idx] != JSVAL_HOLE)
obj->fslots[JSSLOT_ARRAY_COUNT]--;
obj->decArrayCountBy(1);
obj->dslots[idx] = JSVAL_HOLE;
return JS_TRUE;
}
@@ -619,7 +620,7 @@ array_length_getter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
do {
if (obj->isArray())
return IndexToValue(cx, obj->fslots[JSSLOT_ARRAY_LENGTH], vp);
return IndexToValue(cx, obj->getArrayLength(), vp);
} while ((obj = obj->getProto()) != NULL);
return JS_TRUE;
}
@@ -639,7 +640,7 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
newlen = ValueIsLength(cx, vp);
if (JSVAL_IS_NULL(*vp))
return false;
oldlen = obj->fslots[JSSLOT_ARRAY_LENGTH];
oldlen = obj->getArrayLength();
if (oldlen == newlen)
return true;
@@ -648,7 +649,7 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
return false;
if (oldlen < newlen) {
obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen;
obj->setArrayLength(newlen);
return true;
}
@@ -691,7 +692,7 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
}
}
obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen;
obj->setArrayLength(newlen);
return true;
}
@@ -707,7 +708,7 @@ IsDenseArrayId(JSContext *cx, JSObject *obj, jsid id)
uint32 i;
return id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom) ||
(js_IdIsIndex(id, &i) &&
obj->fslots[JSSLOT_ARRAY_LENGTH] != 0 &&
obj->getArrayLength() != 0 &&
i < js_DenseArrayCapacity(obj) &&
obj->dslots[i] != JSVAL_HOLE);
}
@@ -750,7 +751,7 @@ js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, JSProperty *prop,
uint32 i;
if (!js_IdIsIndex(id, &i)) {
JS_ASSERT(id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom));
return IndexToValue(cx, obj->fslots[JSSLOT_ARRAY_LENGTH], vp);
return IndexToValue(cx, obj->getArrayLength(), vp);
}
*vp = obj->dslots[i];
return JS_TRUE;
@@ -762,7 +763,7 @@ array_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
uint32 i;
if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom))
return IndexToValue(cx, obj->fslots[JSSLOT_ARRAY_LENGTH], vp);
return IndexToValue(cx, obj->getArrayLength(), vp);
if (id == ATOM_TO_JSID(cx->runtime->atomState.protoAtom)) {
*vp = OBJECT_TO_JSVAL(obj->getProto());
@@ -811,9 +812,9 @@ slowarray_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
if (!js_IdIsIndex(id, &index))
return JS_TRUE;
length = obj->fslots[JSSLOT_ARRAY_LENGTH];
length = obj->getArrayLength();
if (index >= length)
obj->fslots[JSSLOT_ARRAY_LENGTH] = index + 1;
obj->setArrayLength(index + 1);
return JS_TRUE;
}
@@ -867,10 +868,10 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
if (!EnsureCapacity(cx, obj, i + 1))
return JS_FALSE;
if (i >= (uint32)obj->fslots[JSSLOT_ARRAY_LENGTH])
obj->fslots[JSSLOT_ARRAY_LENGTH] = i + 1;
if (i >= obj->getArrayLength())
obj->setArrayLength(i + 1);
if (obj->dslots[i] == JSVAL_HOLE)
obj->fslots[JSSLOT_ARRAY_COUNT]++;
obj->incArrayCountBy(1);
obj->dslots[i] = *vp;
return JS_TRUE;
}
@@ -927,9 +928,9 @@ dense_grow(JSContext* cx, JSObject* obj, jsint i, jsval v)
if (js_PrototypeHasIndexedProperties(cx, obj))
return JS_FALSE;
if (u >= jsuint(obj->fslots[JSSLOT_ARRAY_LENGTH]))
obj->fslots[JSSLOT_ARRAY_LENGTH] = u + 1;
++obj->fslots[JSSLOT_ARRAY_COUNT];
if (u >= obj->getArrayLength())
obj->setArrayLength(u + 1);
obj->incArrayCountBy(1);
}
obj->dslots[u] = v;
@@ -1039,7 +1040,7 @@ array_deleteProperty(JSContext *cx, JSObject *obj, jsval id, jsval *rval)
if (js_IdIsIndex(id, &i) && i < js_DenseArrayCapacity(obj) &&
obj->dslots[i] != JSVAL_HOLE) {
obj->fslots[JSSLOT_ARRAY_COUNT]--;
obj->decArrayCountBy(1);
obj->dslots[i] = JSVAL_HOLE;
}
@@ -1120,7 +1121,7 @@ array_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
JS_ASSERT(obj->isDenseArray());
capacity = js_DenseArrayCapacity(obj);
if (idp)
*idp = INT_TO_JSVAL(obj->fslots[JSSLOT_ARRAY_COUNT]);
*idp = INT_TO_JSVAL(obj->getArrayCount());
ii = NULL;
for (i = 0; i != capacity; ++i) {
if (obj->dslots[i] == JSVAL_HOLE) {
@@ -1338,15 +1339,13 @@ js_MakeArraySlow(JSContext *cx, JSObject *obj)
}
/*
* Render our formerly-reserved count property GC-safe.
* We do not need to make the length slot GC-safe as this slot is private
* where the implementation can store an arbitrary value.
* Render our formerly-reserved count property GC-safe. We do not need to
* make the length slot GC-safe because it is the private slot (this is
* statically asserted within JSObject) where the implementation can store
* an arbitrary value.
*/
{
JS_STATIC_ASSERT(JSSLOT_ARRAY_LENGTH == JSSLOT_PRIVATE);
JS_ASSERT(js_SlowArrayClass.flags & JSCLASS_HAS_PRIVATE);
obj->fslots[JSSLOT_ARRAY_COUNT] = JSVAL_VOID;
}
JS_ASSERT(js_SlowArrayClass.flags & JSCLASS_HAS_PRIVATE);
obj->voidDenseArrayCount();
/* Make sure we preserve any flags borrowing bits in classword. */
obj->classword ^= (jsuword) &js_ArrayClass;
@@ -1659,8 +1658,8 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva
if (!EnsureCapacity(cx, obj, newlen))
return JS_FALSE;
if (newlen > uint32(obj->fslots[JSSLOT_ARRAY_LENGTH]))
obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen;
if (newlen > obj->getArrayLength())
obj->setArrayLength(newlen);
JS_ASSERT(count < size_t(-1) / sizeof(jsval));
if (targetType == TargetElementsMayContainValues) {
@@ -1669,19 +1668,19 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva
if (obj->dslots[start + i] != JSVAL_HOLE)
valueCount++;
}
JS_ASSERT(uint32(obj->fslots[JSSLOT_ARRAY_COUNT]) >= valueCount);
obj->fslots[JSSLOT_ARRAY_COUNT] -= valueCount;
JS_ASSERT(obj->getArrayCount() >= valueCount);
obj->decArrayCountBy(valueCount);
}
memcpy(obj->dslots + start, vector, sizeof(jsval) * count);
if (vectorType == SourceVectorAllValues) {
obj->fslots[JSSLOT_ARRAY_COUNT] += count;
obj->incArrayCountBy(count);
} else {
jsuint valueCount = 0;
for (jsuint i = 0; i < count; i++) {
if (obj->dslots[start + i] != JSVAL_HOLE)
valueCount++;
}
obj->fslots[JSSLOT_ARRAY_COUNT] += valueCount;
obj->incArrayCountBy(valueCount);
}
JS_ASSERT_IF(count != 0, obj->dslots[newlen - 1] != JSVAL_HOLE);
return JS_TRUE;
@@ -1728,7 +1727,7 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const jsval *vector
{
JS_ASSERT(obj->isArray());
obj->fslots[JSSLOT_ARRAY_LENGTH] = length;
obj->setArrayLength(length);
if (vector) {
if (!EnsureCapacity(cx, obj, length))
@@ -1744,9 +1743,9 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const jsval *vector
obj->dslots[i] = vector[i];
}
}
obj->fslots[JSSLOT_ARRAY_COUNT] = count;
obj->setArrayCount(count);
} else {
obj->fslots[JSSLOT_ARRAY_COUNT] = 0;
obj->setArrayCount(0);
}
return JS_TRUE;
}
@@ -2353,7 +2352,7 @@ array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *
static JSBool
array_push1_dense(JSContext* cx, JSObject* obj, jsval v, jsval *rval)
{
uint32 length = obj->fslots[JSSLOT_ARRAY_LENGTH];
uint32 length = obj->getArrayLength();
if (INDEX_TOO_SPARSE(obj, length)) {
if (!js_MakeArraySlow(cx, obj))
return JS_FALSE;
@@ -2362,19 +2361,19 @@ array_push1_dense(JSContext* cx, JSObject* obj, jsval v, jsval *rval)
if (!EnsureCapacity(cx, obj, length + 1))
return JS_FALSE;
obj->fslots[JSSLOT_ARRAY_LENGTH] = length + 1;
obj->setArrayLength(length + 1);
JS_ASSERT(obj->dslots[length] == JSVAL_HOLE);
obj->fslots[JSSLOT_ARRAY_COUNT]++;
obj->incArrayCountBy(1);
obj->dslots[length] = v;
return IndexToValue(cx, obj->fslots[JSSLOT_ARRAY_LENGTH], rval);
return IndexToValue(cx, obj->getArrayLength(), rval);
}
JSBool JS_FASTCALL
js_ArrayCompPush(JSContext *cx, JSObject *obj, jsval v)
{
JS_ASSERT(obj->isDenseArray());
uint32_t length = (uint32_t) obj->fslots[JSSLOT_ARRAY_LENGTH];
uint32_t length = obj->getArrayLength();
JS_ASSERT(length <= js_DenseArrayCapacity(obj));
if (length == js_DenseArrayCapacity(obj)) {
@@ -2387,8 +2386,8 @@ js_ArrayCompPush(JSContext *cx, JSObject *obj, jsval v)
if (!EnsureCapacity(cx, obj, length + 1))
return JS_FALSE;
}
obj->fslots[JSSLOT_ARRAY_LENGTH] = length + 1;
obj->fslots[JSSLOT_ARRAY_COUNT]++;
obj->setArrayLength(length + 1);
obj->incArrayCountBy(1);
obj->dslots[length] = v;
return JS_TRUE;
}
@@ -2453,7 +2452,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, jsval *vp)
jsuint index;
JSBool hole;
index = obj->fslots[JSSLOT_ARRAY_LENGTH];
index = obj->getArrayLength();
if (index == 0) {
*vp = JSVAL_VOID;
return JS_TRUE;
@@ -2463,7 +2462,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, jsval *vp)
return JS_FALSE;
if (!hole && !DeleteArrayElement(cx, obj, index))
return JS_FALSE;
obj->fslots[JSSLOT_ARRAY_LENGTH] = index;
obj->setArrayLength(index);
return JS_TRUE;
}
@@ -2517,7 +2516,7 @@ array_shift(JSContext *cx, uintN argc, jsval *vp)
if (*vp == JSVAL_HOLE)
*vp = JSVAL_VOID;
else
obj->fslots[JSSLOT_ARRAY_COUNT]--;
obj->decArrayCountBy(1);
memmove(obj->dslots, obj->dslots + 1, length * sizeof(jsval));
obj->dslots[length] = JSVAL_HOLE;
} else {
@@ -2526,7 +2525,7 @@ array_shift(JSContext *cx, uintN argc, jsval *vp)
* with an explicitly set non-zero length when shift() is called on
* it, but note fallthrough to reduce the length by one.
*/
JS_ASSERT(obj->fslots[JSSLOT_ARRAY_COUNT] == 0);
JS_ASSERT(obj->getArrayCount() == 0);
*vp = JSVAL_VOID;
}
} else {
@@ -2678,8 +2677,7 @@ array_splice(JSContext *cx, uintN argc, jsval *vp)
!js_PrototypeHasIndexedProperties(cx, obj2) &&
end <= js_DenseArrayCapacity(obj)) {
if (!InitArrayObject(cx, obj2, count, obj->dslots + begin,
obj->fslots[JSSLOT_ARRAY_COUNT] !=
obj->fslots[JSSLOT_ARRAY_LENGTH])) {
obj->getArrayCount() != obj->getArrayLength())) {
return JS_FALSE;
}
} else {
@@ -2713,10 +2711,10 @@ array_splice(JSContext *cx, uintN argc, jsval *vp)
jsval srcval = obj->dslots[last];
jsval* dest = &obj->dslots[last + delta];
if (*dest == JSVAL_HOLE && srcval != JSVAL_HOLE)
obj->fslots[JSSLOT_ARRAY_COUNT]++;
obj->incArrayCountBy(1);
*dest = srcval;
}
obj->fslots[JSSLOT_ARRAY_LENGTH] += delta;
obj->setArrayLength(obj->getArrayLength() + delta);
} else {
/* (uint) end could be 0, so we can't use a vanilla >= test. */
while (last-- > end) {
@@ -2737,7 +2735,7 @@ array_splice(JSContext *cx, uintN argc, jsval *vp)
jsval srcval = obj->dslots[last];
jsval* dest = &obj->dslots[last - delta];
if (*dest == JSVAL_HOLE && srcval != JSVAL_HOLE)
obj->fslots[JSSLOT_ARRAY_COUNT]++;
obj->incArrayCountBy(1);
*dest = srcval;
}
} else {
@@ -2788,14 +2786,13 @@ array_concat(JSContext *cx, uintN argc, jsval *vp)
* where length is <= capacity, nobj and aobj will have the same
* capacity.
*/
length = aobj->fslots[JSSLOT_ARRAY_LENGTH];
length = aobj->getArrayLength();
jsuint capacity = js_DenseArrayCapacity(aobj);
nobj = js_NewArrayObject(cx, JS_MIN(length, capacity), aobj->dslots,
aobj->fslots[JSSLOT_ARRAY_COUNT] !=
(jsval) length);
aobj->getArrayCount() != length);
if (!nobj)
return JS_FALSE;
nobj->fslots[JSSLOT_ARRAY_LENGTH] = length;
nobj->setArrayLength(length);
*vp = OBJECT_TO_JSVAL(nobj);
if (argc == 0)
return JS_TRUE;
@@ -2909,8 +2906,7 @@ array_slice(JSContext *cx, uintN argc, jsval *vp)
if (obj->isDenseArray() && end <= js_DenseArrayCapacity(obj) &&
!js_PrototypeHasIndexedProperties(cx, obj)) {
nobj = js_NewArrayObject(cx, end - begin, obj->dslots + begin,
obj->fslots[JSSLOT_ARRAY_COUNT] !=
obj->fslots[JSSLOT_ARRAY_LENGTH]);
obj->getArrayCount() != obj->getArrayLength());
if (!nobj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(nobj);
@@ -3357,9 +3353,6 @@ js_Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return InitArrayObject(cx, obj, length, vector);
}
JS_STATIC_ASSERT(JSSLOT_PRIVATE == JSSLOT_ARRAY_LENGTH);
JS_STATIC_ASSERT(JSSLOT_ARRAY_LENGTH + 1 == JSSLOT_ARRAY_COUNT);
JSObject* JS_FASTCALL
js_NewEmptyArray(JSContext* cx, JSObject* proto)
{
@@ -3375,10 +3368,9 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto)
obj->setProto(proto);
obj->setParent(proto->getParent());
obj->fslots[JSSLOT_ARRAY_LENGTH] = 0;
obj->fslots[JSSLOT_ARRAY_COUNT] = 0;
for (unsigned i = JSSLOT_ARRAY_COUNT + 1; i != JS_INITIAL_NSLOTS; ++i)
obj->fslots[i] = JSVAL_VOID;
obj->setArrayLength(0);
obj->setArrayCount(0);
obj->voidArrayUnused();
obj->dslots = NULL;
return obj;
}
@@ -3394,7 +3386,7 @@ js_NewEmptyArrayWithLength(JSContext* cx, JSObject* proto, int32 len)
JSObject *obj = js_NewEmptyArray(cx, proto);
if (!obj)
return NULL;
obj->fslots[JSSLOT_ARRAY_LENGTH] = len;
obj->setArrayLength(len);
return obj;
}
#ifdef JS_TRACER
@@ -3408,7 +3400,7 @@ js_NewArrayWithSlots(JSContext* cx, JSObject* proto, uint32 len)
JSObject* obj = js_NewEmptyArray(cx, proto);
if (!obj)
return NULL;
obj->fslots[JSSLOT_ARRAY_LENGTH] = len;
obj->setArrayLength(len);
if (!ResizeSlots(cx, obj, 0, JS_MAX(len, ARRAY_CAPACITY_MIN)))
return NULL;
return obj;
@@ -3459,7 +3451,7 @@ js_NewSlowArrayObject(JSContext *cx)
{
JSObject *obj = js_NewObject(cx, &js_SlowArrayClass, NULL, NULL);
if (obj)
obj->fslots[JSSLOT_ARRAY_LENGTH] = 0;
obj->setArrayLength(0);
return obj;
}
@@ -3485,10 +3477,10 @@ js_ArrayInfo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
}
fprintf(stderr, "%s: %s (len %lu", bytes,
array->isDenseArray()) ? "dense" : "sparse",
array->fslots[JSSLOT_ARRAY_LENGTH]);
array->getArrayLength());
if (array->isDenseArray()) {
fprintf(stderr, ", count %lu, capacity %lu",
array->fslots[JSSLOT_ARRAY_COUNT],
array->getArrayCount(),
js_DenseArrayCapacity(array));
}
fputs(")\n", stderr);
@@ -3507,7 +3499,7 @@ js_CoerceArrayToCanvasImageData(JSObject *obj, jsuint offset, jsuint count,
if (!obj || !obj->isDenseArray())
return JS_FALSE;
length = obj->fslots[JSSLOT_ARRAY_LENGTH];
length = obj->getArrayLength();
if (length < offset + count)
return JS_FALSE;
@@ -3572,7 +3564,7 @@ js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector)
if (!obj)
return NULL;
obj->fslots[JSSLOT_ARRAY_COUNT] = capacity;
obj->setArrayCount(capacity);
*vector = obj->dslots;
return obj;
}