зеркало из https://github.com/mozilla/gecko-dev.git
Remove hole count from dense arrays (580846, r=njn).
This commit is contained in:
Родитель
4617f42c0b
Коммит
3378383935
|
@ -48,20 +48,12 @@
|
|||
*
|
||||
* We track these pieces of metadata for arrays in dense mode:
|
||||
* - The array's length property as a uint32, accessible with
|
||||
* getArrayLength(), setDenseArrayLength().
|
||||
* - The number of indices that are filled (non-holes), accessible with
|
||||
* {get,set}DenseArrayCount().
|
||||
* getArrayLength(), setArrayLength().
|
||||
* - The number of element slots (capacity), gettable with
|
||||
* getDenseArrayCapacity().
|
||||
* - The minimum of length and capacity (minLenCap). There are no explicit
|
||||
* setters, it's updated automatically by setDenseArrayLength() and
|
||||
* setDenseArrayCapacity(). There are also no explicit getters, the only
|
||||
* user is TraceRecorder which can access it directly because it's a
|
||||
* friend. The function isDenseArrayMinLenCapOk() checks that it is set
|
||||
* correctly; a call to it should be put in an assertion at use points.
|
||||
*
|
||||
* In dense mode, holes in the array are represented by (JS_ARRAY_HOLE) invalid
|
||||
* values. The final slot in fslots is unused.
|
||||
* values. The final two slot in fslots are unused.
|
||||
*
|
||||
* NB: the capacity and length of a dense array are entirely unrelated! The
|
||||
* length may be greater than, less than, or equal to the capacity. See
|
||||
|
@ -131,13 +123,26 @@ INDEX_TOO_BIG(jsuint index)
|
|||
return index > JS_BIT(29) - 1;
|
||||
}
|
||||
|
||||
#define INDEX_TOO_SPARSE(array, index) \
|
||||
(INDEX_TOO_BIG(index) || \
|
||||
((index) > array->getDenseArrayCapacity() && (index) >= MIN_SPARSE_INDEX && \
|
||||
(index) > ((array)->getDenseArrayCount() + 1) * 4))
|
||||
static inline bool
|
||||
INDEX_TOO_SPARSE(JSObject *array, jsuint index)
|
||||
{
|
||||
/* Small arrays with less than 256 elements are dense, no matter what. */
|
||||
if (index < 256)
|
||||
return false;
|
||||
|
||||
#define ENSURE_SLOW_ARRAY(cx, obj) \
|
||||
(obj->getClass() == &js_SlowArrayClass || obj->makeDenseArraySlow(cx))
|
||||
/*
|
||||
* Otherwise if the index becomes too large or is more than 256 past
|
||||
* the current capacity, we have to slowify.
|
||||
*/
|
||||
return INDEX_TOO_BIG(index) || (index > array->getDenseArrayCapacity() + 256);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ENSURE_SLOW_ARRAY(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
return obj->getClass() == &js_SlowArrayClass ||
|
||||
obj->makeDenseArraySlow(cx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if the id represents an array index or an XML property index.
|
||||
|
@ -478,9 +483,7 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, const Value &v)
|
|||
if (!obj->ensureDenseArrayElements(cx, idx + 1))
|
||||
return JS_FALSE;
|
||||
if (idx >= obj->getArrayLength())
|
||||
obj->setDenseArrayLength(idx + 1);
|
||||
if (obj->getDenseArrayElement(idx).isMagic(JS_ARRAY_HOLE))
|
||||
obj->incDenseArrayCountBy(1);
|
||||
obj->setArrayLength(idx + 1);
|
||||
obj->setDenseArrayElement(idx, v);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -507,9 +510,7 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index)
|
|||
if (obj->isDenseArray()) {
|
||||
if (index <= jsuint(-1)) {
|
||||
jsuint idx = jsuint(index);
|
||||
if (!INDEX_TOO_SPARSE(obj, idx) && idx < obj->getDenseArrayCapacity()) {
|
||||
if (!obj->getDenseArrayElement(idx).isMagic(JS_ARRAY_HOLE))
|
||||
obj->decDenseArrayCountBy(1);
|
||||
if (idx < obj->getDenseArrayCapacity()) {
|
||||
obj->setDenseArrayElement(idx, MagicValue(JS_ARRAY_HOLE));
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -623,26 +624,28 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
|
||||
vp->setNumber(newlen);
|
||||
if (oldlen < newlen) {
|
||||
if (obj->isDenseArray())
|
||||
obj->setDenseArrayLength(newlen);
|
||||
else
|
||||
obj->setSlowArrayLength(newlen);
|
||||
obj->setArrayLength(newlen);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj->isDenseArray()) {
|
||||
/* Don't reallocate if we're not actually shrinking our slots. */
|
||||
/*
|
||||
* Don't reallocate if we're not actually shrinking our slots. If we do
|
||||
* shrink slots here, resizeDenseArrayElements will fill all slots to the
|
||||
* right of newlen with JS_ARRAY_HOLE. This permits us to disregard
|
||||
* length when reading from arrays as long we are within the capacity.
|
||||
*/
|
||||
jsuint capacity = obj->getDenseArrayCapacity();
|
||||
if (capacity > newlen && !obj->resizeDenseArrayElements(cx, capacity, newlen))
|
||||
return false;
|
||||
obj->setDenseArrayLength(newlen);
|
||||
obj->setArrayLength(newlen);
|
||||
} else if (oldlen - newlen < (1 << 24)) {
|
||||
do {
|
||||
--oldlen;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeleteArrayElement(cx, obj, oldlen))
|
||||
return false;
|
||||
} while (oldlen != newlen);
|
||||
obj->setSlowArrayLength(newlen);
|
||||
obj->setArrayLength(newlen);
|
||||
} else {
|
||||
/*
|
||||
* We are going to remove a lot of indexes in a presumably sparse
|
||||
|
@ -669,7 +672,7 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
obj->setSlowArrayLength(newlen);
|
||||
obj->setArrayLength(newlen);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -786,7 +789,7 @@ slowarray_addProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
return JS_TRUE;
|
||||
length = obj->getArrayLength();
|
||||
if (index >= length)
|
||||
obj->setSlowArrayLength(index + 1);
|
||||
obj->setArrayLength(index + 1);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -817,9 +820,7 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
return JS_FALSE;
|
||||
|
||||
if (i >= obj->getArrayLength())
|
||||
obj->setDenseArrayLength(i + 1);
|
||||
if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE))
|
||||
obj->incDenseArrayCountBy(1);
|
||||
obj->setArrayLength(i + 1);
|
||||
obj->setDenseArrayElement(i, *vp);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -879,8 +880,7 @@ dense_grow(JSContext* cx, JSObject* obj, jsint i, const Value &v)
|
|||
return JS_FALSE;
|
||||
|
||||
if (u >= obj->getArrayLength())
|
||||
obj->setDenseArrayLength(u + 1);
|
||||
obj->incDenseArrayCountBy(1);
|
||||
obj->setArrayLength(u + 1);
|
||||
}
|
||||
|
||||
obj->setDenseArrayElement(u, v);
|
||||
|
@ -962,11 +962,8 @@ array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
if (js_IdIsIndex(id, &i) && i < obj->getDenseArrayCapacity() &&
|
||||
!obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
|
||||
obj->decDenseArrayCountBy(1);
|
||||
if (js_IdIsIndex(id, &i) && i < obj->getDenseArrayCapacity())
|
||||
obj->setDenseArrayElement(i, MagicValue(JS_ARRAY_HOLE));
|
||||
}
|
||||
|
||||
if (!js_SuppressDeletedProperty(cx, obj, id))
|
||||
return false;
|
||||
|
@ -987,9 +984,23 @@ array_trace(JSTracer *trc, JSObject *obj)
|
|||
JS_ASSERT(obj->isDenseArray());
|
||||
obj->traceProtoAndParent(trc);
|
||||
|
||||
size_t holes = 0;
|
||||
|
||||
uint32 capacity = obj->getDenseArrayCapacity();
|
||||
for (uint32 i = 0; i < capacity; i++)
|
||||
MarkValue(trc, obj->getDenseArrayElement(i), "dense_array_elems");
|
||||
for (uint32 i = 0; i < capacity; i++) {
|
||||
Value v = obj->getDenseArrayElement(i);
|
||||
if (v.isMagic(JS_ARRAY_HOLE))
|
||||
++holes;
|
||||
else
|
||||
MarkValue(trc, obj->getDenseArrayElement(i), "dense_array_elems");
|
||||
}
|
||||
|
||||
if (trc == trc->context->runtime->gcMarkingTracer &&
|
||||
holes > MIN_SPARSE_INDEX &&
|
||||
holes > capacity / 4 * 3) {
|
||||
/* This might fail, in which case we don't slowify it. */
|
||||
reinterpret_cast<JSGCTracer *>(trc)->arraysToSlowify.append(obj);
|
||||
}
|
||||
}
|
||||
|
||||
extern JSObjectOps js_ArrayObjectOps;
|
||||
|
@ -1381,19 +1392,8 @@ array_toLocaleString(JSContext *cx, uintN argc, Value *vp)
|
|||
return array_toString_sub(cx, obj, JS_TRUE, NULL, vp);
|
||||
}
|
||||
|
||||
enum TargetElementsType {
|
||||
TargetElementsAllHoles,
|
||||
TargetElementsMayContainValues
|
||||
};
|
||||
|
||||
enum SourceVectorType {
|
||||
SourceVectorAllValues,
|
||||
SourceVectorMayContainHoles
|
||||
};
|
||||
|
||||
static JSBool
|
||||
InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, Value *vector,
|
||||
TargetElementsType targetType, SourceVectorType vectorType)
|
||||
InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, Value *vector)
|
||||
{
|
||||
JS_ASSERT(count < MAXINDEX);
|
||||
|
||||
|
@ -1404,54 +1404,16 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, Valu
|
|||
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
|
||||
start <= MAXINDEX - count && !INDEX_TOO_BIG(start + count)) {
|
||||
|
||||
#ifdef DEBUG_jwalden
|
||||
{
|
||||
/* Verify that overwriteType and writeType were accurate. */
|
||||
AutoIdRooter idr(cx);
|
||||
for (jsuint i = 0; i < count; i++) {
|
||||
JS_ASSERT_IF(vectorType == SourceVectorAllValues, !vector[i].isMagic(JS_ARRAY_HOLE));
|
||||
|
||||
jsdouble index = jsdouble(start) + i;
|
||||
if (targetType == TargetElementsAllHoles && index < jsuint(-1)) {
|
||||
JS_ASSERT(ReallyBigIndexToId(cx, index, idr.addr()));
|
||||
JSObject* obj2;
|
||||
JSProperty* prop;
|
||||
JS_ASSERT(obj->lookupProperty(cx, idr.id(), &obj2, &prop));
|
||||
JS_ASSERT(!prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
jsuint newlen = start + count;
|
||||
JS_ASSERT(jsdouble(start) + count == jsdouble(newlen));
|
||||
if (!obj->ensureDenseArrayElements(cx, newlen))
|
||||
return JS_FALSE;
|
||||
|
||||
if (newlen > obj->getArrayLength())
|
||||
obj->setDenseArrayLength(newlen);
|
||||
obj->setArrayLength(newlen);
|
||||
|
||||
JS_ASSERT(count < uint32(-1) / sizeof(Value));
|
||||
if (targetType == TargetElementsMayContainValues) {
|
||||
jsuint valueCount = 0;
|
||||
for (jsuint i = 0; i < count; i++) {
|
||||
if (!obj->getDenseArrayElement(start + i).isMagic(JS_ARRAY_HOLE))
|
||||
valueCount++;
|
||||
}
|
||||
JS_ASSERT(obj->getDenseArrayCount() >= valueCount);
|
||||
obj->decDenseArrayCountBy(valueCount);
|
||||
}
|
||||
memcpy(obj->getDenseArrayElements() + start, vector, sizeof(jsval) * count);
|
||||
if (vectorType == SourceVectorAllValues) {
|
||||
obj->incDenseArrayCountBy(count);
|
||||
} else {
|
||||
jsuint valueCount = 0;
|
||||
for (jsuint i = 0; i < count; i++) {
|
||||
if (!obj->getDenseArrayElement(start + i).isMagic(JS_ARRAY_HOLE))
|
||||
valueCount++;
|
||||
}
|
||||
obj->incDenseArrayCountBy(valueCount);
|
||||
}
|
||||
JS_ASSERT_IF(count != 0, !obj->getDenseArrayElement(newlen - 1).isMagic(JS_ARRAY_HOLE));
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -1488,34 +1450,21 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, Valu
|
|||
}
|
||||
|
||||
static JSBool
|
||||
InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector,
|
||||
bool holey = false)
|
||||
InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector)
|
||||
{
|
||||
JS_ASSERT(obj->isArray());
|
||||
|
||||
if (vector) {
|
||||
JS_ASSERT(obj->isDenseArray());
|
||||
obj->setDenseArrayLength(length);
|
||||
obj->setArrayLength(length);
|
||||
if (!obj->ensureDenseArrayElements(cx, length))
|
||||
return JS_FALSE;
|
||||
|
||||
jsuint count = length;
|
||||
if (!holey) {
|
||||
memcpy(obj->getDenseArrayElements(), vector, length * sizeof(Value));
|
||||
} else {
|
||||
for (jsuint i = 0; i < length; i++) {
|
||||
if (vector[i].isMagic(JS_ARRAY_HOLE))
|
||||
--count;
|
||||
obj->setDenseArrayElement(i, vector[i]);
|
||||
}
|
||||
}
|
||||
obj->setDenseArrayCount(count);
|
||||
memcpy(obj->getDenseArrayElements(), vector, length * sizeof(Value));
|
||||
} else {
|
||||
if (obj->isDenseArray()) {
|
||||
obj->setDenseArrayLength(length);
|
||||
obj->setDenseArrayCount(0);
|
||||
obj->setArrayLength(length);
|
||||
} else {
|
||||
obj->setSlowArrayLength(length);
|
||||
obj->setArrayLength(length);
|
||||
}
|
||||
}
|
||||
return JS_TRUE;
|
||||
|
@ -2043,10 +1992,8 @@ array_sort(JSContext *cx, uintN argc, Value *vp)
|
|||
* InitArrayElements easier.
|
||||
*/
|
||||
tvr.changeLength(newlen);
|
||||
if (!InitArrayElements(cx, obj, 0, newlen, vec, TargetElementsMayContainValues,
|
||||
SourceVectorAllValues)) {
|
||||
if (!InitArrayElements(cx, obj, 0, newlen, vec))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set undefs that sorted after the rest of elements. */
|
||||
|
@ -2077,10 +2024,8 @@ array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *
|
|||
|
||||
if (!js_GetLengthProperty(cx, obj, &length))
|
||||
return JS_FALSE;
|
||||
if (!InitArrayElements(cx, obj, length, argc, argv, TargetElementsMayContainValues,
|
||||
SourceVectorAllValues)) {
|
||||
if (!InitArrayElements(cx, obj, length, argc, argv))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Per ECMA-262, return the new array length. */
|
||||
jsdouble newlength = length + jsdouble(argc);
|
||||
|
@ -2101,10 +2046,9 @@ array_push1_dense(JSContext* cx, JSObject* obj, const Value &v, Value *rval)
|
|||
|
||||
if (!obj->ensureDenseArrayElements(cx, length + 1))
|
||||
return JS_FALSE;
|
||||
obj->setDenseArrayLength(length + 1);
|
||||
obj->setArrayLength(length + 1);
|
||||
|
||||
JS_ASSERT(obj->getDenseArrayElement(length).isMagic(JS_ARRAY_HOLE));
|
||||
obj->incDenseArrayCountBy(1);
|
||||
obj->setDenseArrayElement(length, v);
|
||||
rval->setNumber(obj->getArrayLength());
|
||||
return JS_TRUE;
|
||||
|
@ -2127,8 +2071,7 @@ ArrayCompPushImpl(JSContext *cx, JSObject *obj, const Value &v)
|
|||
if (!obj->ensureDenseArrayElements(cx, length + 1))
|
||||
return JS_FALSE;
|
||||
}
|
||||
obj->setDenseArrayLength(length + 1);
|
||||
obj->incDenseArrayCountBy(1);
|
||||
obj->setArrayLength(length + 1);
|
||||
obj->setDenseArrayElement(length, v);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -2198,7 +2141,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, Value *vp)
|
|||
return JS_FALSE;
|
||||
if (!hole && !DeleteArrayElement(cx, obj, index))
|
||||
return JS_FALSE;
|
||||
obj->setDenseArrayLength(index);
|
||||
obj->setArrayLength(index);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -2233,12 +2176,10 @@ array_shift(JSContext *cx, uintN argc, Value *vp)
|
|||
*vp = obj->getDenseArrayElement(0);
|
||||
if (vp->isMagic(JS_ARRAY_HOLE))
|
||||
vp->setUndefined();
|
||||
else
|
||||
obj->decDenseArrayCountBy(1);
|
||||
Value *elems = obj->getDenseArrayElements();
|
||||
memmove(elems, elems + 1, length * sizeof(jsval));
|
||||
obj->setDenseArrayElement(length, MagicValue(JS_ARRAY_HOLE));
|
||||
obj->setDenseArrayLength(length);
|
||||
obj->setArrayLength(length);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -2304,7 +2245,7 @@ array_unshift(JSContext *cx, uintN argc, Value *vp)
|
|||
}
|
||||
|
||||
/* Copy from argv to the bottom of the array. */
|
||||
if (!InitArrayElements(cx, obj, 0, argc, argv, TargetElementsAllHoles, SourceVectorAllValues))
|
||||
if (!InitArrayElements(cx, obj, 0, argc, argv))
|
||||
return JS_FALSE;
|
||||
|
||||
newlen += argc;
|
||||
|
@ -2384,10 +2325,8 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
|
|||
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
|
||||
!js_PrototypeHasIndexedProperties(cx, obj2) &&
|
||||
end <= obj->getDenseArrayCapacity()) {
|
||||
if (!InitArrayObject(cx, obj2, count, obj->getDenseArrayElements() + begin,
|
||||
obj->getDenseArrayCount() != obj->getArrayLength())) {
|
||||
if (!InitArrayObject(cx, obj2, count, obj->getDenseArrayElements() + begin))
|
||||
return JS_FALSE;
|
||||
}
|
||||
} else {
|
||||
for (last = begin; last < end; last++) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
|
@ -2419,14 +2358,10 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
|
|||
Value *srcbeg = arraybeg + last - 1;
|
||||
Value *srcend = arraybeg + end - 1;
|
||||
Value *dstbeg = srcbeg + delta;
|
||||
for (Value *src = srcbeg, *dst = dstbeg; src > srcend; --src, --dst) {
|
||||
Value srcval = *src;
|
||||
if (JS_UNLIKELY(!srcval.isMagic(JS_ARRAY_HOLE) && dst->isMagic(JS_ARRAY_HOLE)))
|
||||
obj->incDenseArrayCountBy(1);
|
||||
*dst = srcval;
|
||||
}
|
||||
for (Value *src = srcbeg, *dst = dstbeg; src > srcend; --src, --dst)
|
||||
*dst = *src;
|
||||
|
||||
obj->setDenseArrayLength(obj->getArrayLength() + delta);
|
||||
obj->setArrayLength(obj->getArrayLength() + delta);
|
||||
} else {
|
||||
/* (uint) end could be 0, so we can't use a vanilla >= test. */
|
||||
while (last-- > end) {
|
||||
|
@ -2447,12 +2382,8 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
|
|||
Value *srcbeg = arraybeg + end;
|
||||
Value *srcend = arraybeg + length;
|
||||
Value *dstbeg = srcbeg - delta;
|
||||
for (Value *src = srcbeg, *dst = dstbeg; src < srcend; ++src, ++dst) {
|
||||
Value srcval = *src;
|
||||
if (JS_UNLIKELY(!srcval.isMagic(JS_ARRAY_HOLE) && dst->isMagic(JS_ARRAY_HOLE)))
|
||||
obj->incDenseArrayCountBy(1);
|
||||
*dst = srcval;
|
||||
}
|
||||
for (Value *src = srcbeg, *dst = dstbeg; src < srcend; ++src, ++dst)
|
||||
*dst = *src;
|
||||
} else {
|
||||
for (last = end; last < length; last++) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
|
@ -2469,8 +2400,7 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
|
|||
* Copy from argv into the hole to complete the splice, and update length in
|
||||
* case we deleted elements from the end.
|
||||
*/
|
||||
return InitArrayElements(cx, obj, begin, argc, argv, TargetElementsMayContainValues,
|
||||
SourceVectorAllValues) &&
|
||||
return InitArrayElements(cx, obj, begin, argc, argv) &&
|
||||
js_SetLengthProperty(cx, obj, length);
|
||||
}
|
||||
|
||||
|
@ -2498,11 +2428,10 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
|
|||
*/
|
||||
length = aobj->getArrayLength();
|
||||
jsuint capacity = aobj->getDenseArrayCapacity();
|
||||
nobj = js_NewArrayObject(cx, JS_MIN(length, capacity), aobj->getDenseArrayElements(),
|
||||
aobj->getDenseArrayCount() != length);
|
||||
nobj = js_NewArrayObject(cx, JS_MIN(length, capacity), aobj->getDenseArrayElements());
|
||||
if (!nobj)
|
||||
return JS_FALSE;
|
||||
nobj->setDenseArrayLength(length);
|
||||
nobj->setArrayLength(length);
|
||||
vp->setObject(*nobj);
|
||||
if (argc == 0)
|
||||
return JS_TRUE;
|
||||
|
@ -2614,8 +2543,7 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
|
|||
|
||||
if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() &&
|
||||
!js_PrototypeHasIndexedProperties(cx, obj)) {
|
||||
nobj = js_NewArrayObject(cx, end - begin, obj->getDenseArrayElements() + begin,
|
||||
obj->getDenseArrayCount() != obj->getArrayLength());
|
||||
nobj = js_NewArrayObject(cx, end - begin, obj->getDenseArrayElements() + begin);
|
||||
if (!nobj)
|
||||
return JS_FALSE;
|
||||
vp->setObject(*nobj);
|
||||
|
@ -3070,8 +2998,7 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto)
|
|||
obj->map = const_cast<JSObjectMap *>(&SharedArrayMap);
|
||||
|
||||
obj->init(&js_ArrayClass, proto, proto->getParent(), NullValue());
|
||||
obj->setDenseArrayLength(0);
|
||||
obj->setDenseArrayCount(0);
|
||||
obj->setArrayLength(0);
|
||||
return obj;
|
||||
}
|
||||
#ifdef JS_TRACER
|
||||
|
@ -3086,7 +3013,7 @@ js_NewEmptyArrayWithLength(JSContext* cx, JSObject* proto, int32 len)
|
|||
JSObject *obj = js_NewEmptyArray(cx, proto);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
obj->setDenseArrayLength(len);
|
||||
obj->setArrayLength(len);
|
||||
return obj;
|
||||
}
|
||||
#ifdef JS_TRACER
|
||||
|
@ -3100,7 +3027,7 @@ js_NewArrayWithSlots(JSContext* cx, JSObject* proto, uint32 len)
|
|||
JSObject* obj = js_NewEmptyArray(cx, proto);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
obj->setDenseArrayLength(len);
|
||||
obj->setArrayLength(len);
|
||||
if (!obj->resizeDenseArrayElements(cx, 0, JS_MAX(len, ARRAY_CAPACITY_MIN)))
|
||||
return NULL;
|
||||
return obj;
|
||||
|
@ -3123,7 +3050,7 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
|
|||
}
|
||||
|
||||
JSObject *
|
||||
js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector, bool holey)
|
||||
js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector)
|
||||
{
|
||||
JSObject *obj = NewDenseArrayObject(cx);
|
||||
if (!obj)
|
||||
|
@ -3137,7 +3064,7 @@ js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector, bool holey)
|
|||
|
||||
{
|
||||
AutoObjectRooter tvr(cx, obj);
|
||||
if (!InitArrayObject(cx, obj, length, vector, holey))
|
||||
if (!InitArrayObject(cx, obj, length, vector))
|
||||
obj = NULL;
|
||||
}
|
||||
|
||||
|
@ -3151,7 +3078,7 @@ js_NewSlowArrayObject(JSContext *cx)
|
|||
{
|
||||
JSObject *obj = NewObject(cx, &js_SlowArrayClass, NULL, NULL);
|
||||
if (obj)
|
||||
obj->setSlowArrayLength(0);
|
||||
obj->setArrayLength(0);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -3178,8 +3105,7 @@ js_ArrayInfo(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval)
|
|||
array->isDenseArray()) ? "dense" : "sparse",
|
||||
array->getArrayLength());
|
||||
if (array->isDenseArray()) {
|
||||
fprintf(stderr, ", count %lu, capacity %lu",
|
||||
array->getDenseArrayCount(),
|
||||
fprintf(stderr, ", capacity %lu",
|
||||
array->getDenseArrayCapacity());
|
||||
}
|
||||
fputs(")\n", stderr);
|
||||
|
@ -3263,7 +3189,6 @@ js_NewArrayObjectWithCapacity(JSContext *cx, uint32_t capacity, jsval **vector)
|
|||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
obj->setDenseArrayCount(capacity);
|
||||
*vector = Jsvalify(obj->getDenseArrayElements());
|
||||
return obj;
|
||||
}
|
||||
|
@ -3311,8 +3236,6 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
|
|||
if (!vector.reserve(jsvalCount))
|
||||
return JS_FALSE;
|
||||
|
||||
jsuint holeCount = 0;
|
||||
|
||||
for (jsuint i = 0; i < jsvalCount; i++) {
|
||||
const Value &val = obj->dslots[i];
|
||||
|
||||
|
@ -3320,8 +3243,6 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
|
|||
// Strings must be made immutable before being copied to a clone.
|
||||
if (!js_MakeStringImmutable(cx, val.toString()))
|
||||
return JS_FALSE;
|
||||
} else if (val.isMagic(JS_ARRAY_HOLE)) {
|
||||
holeCount++;
|
||||
} else if (val.isObject()) {
|
||||
/*
|
||||
* This wasn't an array of primitives. Return JS_TRUE but a null
|
||||
|
@ -3342,8 +3263,7 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
|
|||
AutoObjectRooter cloneRoot(cx, *clone);
|
||||
|
||||
memcpy(buffer, vector.begin(), jsvalCount * sizeof (jsval));
|
||||
(*clone)->setDenseArrayLength(length);
|
||||
(*clone)->setDenseArrayCount(length - holeCount);
|
||||
(*clone)->setArrayLength(length);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ extern JSObject * JS_FASTCALL
|
|||
js_NewArrayWithSlots(JSContext* cx, JSObject* proto, uint32 len);
|
||||
|
||||
extern JSObject *
|
||||
js_NewArrayObject(JSContext *cx, jsuint length, const js::Value *vector, bool holey = false);
|
||||
js_NewArrayObject(JSContext *cx, jsuint length, const js::Value *vector);
|
||||
|
||||
/* Create an array object that starts out already made slow/sparse. */
|
||||
extern JSObject *
|
||||
|
|
|
@ -1203,6 +1203,7 @@ struct JSCompartment {
|
|||
|
||||
struct JSGCTracer : public JSTracer {
|
||||
uint32 color;
|
||||
js::Vector<JSObject *, 0, js::SystemAllocPolicy> arraysToSlowify;
|
||||
};
|
||||
|
||||
struct JSRuntime {
|
||||
|
|
|
@ -3161,6 +3161,16 @@ GC(JSContext *cx GCTIMER_PARAM)
|
|||
*/
|
||||
js_SweepScriptFilenames(rt);
|
||||
|
||||
/*
|
||||
* Slowify arrays we have accumulated.
|
||||
*/
|
||||
while (!trc.arraysToSlowify.empty()) {
|
||||
JSObject *obj = trc.arraysToSlowify.back();
|
||||
trc.arraysToSlowify.popBack();
|
||||
if (IsMarkedGCThing(obj))
|
||||
obj->makeDenseArraySlow(cx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy arenas after we finished the sweeping so finalizers can safely
|
||||
* use js_IsAboutToBeFinalized().
|
||||
|
|
|
@ -4446,8 +4446,7 @@ BEGIN_CASE(JSOP_GETELEM)
|
|||
if (obj->isDenseArray()) {
|
||||
jsuint idx = jsuint(i);
|
||||
|
||||
if (idx < obj->getArrayLength() &&
|
||||
idx < obj->getDenseArrayCapacity()) {
|
||||
if (idx < obj->getDenseArrayCapacity()) {
|
||||
copyFrom = obj->addressOfDenseArrayElement(idx);
|
||||
if (!copyFrom->isMagic())
|
||||
goto end_getelem;
|
||||
|
@ -4538,8 +4537,7 @@ BEGIN_CASE(JSOP_SETELEM)
|
|||
if (js_PrototypeHasIndexedProperties(cx, obj))
|
||||
break;
|
||||
if ((jsuint)i >= obj->getArrayLength())
|
||||
obj->setDenseArrayLength(i + 1);
|
||||
obj->incDenseArrayCountBy(1);
|
||||
obj->setArrayLength(i + 1);
|
||||
}
|
||||
obj->setDenseArrayElement(i, regs.sp[-1]);
|
||||
goto end_setelem;
|
||||
|
@ -5924,7 +5922,7 @@ BEGIN_CASE(JSOP_NEWARRAY)
|
|||
{
|
||||
len = GET_UINT16(regs.pc);
|
||||
cx->assertValidStackDepth(len);
|
||||
JSObject *obj = js_NewArrayObject(cx, len, regs.sp - len, JS_TRUE);
|
||||
JSObject *obj = js_NewArrayObject(cx, len, regs.sp - len);
|
||||
if (!obj)
|
||||
goto error;
|
||||
regs.sp -= len - 1;
|
||||
|
|
|
@ -277,7 +277,7 @@ EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uint
|
|||
return false;
|
||||
}
|
||||
|
||||
if (pobj->getDenseArrayCount() > 0) {
|
||||
if (pobj->getArrayLength() > 0) {
|
||||
size_t capacity = pobj->getDenseArrayCapacity();
|
||||
Value *vp = pobj->dslots;
|
||||
for (size_t i = 0; i < capacity; ++i, ++vp) {
|
||||
|
|
|
@ -1863,7 +1863,7 @@ obj_keys(JSContext *cx, uintN argc, Value *vp)
|
|||
}
|
||||
|
||||
JS_ASSERT(props.length() <= UINT32_MAX);
|
||||
JSObject *aobj = js_NewArrayObject(cx, jsuint(vals.length()), vals.begin(), false);
|
||||
JSObject *aobj = js_NewArrayObject(cx, jsuint(vals.length()), vals.begin());
|
||||
if (!aobj)
|
||||
return JS_FALSE;
|
||||
vp->setObject(*aobj);
|
||||
|
@ -2342,7 +2342,7 @@ DefinePropertyOnArray(JSContext *cx, JSObject *obj, const PropDesc &desc,
|
|||
|
||||
if (index >= oldLen) {
|
||||
JS_ASSERT(index != UINT32_MAX);
|
||||
obj->setSlowArrayLength(index + 1);
|
||||
obj->setArrayLength(index + 1);
|
||||
}
|
||||
|
||||
*rval = true;
|
||||
|
|
|
@ -475,35 +475,20 @@ struct JSObject {
|
|||
// Used by dense and slow arrays.
|
||||
static const uint32 JSSLOT_ARRAY_LENGTH = JSSLOT_PRIVATE;
|
||||
|
||||
// Used only by dense arrays.
|
||||
static const uint32 JSSLOT_DENSE_ARRAY_COUNT = JSSLOT_PRIVATE + 1;
|
||||
static const uint32 JSSLOT_DENSE_ARRAY_MINLENCAP = JSSLOT_PRIVATE + 2;
|
||||
|
||||
// This assertion must remain true; see comment in js_MakeArraySlow().
|
||||
// (Nb: This method is never called, it just contains a static assertion.
|
||||
// The static assertion isn't inline because that doesn't work on Mac.)
|
||||
inline void staticAssertArrayLengthIsInPrivateSlot();
|
||||
|
||||
inline uint32 uncheckedGetArrayLength() const;
|
||||
inline uint32 uncheckedGetDenseArrayCapacity() const;
|
||||
|
||||
public:
|
||||
static const uint32 DENSE_ARRAY_FIXED_RESERVED_SLOTS = 3;
|
||||
|
||||
inline uint32 getArrayLength() const;
|
||||
inline void setDenseArrayLength(uint32 length);
|
||||
inline void setSlowArrayLength(uint32 length);
|
||||
|
||||
inline uint32 getDenseArrayCount() const;
|
||||
inline void setDenseArrayCount(uint32 count);
|
||||
inline void incDenseArrayCountBy(uint32 posDelta);
|
||||
inline void decDenseArrayCountBy(uint32 negDelta);
|
||||
inline void setArrayLength(uint32 length);
|
||||
|
||||
inline uint32 getDenseArrayCapacity() const;
|
||||
inline void setDenseArrayCapacity(uint32 capacity); // XXX: bug 558263 will remove this
|
||||
|
||||
inline bool isDenseArrayMinLenCapOk(bool strictAboutLength = true) const;
|
||||
|
||||
inline const js::Value &getDenseArrayElement(uint32 i) const;
|
||||
inline js::Value *addressOfDenseArrayElement(uint32 i);
|
||||
inline void setDenseArrayElement(uint32 i, const js::Value &v);
|
||||
|
|
|
@ -132,96 +132,25 @@ JSObject::staticAssertArrayLengthIsInPrivateSlot()
|
|||
JS_STATIC_ASSERT(JSSLOT_ARRAY_LENGTH == JSSLOT_PRIVATE);
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isDenseArrayMinLenCapOk(bool strictAboutLength) const
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
|
||||
// This function can be called while the LENGTH and MINLENCAP slots are
|
||||
// still set to JSVAL_VOID and there are no dslots (ie. the capacity is
|
||||
// zero). If 'strictAboutLength' is false we allow this.
|
||||
if (!strictAboutLength &&
|
||||
fslots[JSSLOT_ARRAY_LENGTH].isUndefined() &&
|
||||
uncheckedGetDenseArrayCapacity() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 length = uncheckedGetArrayLength();
|
||||
uint32 capacity = uncheckedGetDenseArrayCapacity();
|
||||
uint32 minLenCap = fslots[JSSLOT_DENSE_ARRAY_MINLENCAP].toPrivateUint32();
|
||||
return minLenCap == JS_MIN(length, capacity);
|
||||
}
|
||||
|
||||
inline uint32
|
||||
JSObject::uncheckedGetArrayLength() const
|
||||
{
|
||||
return fslots[JSSLOT_ARRAY_LENGTH].toPrivateUint32();
|
||||
}
|
||||
|
||||
inline uint32
|
||||
JSObject::getArrayLength() const
|
||||
{
|
||||
JS_ASSERT(isArray());
|
||||
JS_ASSERT_IF(isDenseArray(), isDenseArrayMinLenCapOk());
|
||||
return uncheckedGetArrayLength();
|
||||
return fslots[JSSLOT_ARRAY_LENGTH].toPrivateUint32();
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setDenseArrayLength(uint32 length)
|
||||
JSObject::setArrayLength(uint32 length)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
JS_ASSERT(isArray());
|
||||
fslots[JSSLOT_ARRAY_LENGTH].setPrivateUint32(length);
|
||||
uint32 capacity = uncheckedGetDenseArrayCapacity();
|
||||
fslots[JSSLOT_DENSE_ARRAY_MINLENCAP].setPrivateUint32(JS_MIN(length, capacity));
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setSlowArrayLength(uint32 length)
|
||||
{
|
||||
JS_ASSERT(isSlowArray());
|
||||
fslots[JSSLOT_ARRAY_LENGTH].setPrivateUint32(length);
|
||||
}
|
||||
|
||||
inline uint32
|
||||
JSObject::getDenseArrayCount() const
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
return fslots[JSSLOT_DENSE_ARRAY_COUNT].toPrivateUint32();
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setDenseArrayCount(uint32 count)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
fslots[JSSLOT_DENSE_ARRAY_COUNT].setPrivateUint32(count);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::incDenseArrayCountBy(uint32 posDelta)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
fslots[JSSLOT_DENSE_ARRAY_COUNT].getPrivateUint32Ref() += posDelta;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::decDenseArrayCountBy(uint32 negDelta)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
fslots[JSSLOT_DENSE_ARRAY_COUNT].getPrivateUint32Ref() -= negDelta;
|
||||
}
|
||||
|
||||
inline uint32
|
||||
JSObject::uncheckedGetDenseArrayCapacity() const
|
||||
{
|
||||
return dslots ? dslots[-1].toPrivateUint32() : 0;
|
||||
}
|
||||
|
||||
inline uint32
|
||||
JSObject::getDenseArrayCapacity() const
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
JS_ASSERT(isDenseArrayMinLenCapOk(/* strictAboutLength = */false));
|
||||
return uncheckedGetDenseArrayCapacity();
|
||||
return dslots ? dslots[-1].toPrivateUint32() : 0;
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -230,8 +159,6 @@ JSObject::setDenseArrayCapacity(uint32 capacity)
|
|||
JS_ASSERT(isDenseArray());
|
||||
JS_ASSERT(dslots);
|
||||
dslots[-1].setPrivateUint32(capacity);
|
||||
uint32 length = uncheckedGetArrayLength();
|
||||
fslots[JSSLOT_DENSE_ARRAY_MINLENCAP].setPrivateUint32(JS_MIN(length, capacity));
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
|
@ -273,16 +200,12 @@ JSObject::freeDenseArrayElements(JSContext *cx)
|
|||
cx->free(dslots - 1);
|
||||
dslots = NULL;
|
||||
}
|
||||
fslots[JSSLOT_DENSE_ARRAY_MINLENCAP].setPrivateUint32(0);
|
||||
JS_ASSERT(isDenseArrayMinLenCapOk(/* strictAboutLength = */false));
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::voidDenseOnlyArraySlots()
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
fslots[JSSLOT_DENSE_ARRAY_COUNT].setUndefined();
|
||||
fslots[JSSLOT_DENSE_ARRAY_MINLENCAP].setUndefined();
|
||||
}
|
||||
|
||||
inline void
|
||||
|
|
|
@ -11037,9 +11037,6 @@ TraceRecorder::newArray(JSObject* ctor, uint32 argc, Value* argv, Value* rval)
|
|||
for (uint32 i = 0; i < argc && !outOfMemory(); i++) {
|
||||
stobj_set_dslot(arr_ins, i, dslots_ins, argv[i], get(&argv[i]));
|
||||
}
|
||||
|
||||
if (argc > 0)
|
||||
set_array_fslot(arr_ins, JSObject::JSSLOT_DENSE_ARRAY_COUNT, argc);
|
||||
}
|
||||
|
||||
set(rval, arr_ins);
|
||||
|
@ -13654,23 +13651,27 @@ TraceRecorder::denseArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_
|
|||
LIns* idx_ins = makeNumberInt32(get(&ival));
|
||||
|
||||
VMSideExit* exit = snapshot(BRANCH_EXIT);
|
||||
/* check that the index is within bounds */
|
||||
|
||||
/*
|
||||
* Arrays have both a length and a capacity, but we only need to check
|
||||
* |index < capacity|; in the case where |length < index < capacity|
|
||||
* the entries [length..capacity-1] will have already been marked as
|
||||
* holes by resizeDenseArrayElements() so we can read them and get
|
||||
* the correct value.
|
||||
*/
|
||||
LIns* dslots_ins =
|
||||
addName(lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACC_OTHER), "dslots");
|
||||
jsuint capacity = obj->getDenseArrayCapacity();
|
||||
bool within = (jsuint(idx) < obj->getArrayLength() && jsuint(idx) < capacity);
|
||||
bool within = (jsuint(idx) < capacity);
|
||||
if (!within) {
|
||||
/* If not idx < min(length, capacity), stay on trace (and read value as undefined). */
|
||||
JS_ASSERT(obj->isDenseArrayMinLenCapOk());
|
||||
LIns* minLenCap =
|
||||
addName(stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_DENSE_ARRAY_MINLENCAP), "minLenCap");
|
||||
LIns* br = lir->insBranch(LIR_jf,
|
||||
lir->ins2(LIR_ltui, idx_ins, minLenCap),
|
||||
NULL);
|
||||
/* Also stay on trace if dslots is NULL. */
|
||||
LIns *br = lir->insBranch(LIR_jt, lir->insEqP_0(dslots_ins), NULL);
|
||||
|
||||
lir->insGuard(LIR_x, NULL, createGuardRecord(exit));
|
||||
LIns* label = lir->ins0(LIR_label);
|
||||
br->setTarget(label);
|
||||
/* If not idx < capacity, stay on trace (and read value as undefined). */
|
||||
LIns* capacity_ins = addName(lir->insLoad(LIR_ldi, dslots_ins, -int(sizeof(jsval)), ACC_OTHER), "capacity");
|
||||
guard(true, lir->ins2(LIR_geui, idx_ins, capacity_ins), exit);
|
||||
|
||||
br->setTarget(lir->ins0(LIR_label));
|
||||
|
||||
CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, MISMATCH_EXIT));
|
||||
|
||||
|
@ -13680,11 +13681,10 @@ TraceRecorder::denseArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_
|
|||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
/* Guard array min(length, capacity). */
|
||||
JS_ASSERT(obj->isDenseArrayMinLenCapOk());
|
||||
LIns* minLenCap =
|
||||
addName(stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_DENSE_ARRAY_MINLENCAP), "minLenCap");
|
||||
guard(true, lir->ins2(LIR_ltui, idx_ins, minLenCap), exit);
|
||||
/* Guard that index is within capacity. */
|
||||
guard(false, lir->insEqP_0(dslots_ins), exit);
|
||||
LIns* capacity_ins = addName(lir->insLoad(LIR_ldi, dslots_ins, -int(sizeof(jsval)), ACC_OTHER), "capacity");
|
||||
guard(true, lir->ins2(LIR_ltui, idx_ins, capacity_ins), exit);
|
||||
|
||||
/* Load the value and guard on its type to unbox it. */
|
||||
vp = &obj->dslots[jsuint(idx)];
|
||||
|
@ -15810,9 +15810,6 @@ TraceRecorder::record_JSOP_NEWARRAY()
|
|||
stobj_set_dslot(v_ins, i, dslots_ins, v, get(&v));
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
set_array_fslot(v_ins, JSObject::JSSLOT_DENSE_ARRAY_COUNT, count);
|
||||
|
||||
stack(-int(len), v_ins);
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче