mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 486326 - Specialize array methods which modify large numbers of array elements to work efficiently on dense arrays, avoiding highly generalized get/set/delete methods and the floating-point-to-integer conversions needed solely to handle large array indexes but which are rarely necessary in practice. r=shaver
This commit is contained in:
parent
806e556ee1
commit
8e5456999b
@ -55,6 +55,11 @@
|
||||
* In dense mode, holes in the array are represented by JSVAL_HOLE. The final
|
||||
* slot in fslots is 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
|
||||
* array_length_setter for an explanation of how the first, most surprising
|
||||
* case may occur.
|
||||
*
|
||||
* Arrays are converted to use js_SlowArrayClass when any of these conditions
|
||||
* are met:
|
||||
* - the load factor (COUNT / capacity) is less than 0.25, and there are
|
||||
@ -478,7 +483,7 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, jsval v)
|
||||
JS_ASSERT(idx + 1 > idx);
|
||||
if (!EnsureCapacity(cx, obj, idx + 1))
|
||||
return JS_FALSE;
|
||||
if (index >= uint32(obj->fslots[JSSLOT_ARRAY_LENGTH]))
|
||||
if (idx >= uint32(obj->fslots[JSSLOT_ARRAY_LENGTH]))
|
||||
obj->fslots[JSSLOT_ARRAY_LENGTH] = idx + 1;
|
||||
if (obj->dslots[idx] == JSVAL_HOLE)
|
||||
obj->fslots[JSSLOT_ARRAY_COUNT]++;
|
||||
@ -1605,16 +1610,48 @@ array_toLocaleString(JSContext *cx, uintN argc, jsval *vp)
|
||||
return array_join_sub(cx, obj, TO_LOCALE_STRING, NULL, vp);
|
||||
}
|
||||
|
||||
enum TargetElementsType {
|
||||
TargetElementsAllHoles,
|
||||
TargetElementsMayContainValues
|
||||
};
|
||||
|
||||
enum SourceVectorType {
|
||||
SourceVectorAllValues,
|
||||
SourceVectorMayContainHoles
|
||||
};
|
||||
|
||||
static JSBool
|
||||
InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsval *vector)
|
||||
InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsval *vector,
|
||||
TargetElementsType targetType, SourceVectorType vectorType)
|
||||
{
|
||||
JS_ASSERT(count < MAXINDEX);
|
||||
|
||||
/*
|
||||
* Optimize for dense arrays so long as adding the given set of elements
|
||||
* wouldn't otherwise make the array slow.
|
||||
*/
|
||||
if (OBJ_IS_DENSE_ARRAY(cx, obj) && start <= MAXINDEX - count &&
|
||||
!INDEX_TOO_BIG(start + count)) {
|
||||
if (OBJ_IS_DENSE_ARRAY(cx, obj) && !js_PrototypeHasIndexedProperties(cx, obj) &&
|
||||
start <= MAXINDEX - count && !INDEX_TOO_BIG(start + count)) {
|
||||
|
||||
#ifdef DEBUG_jwalden
|
||||
{
|
||||
/* Verify that overwriteType and writeType were accurate. */
|
||||
JSAutoTempIdRooter idr(cx, JSVAL_ZERO);
|
||||
for (jsuint i = 0; i < count; i++) {
|
||||
JS_ASSERT_IF(vectorType == SourceVectorAllValues, vector[i] != JSVAL_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_LOOKUP_PROPERTY(cx, obj, idr.id(), &obj2, &prop));
|
||||
JS_ASSERT(!prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
jsuint newlen = start + count;
|
||||
JS_ASSERT(jsdouble(start) + count == jsdouble(newlen));
|
||||
if (!EnsureCapacity(cx, obj, newlen))
|
||||
@ -1624,7 +1661,26 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva
|
||||
obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen;
|
||||
|
||||
JS_ASSERT(count < size_t(-1) / sizeof(jsval));
|
||||
if (targetType == TargetElementsMayContainValues) {
|
||||
jsuint valueCount = 0;
|
||||
for (jsuint i = 0; i < count; i++) {
|
||||
if (obj->dslots[start + i] != JSVAL_HOLE)
|
||||
valueCount++;
|
||||
}
|
||||
JS_ASSERT(uint32(obj->fslots[JSSLOT_ARRAY_COUNT]) >= valueCount);
|
||||
obj->fslots[JSSLOT_ARRAY_COUNT] -= valueCount;
|
||||
}
|
||||
memcpy(obj->dslots + start, vector, sizeof(jsval) * count);
|
||||
if (vectorType == SourceVectorAllValues) {
|
||||
obj->fslots[JSSLOT_ARRAY_COUNT] += 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;
|
||||
}
|
||||
JS_ASSERT_IF(count != 0, obj->dslots[newlen - 1] != JSVAL_HOLE);
|
||||
return JS_TRUE;
|
||||
}
|
||||
@ -1749,6 +1805,40 @@ array_reverse(JSContext *cx, uintN argc, jsval *vp)
|
||||
obj = JS_THIS_OBJECT(cx, vp);
|
||||
if (!obj || !js_GetLengthProperty(cx, obj, &len))
|
||||
return JS_FALSE;
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
|
||||
if (OBJ_IS_DENSE_ARRAY(cx, obj) && !js_PrototypeHasIndexedProperties(cx, obj)) {
|
||||
/* An empty array or an array with no elements is already reversed. */
|
||||
if (len == 0 || !obj->dslots)
|
||||
return JS_TRUE;
|
||||
|
||||
/*
|
||||
* It's actually surprisingly complicated to reverse an array due to the
|
||||
* orthogonality of array length and array capacity while handling
|
||||
* leading and trailing holes correctly. Reversing seems less likely to
|
||||
* be a common operation than other array mass-mutation methods, so for
|
||||
* now just take a probably-small memory hit (in the absence of too many
|
||||
* holes in the array at its start) and ensure that the capacity is
|
||||
* sufficient to hold all the elements in the array if it were full.
|
||||
*/
|
||||
if (!EnsureCapacity(cx, obj, len))
|
||||
return JS_FALSE;
|
||||
|
||||
jsval* lo = &obj->dslots[0];
|
||||
jsval* hi = &obj->dslots[len - 1];
|
||||
for (; lo < hi; lo++, hi--) {
|
||||
jsval tmp = *lo;
|
||||
*lo = *hi;
|
||||
*hi = tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Per ECMA-262, don't update the length of the array, even if the new
|
||||
* array has trailing holes (and thus the original array began with
|
||||
* holes).
|
||||
*/
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
ok = JS_TRUE;
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr);
|
||||
@ -2223,7 +2313,8 @@ array_sort(JSContext *cx, uintN argc, jsval *vp)
|
||||
* easier.
|
||||
*/
|
||||
tvr.count = newlen;
|
||||
ok = InitArrayElements(cx, obj, 0, newlen, vec);
|
||||
ok = InitArrayElements(cx, obj, 0, newlen, vec, TargetElementsMayContainValues,
|
||||
SourceVectorAllValues);
|
||||
if (!ok)
|
||||
goto out;
|
||||
|
||||
@ -2263,8 +2354,10 @@ array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *
|
||||
|
||||
if (!js_GetLengthProperty(cx, obj, &length))
|
||||
return JS_FALSE;
|
||||
if (!InitArrayElements(cx, obj, length, argc, argv))
|
||||
if (!InitArrayElements(cx, obj, length, argc, argv, TargetElementsMayContainValues,
|
||||
SourceVectorAllValues)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Per ECMA-262, return the new array length. */
|
||||
jsdouble newlength = length + jsdouble(argc);
|
||||
@ -2422,8 +2515,7 @@ array_shift(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
jsuint length, i;
|
||||
JSBool hole, ok;
|
||||
JSTempValueRooter tvr;
|
||||
JSBool hole;
|
||||
|
||||
obj = JS_THIS_OBJECT(cx, vp);
|
||||
if (!obj || !js_GetLengthProperty(cx, obj, &length))
|
||||
@ -2433,27 +2525,44 @@ array_shift(JSContext *cx, uintN argc, jsval *vp)
|
||||
} else {
|
||||
length--;
|
||||
|
||||
/* Get the to-be-deleted property's value into vp ASAP. */
|
||||
if (!GetArrayElement(cx, obj, 0, &hole, vp))
|
||||
return JS_FALSE;
|
||||
if (OBJ_IS_DENSE_ARRAY(cx, obj) && !js_PrototypeHasIndexedProperties(cx, obj) &&
|
||||
length < js_DenseArrayCapacity(obj)) {
|
||||
if (JS_LIKELY(obj->dslots != NULL)) {
|
||||
*vp = obj->dslots[0];
|
||||
if (*vp == JSVAL_HOLE)
|
||||
*vp = JSVAL_VOID;
|
||||
else
|
||||
obj->fslots[JSSLOT_ARRAY_COUNT]--;
|
||||
memmove(obj->dslots, obj->dslots + 1, length * sizeof(jsval));
|
||||
obj->dslots[length] = JSVAL_HOLE;
|
||||
} else {
|
||||
/*
|
||||
* We don't need to modify the indexed properties of an empty array
|
||||
* 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);
|
||||
*vp = JSVAL_VOID;
|
||||
}
|
||||
} else {
|
||||
/* Get the to-be-deleted property's value into vp ASAP. */
|
||||
if (!GetArrayElement(cx, obj, 0, &hole, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Slide down the array above the first element. */
|
||||
ok = JS_TRUE;
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr);
|
||||
for (i = 0; i != length; i++) {
|
||||
ok = JS_CHECK_OPERATION_LIMIT(cx) &&
|
||||
GetArrayElement(cx, obj, i + 1, &hole, &tvr.u.value) &&
|
||||
SetOrDeleteArrayElement(cx, obj, i, hole, tvr.u.value);
|
||||
if (!ok)
|
||||
break;
|
||||
/* Slide down the array above the first element. */
|
||||
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
|
||||
for (i = 0; i != length; i++) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!GetArrayElement(cx, obj, i + 1, &hole, tvr.addr()) ||
|
||||
!SetOrDeleteArrayElement(cx, obj, i, hole, tvr.value())) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete the only or last element when it exists. */
|
||||
if (!hole && !DeleteArrayElement(cx, obj, length))
|
||||
return JS_FALSE;
|
||||
}
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
|
||||
/* Delete the only or last element when it exist. */
|
||||
if (!hole && !DeleteArrayElement(cx, obj, length))
|
||||
return JS_FALSE;
|
||||
}
|
||||
return js_SetLengthProperty(cx, obj, length);
|
||||
}
|
||||
@ -2464,8 +2573,7 @@ array_unshift(JSContext *cx, uintN argc, jsval *vp)
|
||||
JSObject *obj;
|
||||
jsval *argv;
|
||||
jsuint length;
|
||||
JSBool hole, ok;
|
||||
JSTempValueRooter tvr;
|
||||
JSBool hole;
|
||||
jsdouble last, newlen;
|
||||
|
||||
obj = JS_THIS_OBJECT(cx, vp);
|
||||
@ -2476,25 +2584,31 @@ array_unshift(JSContext *cx, uintN argc, jsval *vp)
|
||||
/* Slide up the array to make room for argc at the bottom. */
|
||||
argv = JS_ARGV(cx, vp);
|
||||
if (length > 0) {
|
||||
last = length;
|
||||
ok = JS_TRUE;
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr);
|
||||
do {
|
||||
--last;
|
||||
ok = JS_CHECK_OPERATION_LIMIT(cx) &&
|
||||
GetArrayElement(cx, obj, last, &hole, &tvr.u.value) &&
|
||||
SetOrDeleteArrayElement(cx, obj, last + argc, hole,
|
||||
tvr.u.value);
|
||||
if (!ok)
|
||||
break;
|
||||
} while (last != 0);
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
if (OBJ_IS_DENSE_ARRAY(cx, obj) && !js_PrototypeHasIndexedProperties(cx, obj) &&
|
||||
!INDEX_TOO_SPARSE(obj, newlen + argc)) {
|
||||
JS_ASSERT(newlen + argc == length + argc);
|
||||
if (!EnsureCapacity(cx, obj, length + argc))
|
||||
return JS_FALSE;
|
||||
memmove(obj->dslots + argc, obj->dslots, length * sizeof(jsval));
|
||||
for (uint32 i = 0; i < argc; i++)
|
||||
obj->dslots[i] = JSVAL_HOLE;
|
||||
} else {
|
||||
last = length;
|
||||
jsdouble upperIndex = last + argc;
|
||||
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
|
||||
do {
|
||||
--last, --upperIndex;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
|
||||
!SetOrDeleteArrayElement(cx, obj, upperIndex, hole, tvr.value())) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
} while (last != 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy from argv to the bottom of the array. */
|
||||
if (!InitArrayElements(cx, obj, 0, argc, argv))
|
||||
if (!InitArrayElements(cx, obj, 0, argc, argv, TargetElementsAllHoles, SourceVectorAllValues))
|
||||
return JS_FALSE;
|
||||
|
||||
newlen += argc;
|
||||
@ -2513,9 +2627,8 @@ array_splice(JSContext *cx, uintN argc, jsval *vp)
|
||||
JSObject *obj;
|
||||
jsuint length, begin, end, count, delta, last;
|
||||
jsdouble d;
|
||||
JSBool hole, ok;
|
||||
JSBool hole;
|
||||
JSObject *obj2;
|
||||
JSTempValueRooter tvr;
|
||||
|
||||
/*
|
||||
* Create a new array value to return. Our ECMA v2 proposal specs
|
||||
@ -2572,68 +2685,94 @@ array_splice(JSContext *cx, uintN argc, jsval *vp)
|
||||
argv++;
|
||||
}
|
||||
|
||||
MUST_FLOW_THROUGH("out");
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr);
|
||||
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
|
||||
|
||||
/* If there are elements to remove, put them into the return value. */
|
||||
if (count > 0) {
|
||||
for (last = begin; last < end; last++) {
|
||||
ok = JS_CHECK_OPERATION_LIMIT(cx) &&
|
||||
GetArrayElement(cx, obj, last, &hole, &tvr.u.value);
|
||||
if (!ok)
|
||||
goto out;
|
||||
|
||||
/* Copy tvr.u.value to new array unless it's a hole. */
|
||||
if (!hole) {
|
||||
ok = SetArrayElement(cx, obj2, last - begin, tvr.u.value);
|
||||
if (!ok)
|
||||
goto out;
|
||||
if (OBJ_IS_DENSE_ARRAY(cx, obj) && !js_PrototypeHasIndexedProperties(cx, obj) &&
|
||||
!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])) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (last = begin; last < end; last++) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!GetArrayElement(cx, obj, last, &hole, tvr.addr())) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
ok = js_SetLengthProperty(cx, obj2, end - begin);
|
||||
if (!ok)
|
||||
goto out;
|
||||
/* Copy tvr.value() to the new array unless it's a hole. */
|
||||
if (!hole && !SetArrayElement(cx, obj2, last - begin, tvr.value()))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (!js_SetLengthProperty(cx, obj2, count))
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the direction (up or down) to copy and make way for argv. */
|
||||
if (argc > count) {
|
||||
delta = (jsuint)argc - count;
|
||||
last = length;
|
||||
/* (uint) end could be 0, so can't use vanilla >= test */
|
||||
while (last-- > end) {
|
||||
ok = JS_CHECK_OPERATION_LIMIT(cx) &&
|
||||
GetArrayElement(cx, obj, last, &hole, &tvr.u.value) &&
|
||||
SetOrDeleteArrayElement(cx, obj, last + delta, hole,
|
||||
tvr.u.value);
|
||||
if (!ok)
|
||||
goto out;
|
||||
if (OBJ_IS_DENSE_ARRAY(cx, obj) && !js_PrototypeHasIndexedProperties(cx, obj) &&
|
||||
length <= js_DenseArrayCapacity(obj) && obj->dslots[length - 1] != JSVAL_HOLE) {
|
||||
if (!EnsureCapacity(cx, obj, length + delta))
|
||||
return JS_FALSE;
|
||||
/* (uint) end could be 0, so we can't use a vanilla >= test. */
|
||||
while (last-- > end) {
|
||||
jsval srcval = obj->dslots[last];
|
||||
jsval* dest = &obj->dslots[last + delta];
|
||||
if (*dest == JSVAL_HOLE && srcval != JSVAL_HOLE)
|
||||
obj->fslots[JSSLOT_ARRAY_COUNT]++;
|
||||
*dest = srcval;
|
||||
}
|
||||
obj->fslots[JSSLOT_ARRAY_LENGTH] += delta;
|
||||
} else {
|
||||
/* (uint) end could be 0, so we can't use a vanilla >= test. */
|
||||
while (last-- > end) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
|
||||
!SetOrDeleteArrayElement(cx, obj, last + delta, hole, tvr.value())) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
length += delta;
|
||||
} else if (argc < count) {
|
||||
delta = count - (jsuint)argc;
|
||||
for (last = end; last < length; last++) {
|
||||
ok = JS_CHECK_OPERATION_LIMIT(cx) &&
|
||||
GetArrayElement(cx, obj, last, &hole, &tvr.u.value) &&
|
||||
SetOrDeleteArrayElement(cx, obj, last - delta, hole,
|
||||
tvr.u.value);
|
||||
if (!ok)
|
||||
goto out;
|
||||
if (OBJ_IS_DENSE_ARRAY(cx, obj) && !js_PrototypeHasIndexedProperties(cx, obj) &&
|
||||
length <= js_DenseArrayCapacity(obj)) {
|
||||
/* (uint) end could be 0, so we can't use a vanilla >= test. */
|
||||
for (last = end; last < length; last++) {
|
||||
jsval srcval = obj->dslots[last];
|
||||
jsval* dest = &obj->dslots[last - delta];
|
||||
if (*dest == JSVAL_HOLE && srcval != JSVAL_HOLE)
|
||||
obj->fslots[JSSLOT_ARRAY_COUNT]++;
|
||||
*dest = srcval;
|
||||
}
|
||||
} else {
|
||||
for (last = end; last < length; last++) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
|
||||
!SetOrDeleteArrayElement(cx, obj, last - delta, hole, tvr.value())) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
length -= delta;
|
||||
}
|
||||
|
||||
/* Copy from argv into the hole to complete the splice. */
|
||||
ok = InitArrayElements(cx, obj, begin, argc, argv);
|
||||
if (!ok)
|
||||
goto out;
|
||||
|
||||
/* Update length in case we deleted elements from the end. */
|
||||
ok = js_SetLengthProperty(cx, obj, length);
|
||||
|
||||
out:
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
return ok;
|
||||
/*
|
||||
* 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) &&
|
||||
js_SetLengthProperty(cx, obj, length);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2753,8 +2892,7 @@ array_slice(JSContext *cx, uintN argc, jsval *vp)
|
||||
JSObject *nobj, *obj;
|
||||
jsuint length, begin, end, slot;
|
||||
jsdouble d;
|
||||
JSBool hole, ok;
|
||||
JSTempValueRooter tvr;
|
||||
JSBool hole;
|
||||
|
||||
argv = JS_ARGV(cx, vp);
|
||||
|
||||
@ -2797,7 +2935,8 @@ array_slice(JSContext *cx, uintN argc, jsval *vp)
|
||||
if (begin > end)
|
||||
begin = end;
|
||||
|
||||
if (OBJ_IS_DENSE_ARRAY(cx, obj) && end <= js_DenseArrayCapacity(obj)) {
|
||||
if (OBJ_IS_DENSE_ARRAY(cx, obj) && 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]);
|
||||
@ -2813,25 +2952,17 @@ array_slice(JSContext *cx, uintN argc, jsval *vp)
|
||||
return JS_FALSE;
|
||||
*vp = OBJECT_TO_JSVAL(nobj);
|
||||
|
||||
MUST_FLOW_THROUGH("out");
|
||||
JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr);
|
||||
|
||||
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
|
||||
for (slot = begin; slot < end; slot++) {
|
||||
ok = JS_CHECK_OPERATION_LIMIT(cx) &&
|
||||
GetArrayElement(cx, obj, slot, &hole, &tvr.u.value);
|
||||
if (!ok)
|
||||
goto out;
|
||||
if (!hole) {
|
||||
ok = SetArrayElement(cx, nobj, slot - begin, tvr.u.value);
|
||||
if (!ok)
|
||||
goto out;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!GetArrayElement(cx, obj, slot, &hole, tvr.addr())) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (!hole && !SetArrayElement(cx, nobj, slot - begin, tvr.value()))
|
||||
return JS_FALSE;
|
||||
}
|
||||
ok = js_SetLengthProperty(cx, nobj, end - begin);
|
||||
|
||||
out:
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
return ok;
|
||||
return js_SetLengthProperty(cx, nobj, end - begin);
|
||||
}
|
||||
|
||||
#if JS_HAS_ARRAY_EXTRAS
|
||||
|
Loading…
Reference in New Issue
Block a user