Bug 548702 - Temporary value-rooting scheme should be C++- and RAII-based, not macro-based. r=igor

This commit is contained in:
Jeff Walden
2010-01-11 11:52:21 -06:00
parent 9a0812f239
commit e1d797671d
50 changed files with 1384 additions and 1389 deletions

View File

@@ -231,7 +231,7 @@ js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
return JS_TRUE;
}
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
AutoValueRooter 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)
{
JSAutoTempValueRooter dval(cx);
AutoValueRooter 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;
}
JSAutoTempIdRooter idr(cx);
AutoIdRooter 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;
}
JSAutoTempIdRooter idr(cx);
AutoIdRooter 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;
}
JSAutoTempIdRooter idr(cx);
AutoIdRooter 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);
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
AutoValueRooter 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,9 +626,6 @@ 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);
@@ -638,32 +635,30 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
newlen = ValueIsLength(cx, vp);
if (JSVAL_IS_NULL(*vp))
return JS_FALSE;
return false;
oldlen = obj->fslots[JSSLOT_ARRAY_LENGTH];
if (oldlen == newlen)
return JS_TRUE;
return true;
if (!IndexToValue(cx, newlen, vp))
return JS_FALSE;
return false;
if (oldlen < newlen) {
obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen;
return JS_TRUE;
return 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 JS_FALSE;
return false;
} else if (oldlen - newlen < (1 << 24)) {
do {
--oldlen;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!DeleteArrayElement(cx, obj, oldlen)) {
return JS_FALSE;
}
if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeleteArrayElement(cx, obj, oldlen))
return false;
} while (oldlen != newlen);
} else {
/*
@@ -673,33 +668,28 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
* correspond to indexes in the half-open range [newlen, oldlen). See
* bug 322135.
*/
iter = JS_NewPropertyIterator(cx, obj);
JSObject *iter = JS_NewPropertyIterator(cx, obj);
if (!iter)
return JS_FALSE;
return false;
/* Protect iter against GC under JSObject::deleteProperty. */
JS_PUSH_TEMP_ROOT_OBJECT(cx, iter, &tvr);
AutoValueRooter tvr(cx, iter);
gap = oldlen - newlen;
for (;;) {
ok = (JS_CHECK_OPERATION_LIMIT(cx) &&
JS_NextProperty(cx, iter, &id));
if (!ok)
break;
if (!JS_CHECK_OPERATION_LIMIT(cx) || !JS_NextProperty(cx, iter, &id))
return false;
if (JSVAL_IS_VOID(id))
break;
if (js_IdIsIndex(id, &index) && index - newlen < gap) {
ok = obj->deleteProperty(cx, id, &junk);
if (!ok)
break;
if (js_IdIsIndex(id, &index) && index - newlen < gap &&
!obj->deleteProperty(cx, id, &junk)) {
return false;
}
}
JS_POP_TEMP_ROOT(cx, &tvr);
if (!ok)
return JS_FALSE;
}
obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen;
return JS_TRUE;
return true;
}
/*
@@ -1518,7 +1508,7 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
return true;
}
JSAutoTempValueRooter tvr(cx, obj);
AutoValueRooter tvr(cx, obj);
/* After this point, all paths exit through the 'out' label. */
MUST_FLOW_THROUGH("out");
@@ -1652,7 +1642,7 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva
#ifdef DEBUG_jwalden
{
/* Verify that overwriteType and writeType were accurate. */
JSAutoTempIdRooter idr(cx, JSVAL_ZERO);
AutoIdRooter idr(cx);
for (jsuint i = 0; i < count; i++) {
JS_ASSERT_IF(vectorType == SourceVectorAllValues, vector[i] != JSVAL_HOLE);
@@ -1718,12 +1708,12 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva
JS_ASSERT(start == MAXINDEX);
jsval tmp[2] = {JSVAL_NULL, JSVAL_NULL};
JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(tmp), tmp);
AutoArrayRooter 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);
JSAutoTempIdRooter idr(cx);
AutoIdRooter idr(cx);
do {
tmp[1] = *vector++;
if (!js_ValueToStringId(cx, tmp[0], idr.addr()) ||
@@ -1769,7 +1759,7 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector,
static JSString* FASTCALL
Array_p_join(JSContext* cx, JSObject* obj, JSString *str)
{
JSAutoTempValueRooter tvr(cx);
AutoValueRooter tvr(cx);
if (!array_toString_sub(cx, obj, JS_FALSE, str, tvr.addr())) {
SetBuiltinError(cx);
return NULL;
@@ -1780,7 +1770,7 @@ Array_p_join(JSContext* cx, JSObject* obj, JSString *str)
static JSString* FASTCALL
Array_p_toString(JSContext* cx, JSObject* obj)
{
JSAutoTempValueRooter tvr(cx);
AutoValueRooter tvr(cx);
if (!array_toString_sub(cx, obj, JS_FALSE, NULL, tvr.addr())) {
SetBuiltinError(cx);
return NULL;
@@ -1852,7 +1842,7 @@ array_reverse(JSContext *cx, uintN argc, jsval *vp)
return JS_TRUE;
}
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
AutoValueRooter tvr(cx);
for (jsuint i = 0, half = len / 2; i < half; i++) {
JSBool hole, hole2;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
@@ -2102,40 +2092,28 @@ JS_STATIC_ASSERT(JSVAL_NULL == 0);
static JSBool
array_sort(JSContext *cx, uintN argc, jsval *vp)
{
jsval *argv, fval, *vec, *mergesort_tmp, v;
JSObject *obj;
CompareArgs ca;
jsval fval;
jsuint len, newlen, i, undefs;
JSTempValueRooter tvr;
JSBool hole;
JSBool ok;
size_t elemsize;
JSString *str;
/*
* 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);
jsval *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 JS_FALSE;
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG);
return false;
}
fval = argv[0]; /* non-default compare function */
} else {
fval = JSVAL_NULL;
}
obj = JS_THIS_OBJECT(cx, vp);
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj || !js_GetLengthProperty(cx, obj, &len))
return JS_FALSE;
return false;
if (len == 0) {
*vp = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
return true;
}
/*
@@ -2145,19 +2123,16 @@ array_sort(JSContext *cx, uintN argc, jsval *vp)
* malloc'd vector.
*/
#if JS_BITS_PER_WORD == 32
if ((size_t)len > ~(size_t)0 / (2 * sizeof(jsval))) {
if (size_t(len) > SIZE_MAX / (2 * sizeof(jsval))) {
js_ReportAllocationOverflow(cx);
return JS_FALSE;
return 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 tvr.count when we know that the property at
* the corresponding index exists and its value must be rooted.
* 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.
*
* In this way when sorting a huge mostly sparse array we will not
* access the tail of vec corresponding to properties that do not
@@ -2165,204 +2140,196 @@ array_sort(JSContext *cx, uintN argc, jsval *vp)
*
* After this point control must flow through label out: to exit.
*/
JS_PUSH_TEMP_ROOT(cx, 0, vec, &tvr);
{
jsval *vec = (jsval *) cx->malloc(2 * size_t(len) * sizeof(jsval));
if (!vec)
return false;
/*
* 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;
struct AutoFreeVector {
AutoFreeVector(JSContext *cx, jsval *&vec) : cx(cx), vec(vec) { }
~AutoFreeVector() {
cx->free(vec);
}
JSContext * const cx;
jsval *&vec;
} free(cx, 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;
AutoArrayRooter tvr(cx, 0, vec);
if (hole)
continue;
/*
* 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 (JSVAL_IS_VOID(vec[newlen])) {
++undefs;
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;
}
/* We know JSVAL_IS_STRING yields 0 or 1, so avoid a branch via &=. */
all_strings &= JSVAL_IS_STRING(vec[newlen]);
if (newlen == 0)
return true; /* The array has only holes and undefs. */
++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) {
/*
* Sort using the default comparator converting all elements to
* strings.
* 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.
*/
if (all_strings) {
elemsize = sizeof(jsval);
} else {
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) {
/*
* 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.
* Sort using the default comparator converting all elements to
* strings.
*/
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_t)0 / (4 * sizeof(jsval))) {
js_ReportAllocationOverflow(cx);
ok = JS_FALSE;
goto out;
}
if (size_t(newlen) > SIZE_MAX / (4 * sizeof(jsval))) {
js_ReportAllocationOverflow(cx);
return false;
}
#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;
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;
/*
* 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;
}
vec[2 * i] = STRING_TO_JSVAL(str);
vec[2 * i + 1] = v;
} while (i != 0);
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;
mergesort_tmp = vec + 2 * newlen;
memset(mergesort_tmp, 0, newlen * 2 * sizeof(jsval));
tvr.changeArray(vec, newlen * 4);
elemsize = 2 * sizeof(jsval);
}
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);
}
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;
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;
LeaveTrace(cx);
LeaveTrace(cx);
ca.context = cx;
ca.fval = fval;
ca.elemroot = js_AllocStack(cx, 2 + 2, &mark);
if (!ca.elemroot) {
ok = JS_FALSE;
goto out;
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;
}
/*
* 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, 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 JS_FALSE;
}
if (!JS_CHECK_OPERATION_LIMIT(cx) || !SetArrayElement(cx, obj, newlen++, JSVAL_VOID))
return 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 JS_TRUE;
return true;
}
/*
@@ -2436,7 +2403,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)
{
JSAutoTempValueRooter tvr(cx, v);
AutoValueRooter tvr(cx, v);
if (obj->isDenseArray()
? array_push1_dense(cx, obj, v, tvr.addr())
: array_push_slowly(cx, obj, 1, tvr.addr(), tvr.addr())) {
@@ -2508,7 +2475,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, jsval *vp)
static jsval FASTCALL
Array_p_pop(JSContext* cx, JSObject* obj)
{
JSAutoTempValueRooter tvr(cx);
AutoValueRooter tvr(cx);
if (obj->isDenseArray()
? array_pop_dense(cx, obj, tvr.addr())
: array_pop_slowly(cx, obj, tvr.addr())) {
@@ -2572,7 +2539,7 @@ array_shift(JSContext *cx, uintN argc, jsval *vp)
return JS_FALSE;
/* Slide down the array above the first element. */
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
AutoValueRooter tvr(cx);
for (i = 0; i != length; i++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, i + 1, &hole, tvr.addr()) ||
@@ -2617,7 +2584,7 @@ array_unshift(JSContext *cx, uintN argc, jsval *vp)
} else {
last = length;
jsdouble upperIndex = last + argc;
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
AutoValueRooter tvr(cx);
do {
--last, --upperIndex;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
@@ -2707,7 +2674,7 @@ array_splice(JSContext *cx, uintN argc, jsval *vp)
argv++;
}
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
AutoValueRooter tvr(cx, JSVAL_NULL);
/* If there are elements to remove, put them into the return value. */
if (count > 0) {
@@ -2846,7 +2813,7 @@ array_concat(JSContext *cx, uintN argc, jsval *vp)
length = 0;
}
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
AutoValueRooter tvr(cx, JSVAL_NULL);
/* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
for (i = 0; i <= argc; i++) {
@@ -2960,7 +2927,7 @@ array_slice(JSContext *cx, uintN argc, jsval *vp)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(nobj);
JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
AutoValueRooter tvr(cx);
for (slot = begin; slot < end; slot++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, slot, &hole, tvr.addr())) {
@@ -3470,10 +3437,7 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
JSObject *
js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey)
{
JSTempValueRooter tvr;
JSObject *obj;
obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
JSObject *obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
if (!obj)
return NULL;
@@ -3483,10 +3447,11 @@ js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey)
*/
JS_ASSERT(obj->getProto());
JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);
if (!InitArrayObject(cx, obj, length, vector, holey))
obj = NULL;
JS_POP_TEMP_ROOT(cx, &tvr);
{
AutoValueRooter tvr(cx, obj);
if (!InitArrayObject(cx, obj, length, vector, holey))
obj = NULL;
}
/* Set/clear newborn root, in case we lost it. */
cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
@@ -3602,7 +3567,7 @@ js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector)
if (!obj)
return NULL;
JSAutoTempValueRooter tvr(cx, obj);
AutoValueRooter tvr(cx, obj);
if (!EnsureCapacity(cx, obj, capacity, JS_FALSE))
obj = NULL;