Backed out changeset e7065853ef79; I'll be repushing this incrementally, attempting to find the precise place where things go bad, in the near future. Happy days are here again! :-\
This commit is contained in:
@@ -231,7 +231,7 @@ js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
AutoValueRooter tvr(cx, JSVAL_NULL);
|
||||
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
|
||||
if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), tvr.addr()))
|
||||
return JS_FALSE;
|
||||
|
||||
@@ -405,7 +405,7 @@ EnsureCapacity(JSContext *cx, JSObject *obj, uint32 newcap,
|
||||
static bool
|
||||
ReallyBigIndexToId(JSContext* cx, jsdouble index, jsid* idp)
|
||||
{
|
||||
AutoValueRooter dval(cx);
|
||||
JSAutoTempValueRooter dval(cx);
|
||||
if (!js_NewDoubleInRootedValue(cx, index, dval.addr()) ||
|
||||
!js_ValueToStringId(cx, dval.value(), idp)) {
|
||||
return JS_FALSE;
|
||||
@@ -450,7 +450,7 @@ GetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole,
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
AutoIdRooter idr(cx);
|
||||
JSAutoTempIdRooter idr(cx);
|
||||
|
||||
*hole = JS_FALSE;
|
||||
if (!IndexToId(cx, obj, index, hole, idr.addr()))
|
||||
@@ -505,7 +505,7 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, jsval v)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
AutoIdRooter idr(cx);
|
||||
JSAutoTempIdRooter idr(cx);
|
||||
|
||||
if (!IndexToId(cx, obj, index, NULL, idr.addr(), JS_TRUE))
|
||||
return JS_FALSE;
|
||||
@@ -531,7 +531,7 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
AutoIdRooter idr(cx);
|
||||
JSAutoTempIdRooter idr(cx);
|
||||
|
||||
if (!IndexToId(cx, obj, index, NULL, idr.addr()))
|
||||
return JS_FALSE;
|
||||
@@ -573,7 +573,7 @@ JSBool
|
||||
js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
|
||||
{
|
||||
JSErrorReporter older = JS_SetErrorReporter(cx, NULL);
|
||||
AutoValueRooter tvr(cx, JSVAL_NULL);
|
||||
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
||||
JSBool ok = obj->getProperty(cx, id, tvr.addr());
|
||||
JS_SetErrorReporter(cx, older);
|
||||
@@ -626,6 +626,9 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||
{
|
||||
jsuint newlen, oldlen, gap, index;
|
||||
jsval junk;
|
||||
JSObject *iter;
|
||||
JSTempValueRooter tvr;
|
||||
JSBool ok;
|
||||
|
||||
if (!obj->isArray()) {
|
||||
jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
||||
@@ -635,30 +638,32 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||
|
||||
newlen = ValueIsLength(cx, vp);
|
||||
if (JSVAL_IS_NULL(*vp))
|
||||
return false;
|
||||
return JS_FALSE;
|
||||
oldlen = obj->fslots[JSSLOT_ARRAY_LENGTH];
|
||||
|
||||
if (oldlen == newlen)
|
||||
return true;
|
||||
return JS_TRUE;
|
||||
|
||||
if (!IndexToValue(cx, newlen, vp))
|
||||
return false;
|
||||
return JS_FALSE;
|
||||
|
||||
if (oldlen < newlen) {
|
||||
obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen;
|
||||
return true;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
if (obj->isDenseArray()) {
|
||||
/* Don't reallocate if we're not actually shrinking our slots. */
|
||||
jsuint capacity = js_DenseArrayCapacity(obj);
|
||||
if (capacity > newlen && !ResizeSlots(cx, obj, capacity, newlen))
|
||||
return false;
|
||||
return JS_FALSE;
|
||||
} else if (oldlen - newlen < (1 << 24)) {
|
||||
do {
|
||||
--oldlen;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeleteArrayElement(cx, obj, oldlen))
|
||||
return false;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!DeleteArrayElement(cx, obj, oldlen)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
} while (oldlen != newlen);
|
||||
} else {
|
||||
/*
|
||||
@@ -668,28 +673,33 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||
* correspond to indexes in the half-open range [newlen, oldlen). See
|
||||
* bug 322135.
|
||||
*/
|
||||
JSObject *iter = JS_NewPropertyIterator(cx, obj);
|
||||
iter = JS_NewPropertyIterator(cx, obj);
|
||||
if (!iter)
|
||||
return false;
|
||||
return JS_FALSE;
|
||||
|
||||
/* Protect iter against GC under JSObject::deleteProperty. */
|
||||
AutoValueRooter tvr(cx, iter);
|
||||
|
||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, iter, &tvr);
|
||||
gap = oldlen - newlen;
|
||||
for (;;) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) || !JS_NextProperty(cx, iter, &id))
|
||||
return false;
|
||||
ok = (JS_CHECK_OPERATION_LIMIT(cx) &&
|
||||
JS_NextProperty(cx, iter, &id));
|
||||
if (!ok)
|
||||
break;
|
||||
if (JSVAL_IS_VOID(id))
|
||||
break;
|
||||
if (js_IdIsIndex(id, &index) && index - newlen < gap &&
|
||||
!obj->deleteProperty(cx, id, &junk)) {
|
||||
return false;
|
||||
if (js_IdIsIndex(id, &index) && index - newlen < gap) {
|
||||
ok = obj->deleteProperty(cx, id, &junk);
|
||||
if (!ok)
|
||||
break;
|
||||
}
|
||||
}
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen;
|
||||
return true;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1508,7 +1518,7 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
|
||||
return true;
|
||||
}
|
||||
|
||||
AutoValueRooter tvr(cx, obj);
|
||||
JSAutoTempValueRooter tvr(cx, obj);
|
||||
|
||||
/* After this point, all paths exit through the 'out' label. */
|
||||
MUST_FLOW_THROUGH("out");
|
||||
@@ -1642,7 +1652,7 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva
|
||||
#ifdef DEBUG_jwalden
|
||||
{
|
||||
/* Verify that overwriteType and writeType were accurate. */
|
||||
AutoIdRooter idr(cx);
|
||||
JSAutoTempIdRooter idr(cx, JSVAL_ZERO);
|
||||
for (jsuint i = 0; i < count; i++) {
|
||||
JS_ASSERT_IF(vectorType == SourceVectorAllValues, vector[i] != JSVAL_HOLE);
|
||||
|
||||
@@ -1708,12 +1718,12 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva
|
||||
|
||||
JS_ASSERT(start == MAXINDEX);
|
||||
jsval tmp[2] = {JSVAL_NULL, JSVAL_NULL};
|
||||
AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tmp), tmp);
|
||||
JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(tmp), tmp);
|
||||
if (!js_NewDoubleInRootedValue(cx, MAXINDEX, &tmp[0]))
|
||||
return JS_FALSE;
|
||||
jsdouble *dp = JSVAL_TO_DOUBLE(tmp[0]);
|
||||
JS_ASSERT(*dp == MAXINDEX);
|
||||
AutoIdRooter idr(cx);
|
||||
JSAutoTempIdRooter idr(cx);
|
||||
do {
|
||||
tmp[1] = *vector++;
|
||||
if (!js_ValueToStringId(cx, tmp[0], idr.addr()) ||
|
||||
@@ -1759,7 +1769,7 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector,
|
||||
static JSString* FASTCALL
|
||||
Array_p_join(JSContext* cx, JSObject* obj, JSString *str)
|
||||
{
|
||||
AutoValueRooter tvr(cx);
|
||||
JSAutoTempValueRooter tvr(cx);
|
||||
if (!array_toString_sub(cx, obj, JS_FALSE, str, tvr.addr())) {
|
||||
SetBuiltinError(cx);
|
||||
return NULL;
|
||||
@@ -1770,7 +1780,7 @@ Array_p_join(JSContext* cx, JSObject* obj, JSString *str)
|
||||
static JSString* FASTCALL
|
||||
Array_p_toString(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
AutoValueRooter tvr(cx);
|
||||
JSAutoTempValueRooter tvr(cx);
|
||||
if (!array_toString_sub(cx, obj, JS_FALSE, NULL, tvr.addr())) {
|
||||
SetBuiltinError(cx);
|
||||
return NULL;
|
||||
@@ -1842,7 +1852,7 @@ array_reverse(JSContext *cx, uintN argc, jsval *vp)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
AutoValueRooter tvr(cx);
|
||||
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
|
||||
for (jsuint i = 0, half = len / 2; i < half; i++) {
|
||||
JSBool hole, hole2;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
@@ -2092,28 +2102,40 @@ JS_STATIC_ASSERT(JSVAL_NULL == 0);
|
||||
static JSBool
|
||||
array_sort(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
jsval fval;
|
||||
jsval *argv, fval, *vec, *mergesort_tmp, v;
|
||||
JSObject *obj;
|
||||
CompareArgs ca;
|
||||
jsuint len, newlen, i, undefs;
|
||||
JSTempValueRooter tvr;
|
||||
JSBool hole;
|
||||
JSBool ok;
|
||||
size_t elemsize;
|
||||
JSString *str;
|
||||
|
||||
jsval *argv = JS_ARGV(cx, vp);
|
||||
/*
|
||||
* Optimize the default compare function case if all of obj's elements
|
||||
* have values of type string.
|
||||
*/
|
||||
JSBool all_strings;
|
||||
|
||||
argv = JS_ARGV(cx, vp);
|
||||
if (argc > 0) {
|
||||
if (JSVAL_IS_PRIMITIVE(argv[0])) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG);
|
||||
return false;
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_SORT_ARG);
|
||||
return JS_FALSE;
|
||||
}
|
||||
fval = argv[0]; /* non-default compare function */
|
||||
} else {
|
||||
fval = JSVAL_NULL;
|
||||
}
|
||||
|
||||
JSObject *obj = JS_THIS_OBJECT(cx, vp);
|
||||
obj = JS_THIS_OBJECT(cx, vp);
|
||||
if (!obj || !js_GetLengthProperty(cx, obj, &len))
|
||||
return false;
|
||||
return JS_FALSE;
|
||||
if (len == 0) {
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
return true;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2123,16 +2145,19 @@ array_sort(JSContext *cx, uintN argc, jsval *vp)
|
||||
* malloc'd vector.
|
||||
*/
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
if (size_t(len) > SIZE_MAX / (2 * sizeof(jsval))) {
|
||||
if ((size_t)len > ~(size_t)0 / (2 * sizeof(jsval))) {
|
||||
js_ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
vec = (jsval *) cx->malloc(2 * (size_t) len * sizeof(jsval));
|
||||
if (!vec)
|
||||
return JS_FALSE;
|
||||
|
||||
/*
|
||||
* Initialize vec as a root. We will clear elements of vec one by
|
||||
* one while increasing the rooted amount of vec when we know that the
|
||||
* property at the corresponding index exists and its value must be rooted.
|
||||
* one while increasing tvr.count when we know that the property at
|
||||
* the corresponding index exists and its value must be rooted.
|
||||
*
|
||||
* In this way when sorting a huge mostly sparse array we will not
|
||||
* access the tail of vec corresponding to properties that do not
|
||||
@@ -2140,196 +2165,204 @@ array_sort(JSContext *cx, uintN argc, jsval *vp)
|
||||
*
|
||||
* After this point control must flow through label out: to exit.
|
||||
*/
|
||||
{
|
||||
jsval *vec = (jsval *) cx->malloc(2 * size_t(len) * sizeof(jsval));
|
||||
if (!vec)
|
||||
return false;
|
||||
JS_PUSH_TEMP_ROOT(cx, 0, vec, &tvr);
|
||||
|
||||
struct AutoFreeVector {
|
||||
AutoFreeVector(JSContext *cx, jsval *&vec) : cx(cx), vec(vec) { }
|
||||
~AutoFreeVector() {
|
||||
cx->free(vec);
|
||||
}
|
||||
JSContext * const cx;
|
||||
jsval *&vec;
|
||||
} free(cx, vec);
|
||||
/*
|
||||
* By ECMA 262, 15.4.4.11, a property that does not exist (which we
|
||||
* call a "hole") is always greater than an existing property with
|
||||
* value undefined and that is always greater than any other property.
|
||||
* Thus to sort holes and undefs we simply count them, sort the rest
|
||||
* of elements, append undefs after them and then make holes after
|
||||
* undefs.
|
||||
*/
|
||||
undefs = 0;
|
||||
newlen = 0;
|
||||
all_strings = JS_TRUE;
|
||||
for (i = 0; i < len; i++) {
|
||||
ok = JS_CHECK_OPERATION_LIMIT(cx);
|
||||
if (!ok)
|
||||
goto out;
|
||||
|
||||
AutoArrayRooter tvr(cx, 0, vec);
|
||||
/* Clear vec[newlen] before including it in the rooted set. */
|
||||
vec[newlen] = JSVAL_NULL;
|
||||
tvr.count = newlen + 1;
|
||||
ok = GetArrayElement(cx, obj, i, &hole, &vec[newlen]);
|
||||
if (!ok)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* By ECMA 262, 15.4.4.11, a property that does not exist (which we
|
||||
* call a "hole") is always greater than an existing property with
|
||||
* value undefined and that is always greater than any other property.
|
||||
* Thus to sort holes and undefs we simply count them, sort the rest
|
||||
* of elements, append undefs after them and then make holes after
|
||||
* undefs.
|
||||
*/
|
||||
undefs = 0;
|
||||
newlen = 0;
|
||||
bool allStrings = true;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
||||
return false;
|
||||
if (hole)
|
||||
continue;
|
||||
|
||||
/* Clear vec[newlen] before including it in the rooted set. */
|
||||
JSBool hole;
|
||||
vec[newlen] = JSVAL_NULL;
|
||||
tvr.changeLength(newlen + 1);
|
||||
if (!GetArrayElement(cx, obj, i, &hole, &vec[newlen]))
|
||||
return false;
|
||||
|
||||
if (hole)
|
||||
continue;
|
||||
|
||||
if (JSVAL_IS_VOID(vec[newlen])) {
|
||||
++undefs;
|
||||
continue;
|
||||
}
|
||||
|
||||
allStrings = allStrings && JSVAL_IS_STRING(vec[newlen]);
|
||||
|
||||
++newlen;
|
||||
if (JSVAL_IS_VOID(vec[newlen])) {
|
||||
++undefs;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (newlen == 0)
|
||||
return true; /* The array has only holes and undefs. */
|
||||
/* We know JSVAL_IS_STRING yields 0 or 1, so avoid a branch via &=. */
|
||||
all_strings &= JSVAL_IS_STRING(vec[newlen]);
|
||||
|
||||
++newlen;
|
||||
}
|
||||
|
||||
if (newlen == 0) {
|
||||
/* The array has only holes and undefs. */
|
||||
ok = JS_TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* The first newlen elements of vec are copied from the array object
|
||||
* (above). The remaining newlen positions are used as GC-rooted scratch
|
||||
* space for mergesort. We must clear the space before including it to
|
||||
* the root set covered by tvr.count. We assume JSVAL_NULL==0 to optimize
|
||||
* initialization using memset.
|
||||
*/
|
||||
mergesort_tmp = vec + newlen;
|
||||
memset(mergesort_tmp, 0, newlen * sizeof(jsval));
|
||||
tvr.count = newlen * 2;
|
||||
|
||||
/* Here len == 2 * (newlen + undefs + number_of_holes). */
|
||||
if (fval == JSVAL_NULL) {
|
||||
/*
|
||||
* The first newlen elements of vec are copied from the array object
|
||||
* (above). The remaining newlen positions are used as GC-rooted scratch
|
||||
* space for mergesort. We must clear the space before including it to
|
||||
* the root set covered by tvr.count. We assume JSVAL_NULL==0 to optimize
|
||||
* initialization using memset.
|
||||
* Sort using the default comparator converting all elements to
|
||||
* strings.
|
||||
*/
|
||||
jsval *mergesort_tmp = vec + newlen;
|
||||
memset(mergesort_tmp, 0, newlen * sizeof(jsval));
|
||||
tvr.changeLength(newlen * 2);
|
||||
|
||||
/* Here len == 2 * (newlen + undefs + number_of_holes). */
|
||||
if (fval == JSVAL_NULL) {
|
||||
if (all_strings) {
|
||||
elemsize = sizeof(jsval);
|
||||
} else {
|
||||
/*
|
||||
* Sort using the default comparator converting all elements to
|
||||
* strings.
|
||||
* To avoid string conversion on each compare we do it only once
|
||||
* prior to sorting. But we also need the space for the original
|
||||
* values to recover the sorting result. To reuse
|
||||
* sort_compare_strings we move the original values to the odd
|
||||
* indexes in vec, put the string conversion results in the even
|
||||
* indexes and pass 2 * sizeof(jsval) as an element size to the
|
||||
* sorting function. In this way sort_compare_strings will only
|
||||
* see the string values when it casts the compare arguments as
|
||||
* pointers to jsval.
|
||||
*
|
||||
* This requires doubling the temporary storage including the
|
||||
* scratch space for the merge sort. Since vec already contains
|
||||
* the rooted scratch space for newlen elements at the tail, we
|
||||
* can use it to rearrange and convert to strings first and try
|
||||
* realloc only when we know that we successfully converted all
|
||||
* the elements.
|
||||
*/
|
||||
if (allStrings) {
|
||||
elemsize = sizeof(jsval);
|
||||
} else {
|
||||
/*
|
||||
* To avoid string conversion on each compare we do it only once
|
||||
* prior to sorting. But we also need the space for the original
|
||||
* values to recover the sorting result. To reuse
|
||||
* sort_compare_strings we move the original values to the odd
|
||||
* indexes in vec, put the string conversion results in the even
|
||||
* indexes and pass 2 * sizeof(jsval) as an element size to the
|
||||
* sorting function. In this way sort_compare_strings will only
|
||||
* see the string values when it casts the compare arguments as
|
||||
* pointers to jsval.
|
||||
*
|
||||
* This requires doubling the temporary storage including the
|
||||
* scratch space for the merge sort. Since vec already contains
|
||||
* the rooted scratch space for newlen elements at the tail, we
|
||||
* can use it to rearrange and convert to strings first and try
|
||||
* realloc only when we know that we successfully converted all
|
||||
* the elements.
|
||||
*/
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
if (size_t(newlen) > SIZE_MAX / (4 * sizeof(jsval))) {
|
||||
js_ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
}
|
||||
if ((size_t)newlen > ~(size_t)0 / (4 * sizeof(jsval))) {
|
||||
js_ReportAllocationOverflow(cx);
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Rearrange and string-convert the elements of the vector from
|
||||
* the tail here and, after sorting, move the results back
|
||||
* starting from the start to prevent overwrite the existing
|
||||
* elements.
|
||||
*/
|
||||
i = newlen;
|
||||
do {
|
||||
--i;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
||||
return false;
|
||||
jsval v = vec[i];
|
||||
str = js_ValueToString(cx, v);
|
||||
if (!str)
|
||||
return false;
|
||||
vec[2 * i] = STRING_TO_JSVAL(str);
|
||||
vec[2 * i + 1] = v;
|
||||
} while (i != 0);
|
||||
|
||||
JS_ASSERT(tvr.array == vec);
|
||||
vec = (jsval *) cx->realloc(vec, 4 * size_t(newlen) * sizeof(jsval));
|
||||
if (!vec) {
|
||||
vec = tvr.array;
|
||||
return false;
|
||||
/*
|
||||
* Rearrange and string-convert the elements of the vector from
|
||||
* the tail here and, after sorting, move the results back
|
||||
* starting from the start to prevent overwrite the existing
|
||||
* elements.
|
||||
*/
|
||||
i = newlen;
|
||||
do {
|
||||
--i;
|
||||
ok = JS_CHECK_OPERATION_LIMIT(cx);
|
||||
if (!ok)
|
||||
goto out;
|
||||
v = vec[i];
|
||||
str = js_ValueToString(cx, v);
|
||||
if (!str) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
mergesort_tmp = vec + 2 * newlen;
|
||||
memset(mergesort_tmp, 0, newlen * 2 * sizeof(jsval));
|
||||
tvr.changeArray(vec, newlen * 4);
|
||||
elemsize = 2 * sizeof(jsval);
|
||||
}
|
||||
if (!js_MergeSort(vec, size_t(newlen), elemsize,
|
||||
sort_compare_strings, cx, mergesort_tmp)) {
|
||||
return false;
|
||||
}
|
||||
if (!allStrings) {
|
||||
/*
|
||||
* We want to make the following loop fast and to unroot the
|
||||
* cached results of toString invocations before the operation
|
||||
* callback has a chance to run the GC. For this reason we do
|
||||
* not call JS_CHECK_OPERATION_LIMIT in the loop.
|
||||
*/
|
||||
i = 0;
|
||||
do {
|
||||
vec[i] = vec[2 * i + 1];
|
||||
} while (++i != newlen);
|
||||
}
|
||||
} else {
|
||||
void *mark;
|
||||
vec[2 * i] = STRING_TO_JSVAL(str);
|
||||
vec[2 * i + 1] = v;
|
||||
} while (i != 0);
|
||||
|
||||
LeaveTrace(cx);
|
||||
|
||||
CompareArgs ca;
|
||||
ca.context = cx;
|
||||
ca.fval = fval;
|
||||
ca.elemroot = js_AllocStack(cx, 2 + 2, &mark);
|
||||
if (!ca.elemroot)
|
||||
return false;
|
||||
bool ok = js_MergeSort(vec, size_t(newlen), sizeof(jsval),
|
||||
comparator_stack_cast(sort_compare),
|
||||
&ca, mergesort_tmp);
|
||||
js_FreeStack(cx, mark);
|
||||
if (!ok)
|
||||
return false;
|
||||
JS_ASSERT(tvr.u.array == vec);
|
||||
vec = (jsval *) cx->realloc(vec,
|
||||
4 * (size_t) newlen * sizeof(jsval));
|
||||
if (!vec) {
|
||||
vec = tvr.u.array;
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
tvr.u.array = vec;
|
||||
mergesort_tmp = vec + 2 * newlen;
|
||||
memset(mergesort_tmp, 0, newlen * 2 * sizeof(jsval));
|
||||
tvr.count = newlen * 4;
|
||||
elemsize = 2 * sizeof(jsval);
|
||||
}
|
||||
|
||||
/*
|
||||
* We no longer need to root the scratch space for the merge sort, so
|
||||
* unroot it now to make the job of a potential GC under
|
||||
* InitArrayElements easier.
|
||||
*/
|
||||
tvr.changeLength(newlen);
|
||||
if (!InitArrayElements(cx, obj, 0, newlen, vec, TargetElementsMayContainValues,
|
||||
SourceVectorAllValues)) {
|
||||
return false;
|
||||
ok = js_MergeSort(vec, (size_t) newlen, elemsize,
|
||||
sort_compare_strings, cx, mergesort_tmp);
|
||||
if (!ok)
|
||||
goto out;
|
||||
if (!all_strings) {
|
||||
/*
|
||||
* We want to make the following loop fast and to unroot the
|
||||
* cached results of toString invocations before the operation
|
||||
* callback has a chance to run the GC. For this reason we do
|
||||
* not call JS_CHECK_OPERATION_LIMIT in the loop.
|
||||
*/
|
||||
i = 0;
|
||||
do {
|
||||
vec[i] = vec[2 * i + 1];
|
||||
} while (++i != newlen);
|
||||
}
|
||||
} else {
|
||||
void *mark;
|
||||
|
||||
LeaveTrace(cx);
|
||||
|
||||
ca.context = cx;
|
||||
ca.fval = fval;
|
||||
ca.elemroot = js_AllocStack(cx, 2 + 2, &mark);
|
||||
if (!ca.elemroot) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
ok = js_MergeSort(vec, (size_t) newlen, sizeof(jsval),
|
||||
comparator_stack_cast(sort_compare),
|
||||
&ca, mergesort_tmp);
|
||||
js_FreeStack(cx, mark);
|
||||
if (!ok)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* We no longer need to root the scratch space for the merge sort, so
|
||||
* unroot it now to make the job of a potential GC under InitArrayElements
|
||||
* easier.
|
||||
*/
|
||||
tvr.count = newlen;
|
||||
ok = InitArrayElements(cx, obj, 0, newlen, vec, TargetElementsMayContainValues,
|
||||
SourceVectorAllValues);
|
||||
if (!ok)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
cx->free(vec);
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
|
||||
/* Set undefs that sorted after the rest of elements. */
|
||||
while (undefs != 0) {
|
||||
--undefs;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) || !SetArrayElement(cx, obj, newlen++, JSVAL_VOID))
|
||||
return false;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!SetArrayElement(cx, obj, newlen++, JSVAL_VOID)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Re-create any holes that sorted to the end of the array. */
|
||||
while (len > newlen) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeleteArrayElement(cx, obj, --len))
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!DeleteArrayElement(cx, obj, --len)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
return true;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2403,7 +2436,7 @@ JS_DEFINE_CALLINFO_3(extern, BOOL, js_ArrayCompPush, CONTEXT, OBJECT, JSVAL, 0,
|
||||
static jsval FASTCALL
|
||||
Array_p_push1(JSContext* cx, JSObject* obj, jsval v)
|
||||
{
|
||||
AutoValueRooter tvr(cx, v);
|
||||
JSAutoTempValueRooter tvr(cx, v);
|
||||
if (obj->isDenseArray()
|
||||
? array_push1_dense(cx, obj, v, tvr.addr())
|
||||
: array_push_slowly(cx, obj, 1, tvr.addr(), tvr.addr())) {
|
||||
@@ -2475,7 +2508,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, jsval *vp)
|
||||
static jsval FASTCALL
|
||||
Array_p_pop(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
AutoValueRooter tvr(cx);
|
||||
JSAutoTempValueRooter tvr(cx);
|
||||
if (obj->isDenseArray()
|
||||
? array_pop_dense(cx, obj, tvr.addr())
|
||||
: array_pop_slowly(cx, obj, tvr.addr())) {
|
||||
@@ -2539,7 +2572,7 @@ array_shift(JSContext *cx, uintN argc, jsval *vp)
|
||||
return JS_FALSE;
|
||||
|
||||
/* Slide down the array above the first element. */
|
||||
AutoValueRooter tvr(cx);
|
||||
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()) ||
|
||||
@@ -2584,7 +2617,7 @@ array_unshift(JSContext *cx, uintN argc, jsval *vp)
|
||||
} else {
|
||||
last = length;
|
||||
jsdouble upperIndex = last + argc;
|
||||
AutoValueRooter tvr(cx);
|
||||
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
|
||||
do {
|
||||
--last, --upperIndex;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
@@ -2674,7 +2707,7 @@ array_splice(JSContext *cx, uintN argc, jsval *vp)
|
||||
argv++;
|
||||
}
|
||||
|
||||
AutoValueRooter tvr(cx, JSVAL_NULL);
|
||||
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
|
||||
|
||||
/* If there are elements to remove, put them into the return value. */
|
||||
if (count > 0) {
|
||||
@@ -2813,7 +2846,7 @@ array_concat(JSContext *cx, uintN argc, jsval *vp)
|
||||
length = 0;
|
||||
}
|
||||
|
||||
AutoValueRooter tvr(cx, JSVAL_NULL);
|
||||
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
|
||||
|
||||
/* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
|
||||
for (i = 0; i <= argc; i++) {
|
||||
@@ -2927,7 +2960,7 @@ array_slice(JSContext *cx, uintN argc, jsval *vp)
|
||||
return JS_FALSE;
|
||||
*vp = OBJECT_TO_JSVAL(nobj);
|
||||
|
||||
AutoValueRooter tvr(cx);
|
||||
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
|
||||
for (slot = begin; slot < end; slot++) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!GetArrayElement(cx, obj, slot, &hole, tvr.addr())) {
|
||||
@@ -3437,7 +3470,10 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
|
||||
JSObject *
|
||||
js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey)
|
||||
{
|
||||
JSObject *obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
|
||||
JSTempValueRooter tvr;
|
||||
JSObject *obj;
|
||||
|
||||
obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
@@ -3447,11 +3483,10 @@ js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey)
|
||||
*/
|
||||
JS_ASSERT(obj->getProto());
|
||||
|
||||
{
|
||||
AutoValueRooter tvr(cx, obj);
|
||||
if (!InitArrayObject(cx, obj, length, vector, holey))
|
||||
obj = NULL;
|
||||
}
|
||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);
|
||||
if (!InitArrayObject(cx, obj, length, vector, holey))
|
||||
obj = NULL;
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
|
||||
/* Set/clear newborn root, in case we lost it. */
|
||||
cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
|
||||
@@ -3567,7 +3602,7 @@ js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector)
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
AutoValueRooter tvr(cx, obj);
|
||||
JSAutoTempValueRooter tvr(cx, obj);
|
||||
if (!EnsureCapacity(cx, obj, capacity, JS_FALSE))
|
||||
obj = NULL;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user