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 06c049adbc
commit 4542317997
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;
}
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;
}

View File

@ -61,10 +61,16 @@ JSObject::isDenseArray() const
return getClass() == &js_ArrayClass;
}
inline bool
JSObject::isSlowArray() const
{
return getClass() == &js_SlowArrayClass;
}
inline bool
JSObject::isArray() const
{
return isDenseArray() || getClass() == &js_SlowArrayClass;
return isDenseArray() || isSlowArray();
}
/*
@ -115,10 +121,6 @@ js_NewSlowArrayObject(JSContext *cx);
extern JSBool
js_MakeArraySlow(JSContext *cx, JSObject *obj);
#define JSSLOT_ARRAY_LENGTH JSSLOT_PRIVATE
#define JSSLOT_ARRAY_COUNT (JSSLOT_ARRAY_LENGTH + 1)
#define JSSLOT_ARRAY_UNUSED (JSSLOT_ARRAY_COUNT + 1)
static JS_INLINE uint32
js_DenseArrayCapacity(JSObject *obj)
{

View File

@ -2071,7 +2071,7 @@ obj_keys(JSContext *cx, uintN argc, jsval *vp)
}
JS_ASSERT(len <= UINT32_MAX);
aobj->fslots[JSSLOT_ARRAY_COUNT] = len;
aobj->setArrayCount(len);
return JS_TRUE;
}
@ -2513,7 +2513,7 @@ DefinePropertyArray(JSContext *cx, JSObject *obj, const PropertyDescriptor &desc
if (obj->isDenseArray() && !js_MakeArraySlow(cx, obj))
return JS_FALSE;
jsuint oldLen = obj->fslots[JSSLOT_ARRAY_LENGTH];
jsuint oldLen = obj->getArrayLength();
if (desc.id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) {
/*
@ -2541,7 +2541,7 @@ DefinePropertyArray(JSContext *cx, JSObject *obj, const PropertyDescriptor &desc
if (index >= oldLen) {
JS_ASSERT(index != UINT32_MAX);
obj->fslots[JSSLOT_ARRAY_LENGTH] = index + 1;
obj->setArrayLength(index + 1);
}
*rval = true;
@ -6937,8 +6937,7 @@ js_DumpObject(JSObject *obj)
fprintf(stderr, "class %p %s\n", (void *)clasp, clasp->name);
if (obj->isDenseArray()) {
slots = JS_MIN((jsuint) obj->fslots[JSSLOT_ARRAY_LENGTH],
js_DenseArrayCapacity(obj));
slots = JS_MIN(obj->getArrayLength(), js_DenseArrayCapacity(obj));
fprintf(stderr, "elements\n");
for (i = 0; i < slots; i++) {
fprintf(stderr, " %3d: ", i);

View File

@ -248,6 +248,12 @@ const uintptr_t JSSLOT_CLASS_MASK_BITS = 3;
* records the number of available slots.
*/
struct JSObject {
/*
* TraceRecorder must be a friend because it generates code that
* manipulates JSObjects, which requires peeking under any encapsulation.
*/
friend class js::TraceRecorder;
JSObjectMap *map; /* property map, see jsscope.h */
jsuword classword; /* JSClass ptr | bits, see above */
jsval fslots[JS_INITIAL_NSLOTS]; /* small number of fixed slots */
@ -378,6 +384,33 @@ struct JSObject {
: JSVAL_VOID;
}
/*
* Array-specific getters and setters (for both dense and slow arrays).
*/
private:
static const uint32 JSSLOT_ARRAY_LENGTH = JSSLOT_PRIVATE;
static const uint32 JSSLOT_ARRAY_COUNT = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_ARRAY_UNUSED = JSSLOT_PRIVATE + 2;
// This must remain true; see comment in js_MakeArraySlow().
JS_STATIC_ASSERT(JSSLOT_ARRAY_LENGTH == JSSLOT_PRIVATE);
public:
inline uint32 getArrayLength() const;
inline uint32 getArrayCount() const;
inline void setArrayLength(uint32 length);
inline void setArrayCount(uint32 count);
inline void voidDenseArrayCount();
inline void incArrayCountBy(uint32 posDelta);
inline void decArrayCountBy(uint32 negDelta);
inline void voidArrayUnused();
/*
* Back to generic stuff.
*/
bool isCallable();
/* The map field is not initialized here and should be set separately. */
@ -477,6 +510,7 @@ struct JSObject {
inline bool isArguments() const;
inline bool isArray() const;
inline bool isDenseArray() const;
inline bool isSlowArray() const;
inline bool isFunction() const;
inline bool isRegExp() const;
inline bool isXML() const;

View File

@ -45,7 +45,8 @@
#include "jsscope.h"
inline jsval
JSObject::getSlotMT(JSContext *cx, uintN slot) {
JSObject::getSlotMT(JSContext *cx, uintN slot)
{
#ifdef JS_THREADSAFE
/*
* If thread-safe, define a getSlotMT() that bypasses, for a native
@ -66,7 +67,8 @@ JSObject::getSlotMT(JSContext *cx, uintN slot) {
}
inline void
JSObject::setSlotMT(JSContext *cx, uintN slot, jsval value) {
JSObject::setSlotMT(JSContext *cx, uintN slot, jsval value)
{
#ifdef JS_THREADSAFE
/* Thread-safe way to set a slot. */
OBJ_CHECK_SLOT(this, slot);
@ -79,6 +81,62 @@ JSObject::setSlotMT(JSContext *cx, uintN slot, jsval value) {
#endif
}
inline uint32
JSObject::getArrayLength() const
{
JS_ASSERT(isArray());
return uint32(fslots[JSSLOT_ARRAY_LENGTH]);
}
inline uint32
JSObject::getArrayCount() const
{
JS_ASSERT(isArray());
return uint32(fslots[JSSLOT_ARRAY_COUNT]);
}
inline void
JSObject::setArrayLength(uint32 length)
{
JS_ASSERT(isArray());
fslots[JSSLOT_ARRAY_LENGTH] = length;
}
inline void
JSObject::setArrayCount(uint32 count)
{
JS_ASSERT(isArray());
fslots[JSSLOT_ARRAY_COUNT] = count;
}
inline void
JSObject::voidDenseArrayCount()
{
JS_ASSERT(isDenseArray());
fslots[JSSLOT_ARRAY_COUNT] = JSVAL_VOID;
}
inline void
JSObject::incArrayCountBy(uint32 posDelta)
{
JS_ASSERT(isArray());
fslots[JSSLOT_ARRAY_COUNT] += posDelta;
}
inline void
JSObject::decArrayCountBy(uint32 negDelta)
{
JS_ASSERT(isArray());
fslots[JSSLOT_ARRAY_COUNT] -= negDelta;
}
inline void
JSObject::voidArrayUnused()
{
JS_ASSERT(isArray());
fslots[JSSLOT_ARRAY_COUNT] = JSVAL_VOID;
}
inline void
JSObject::initSharingEmptyScope(JSClass *clasp, JSObject *proto, JSObject *parent,
jsval privateSlotValue)

View File

@ -1523,12 +1523,7 @@ BEGIN_CASE(JSOP_LENGTH)
} else if (!JSVAL_IS_PRIMITIVE(lval)) {
obj = JSVAL_TO_OBJECT(lval);
if (obj->isArray()) {
/*
* We know that the array is created with its 'length' private data
* in a fixed slot at JSSLOT_ARRAY_LENGTH. See also JSOP_ARRAYPUSH,
* far below.
*/
jsuint length = obj->fslots[JSSLOT_ARRAY_LENGTH];
jsuint length = obj->getArrayLength();
if (length <= JSVAL_INT_MAX)
regs.sp[-1] = INT_TO_JSVAL(length);
@ -1876,7 +1871,7 @@ BEGIN_CASE(JSOP_GETELEM)
if (obj->isDenseArray()) {
jsuint idx = jsuint(JSVAL_TO_INT(rval));
if (idx < jsuint(obj->fslots[JSSLOT_ARRAY_LENGTH]) &&
if (idx < obj->getArrayLength() &&
idx < js_DenseArrayCapacity(obj)) {
rval = obj->dslots[idx];
if (rval != JSVAL_HOLE)
@ -1948,9 +1943,9 @@ BEGIN_CASE(JSOP_SETELEM)
if (obj->dslots[i] == JSVAL_HOLE) {
if (js_PrototypeHasIndexedProperties(cx, obj))
break;
if (i >= obj->fslots[JSSLOT_ARRAY_LENGTH])
obj->fslots[JSSLOT_ARRAY_LENGTH] = i + 1;
obj->fslots[JSSLOT_ARRAY_COUNT]++;
if ((jsuint)i >= obj->getArrayLength())
obj->setArrayLength(i + 1);
obj->incArrayCountBy(1);
}
obj->dslots[i] = rval;
goto end_setelem;

View File

@ -10448,7 +10448,7 @@ TraceRecorder::newArray(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval)
}
if (argc > 0)
stobj_set_fslot(arr_ins, JSSLOT_ARRAY_COUNT, INS_CONST(argc));
stobj_set_fslot(arr_ins, JSObject::JSSLOT_ARRAY_COUNT, INS_CONST(argc));
}
set(rval, arr_ins);
@ -12584,10 +12584,10 @@ TraceRecorder::record_JSOP_APPLY()
*/
if (aobj->isDenseArray()) {
guardDenseArray(aobj, aobj_ins, MISMATCH_EXIT);
length = jsuint(aobj->fslots[JSSLOT_ARRAY_LENGTH]);
length = aobj->getArrayLength();
guard(true,
lir->ins2i(LIR_eq,
p2i(stobj_get_fslot(aobj_ins, JSSLOT_ARRAY_LENGTH)),
p2i(stobj_get_fslot(aobj_ins, JSObject::JSSLOT_ARRAY_LENGTH)),
length),
BRANCH_EXIT);
} else if (aobj->isArguments()) {
@ -12957,7 +12957,7 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_
/* check that the index is within bounds */
LIns* dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACC_OTHER);
jsuint capacity = js_DenseArrayCapacity(obj);
bool within = (jsuint(idx) < jsuint(obj->fslots[JSSLOT_ARRAY_LENGTH]) && jsuint(idx) < capacity);
bool within = (jsuint(idx) < obj->getArrayLength() && jsuint(idx) < capacity);
if (!within) {
/* If idx < 0, stay on trace (and read value as undefined, since this is a dense array). */
LIns* br1 = NULL;
@ -12973,7 +12973,7 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_
LIns* br2 = lir->insBranch(LIR_jf,
lir->ins2(LIR_pult,
pidx_ins,
stobj_get_fslot(obj_ins, JSSLOT_ARRAY_LENGTH)),
stobj_get_fslot(obj_ins, JSObject::JSSLOT_ARRAY_LENGTH)),
NULL);
/* If dslots is NULL, stay on trace (and read value as undefined). */
@ -13013,7 +13013,7 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_
/* Guard array length */
guard(true,
lir->ins2(LIR_pult, pidx_ins, stobj_get_fslot(obj_ins, JSSLOT_ARRAY_LENGTH)),
lir->ins2(LIR_pult, pidx_ins, stobj_get_fslot(obj_ins, JSObject::JSSLOT_ARRAY_LENGTH)),
exit);
/* dslots must not be NULL */
@ -15026,7 +15026,7 @@ TraceRecorder::record_JSOP_LENGTH()
if (!guardClass(obj, obj_ins, &js_SlowArrayClass, snapshot(BRANCH_EXIT), ACC_OTHER))
RETURN_STOP_A("can't trace length property access on non-array");
}
v_ins = lir->ins1(LIR_i2f, p2i(stobj_get_fslot(obj_ins, JSSLOT_ARRAY_LENGTH)));
v_ins = lir->ins1(LIR_i2f, p2i(stobj_get_fslot(obj_ins, JSObject::JSSLOT_ARRAY_LENGTH)));
} else if (OkToTraceTypedArrays && js_IsTypedArray(obj)) {
// Ensure array is a typed array and is the same type as what was written
guardClass(obj, obj_ins, obj->getClass(), snapshot(BRANCH_EXIT), ACC_OTHER);
@ -15066,7 +15066,7 @@ TraceRecorder::record_JSOP_NEWARRAY()
}
if (count > 0)
stobj_set_fslot(v_ins, JSSLOT_ARRAY_COUNT, INS_CONST(count));
stobj_set_fslot(v_ins, JSObject::JSSLOT_ARRAY_COUNT, INS_CONST(count));
stack(-int(len), v_ins);
return ARECORD_CONTINUE;

View File

@ -63,6 +63,8 @@
#include "jsvector.h"
#include "jstypedarray.h"
#include "jsobjinlines.h"
using namespace js;
/*
@ -1014,7 +1016,7 @@ class TypedArrayTemplate
NativeType *dest = static_cast<NativeType*>(data);
if (ar->isDenseArray() && js_DenseArrayCapacity(ar) >= len) {
JS_ASSERT(ar->fslots[JSSLOT_ARRAY_LENGTH] == (jsval)len);
JS_ASSERT(ar->getArrayLength() == len);
jsval *src = ar->dslots;