diff --git a/content/canvas/src/CustomQS_WebGL.h b/content/canvas/src/CustomQS_WebGL.h index abde159d3ff..2d479060e59 100644 --- a/content/canvas/src/CustomQS_WebGL.h +++ b/content/canvas/src/CustomQS_WebGL.h @@ -68,7 +68,7 @@ nsICanvasRenderingContextWebGL_BufferData(JSContext *cx, uintN argc, jsval *vp) nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -134,7 +134,7 @@ nsICanvasRenderingContextWebGL_BufferSubData(JSContext *cx, uintN argc, jsval *v nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -204,7 +204,7 @@ nsICanvasRenderingContextWebGL_TexImage2D(JSContext *cx, uintN argc, jsval *vp) nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -306,7 +306,7 @@ nsICanvasRenderingContextWebGL_TexSubImage2D(JSContext *cx, uintN argc, jsval *v nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -407,7 +407,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv(JSContext *cx, uintN argc, js nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -427,7 +427,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv(JSContext *cx, uintN argc, js JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]); - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -477,7 +477,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv(JSContext *cx, uintN argc, js nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -497,7 +497,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv(JSContext *cx, uintN argc, js JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]); - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -547,7 +547,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv(JSContext *cx, uintN ar nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -571,7 +571,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv(JSContext *cx, uintN ar JSObject *arg2 = JSVAL_TO_OBJECT(argv[2]); - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -618,7 +618,7 @@ helper_nsICanvasRenderingContextWebGL_VertexAttrib_x_fv(JSContext *cx, uintN arg nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; - js::AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) return JS_FALSE; @@ -638,7 +638,7 @@ helper_nsICanvasRenderingContextWebGL_VertexAttrib_x_fv(JSContext *cx, uintN arg JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]); - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -780,7 +780,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(JSContext *cx, JSObject *o return JSVAL_VOID; } - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -835,7 +835,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(JSContext *cx, JSObject *o return JSVAL_VOID; } - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; @@ -890,7 +890,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(JSContext *cx, JSObj return JSVAL_VOID; } - js::AutoValueRooter obj_tvr(cx); + JSAutoTempValueRooter obj_tvr(cx); js::TypedArray *wa = 0; diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 1044d6bccf6..4c1ad2506d5 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2111,13 +2111,14 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler return NS_OK; } - js::AutoValueRooter targetVal(mContext, JSVAL_VOID); + jsval targetVal = JSVAL_VOID; + JSAutoTempValueRooter tvr(mContext, 1, &targetVal); JSObject* target = nsnull; nsresult rv = JSObjectFromInterface(aTarget, aScope, &target); NS_ENSURE_SUCCESS(rv, rv); - targetVal.setObject(target); + targetVal = OBJECT_TO_JSVAL(target); jsval rval = JSVAL_VOID; @@ -2142,7 +2143,7 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler jsval *argv = nsnull; js::LazilyConstructed poolRelease; - js::LazilyConstructed tvr; + js::LazilyConstructed tvr; // Use |target| as the scope for wrapping the arguments, since aScope is // the safe scope in many cases, which isn't very useful. Wrapping aTarget @@ -2654,7 +2655,7 @@ nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArg JSAutoRequest ar(mContext); js::LazilyConstructed poolRelease; - js::LazilyConstructed tvr; + js::LazilyConstructed tvr; nsresult rv; rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, @@ -2689,7 +2690,7 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs, PRUint32 *aArgc, jsval **aArgv, js::LazilyConstructed &aPoolRelease, - js::LazilyConstructed &aRooter) + js::LazilyConstructed &aRooter) { nsresult rv = NS_OK; diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index c7080ae5182..785d53c109e 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -49,11 +49,8 @@ class nsIXPConnectJSObjectHolder; class nsAutoPoolRelease; -namespace js { -class AutoValueRooter; -class AutoArrayRooter; -template class LazilyConstructed; -} +class JSAutoTempValueRooter; +namespace js { template class LazilyConstructed; } class nsJSContext : public nsIScriptContext, public nsIXPCScriptNotify @@ -218,7 +215,7 @@ protected: PRUint32 *aArgc, jsval **aArgv, js::LazilyConstructed &aPoolRelease, - js::LazilyConstructed &aRooter); + js::LazilyConstructed &aRooter); nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv); diff --git a/js/ctypes/Function.cpp b/js/ctypes/Function.cpp index 45e69f43f16..c30efc5cf96 100644 --- a/js/ctypes/Function.cpp +++ b/js/ctypes/Function.cpp @@ -624,7 +624,7 @@ Function::Create(JSContext* aContext, return NULL; JSObject* fnObj = JS_GetFunctionObject(fn); - js::AutoValueRooter fnRoot(aContext, fnObj); + JSAutoTempValueRooter fnRoot(aContext, fnObj); // stash a pointer to self, which Function::Call will need at call time if (!JS_SetReservedSlot(aContext, fnObj, 0, PRIVATE_TO_JSVAL(self.get()))) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index cb697a8bcc1..d47ccec6bce 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -438,7 +438,7 @@ JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp) { CHECK_REQUEST(cx); - AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); *dp = js_ValueToNumber(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -454,7 +454,7 @@ JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip) { CHECK_REQUEST(cx); - AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); *ip = js_ValueToECMAInt32(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -464,7 +464,7 @@ JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip) { CHECK_REQUEST(cx); - AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); *ip = js_ValueToECMAUint32(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -474,7 +474,7 @@ JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip) { CHECK_REQUEST(cx); - AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); *ip = js_ValueToInt32(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -484,7 +484,7 @@ JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip) { CHECK_REQUEST(cx); - AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); *ip = js_ValueToUint16(cx, tvr.addr()); return !JSVAL_IS_NULL(tvr.value()); } @@ -3059,7 +3059,7 @@ LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop, JSScopeProperty *sprop = (JSScopeProperty *) prop; if (sprop->isMethod()) { - AutoScopePropertyRooter root(cx, sprop); + JSAutoTempValueRooter root(cx, sprop); JS_UNLOCK_OBJ(cx, obj2); *vp = sprop->methodValue(); return OBJ_SCOPE(obj2)->methodReadBarrier(cx, sprop, vp); @@ -3810,6 +3810,7 @@ JS_PUBLIC_API(JSIdArray *) JS_Enumerate(JSContext *cx, JSObject *obj) { jsint i, n; + jsval iter_state, num_properties; jsid id; JSIdArray *ida; jsval *vector; @@ -3817,11 +3818,11 @@ JS_Enumerate(JSContext *cx, JSObject *obj) CHECK_REQUEST(cx); ida = NULL; - AutoEnumStateRooter iterState(cx, obj); + iter_state = JSVAL_NULL; + JSAutoEnumStateRooter tvr(cx, obj, &iter_state); /* Get the number of properties to enumerate. */ - jsval num_properties; - if (!obj->enumerate(cx, JSENUMERATE_INIT, iterState.addr(), &num_properties)) + if (!obj->enumerate(cx, JSENUMERATE_INIT, &iter_state, &num_properties)) goto error; if (!JSVAL_IS_INT(num_properties)) { JS_ASSERT(0); @@ -3841,11 +3842,11 @@ JS_Enumerate(JSContext *cx, JSObject *obj) i = 0; vector = &ida->vector[0]; for (;;) { - if (!obj->enumerate(cx, JSENUMERATE_NEXT, iterState.addr(), &id)) + if (!obj->enumerate(cx, JSENUMERATE_NEXT, &iter_state, &id)) goto error; /* No more jsid's to enumerate ? */ - if (iterState.state() == JSVAL_NULL) + if (iter_state == JSVAL_NULL) break; if (i == ida->length) { @@ -3859,6 +3860,8 @@ JS_Enumerate(JSContext *cx, JSObject *obj) return SetIdArrayLength(cx, ida, i); error: + if (!JSVAL_IS_NULL(iter_state)) + obj->enumerate(cx, JSENUMERATE_DESTROY, &iter_state, 0); if (ida) JS_DestroyIdArray(cx, ida); return NULL; @@ -3942,7 +3945,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj) * Note: we have to make sure that we root obj around the call to * JS_Enumerate to protect against multiple allocations under it. */ - AutoValueRooter tvr(cx, iterobj); + JSAutoTempValueRooter tvr(cx, iterobj); ida = JS_Enumerate(cx, obj); if (!ida) return NULL; @@ -4592,6 +4595,7 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, JS_PUBLIC_API(JSObject *) JS_NewScriptObject(JSContext *cx, JSScript *script) { + JSTempValueRooter tvr; JSObject *obj; CHECK_REQUEST(cx); @@ -4600,19 +4604,16 @@ JS_NewScriptObject(JSContext *cx, JSScript *script) JS_ASSERT(!script->u.object); - { - AutoScriptRooter root(cx, script); - - obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); - if (obj) { - obj->setPrivate(script); - script->u.object = obj; + JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr); + obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); + if (obj) { + obj->setPrivate(script); + script->u.object = obj; #ifdef CHECK_SCRIPT_OWNER - script->owner = NULL; + script->owner = NULL; #endif - } } - + JS_POP_TEMP_ROOT(cx, &tvr); return obj; } @@ -4690,6 +4691,7 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, const char *filename, uintN lineno) { JSFunction *fun; + JSTempValueRooter tvr; JSAtom *funAtom, *argAtom; uintN i; @@ -4707,48 +4709,47 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, if (!fun) goto out2; - { - AutoValueRooter tvr(cx, FUN_OBJECT(fun)); - MUST_FLOW_THROUGH("out"); - - for (i = 0; i < nargs; i++) { - argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0); - if (!argAtom) { - fun = NULL; - goto out; - } - if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) { - fun = NULL; - goto out; - } - } - - if (!JSCompiler::compileFunctionBody(cx, fun, principals, - chars, length, filename, lineno)) { + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr); + for (i = 0; i < nargs; i++) { + argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0); + if (!argAtom) { fun = NULL; goto out; } - - if (obj && funAtom && - !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)), - NULL, NULL, JSPROP_ENUMERATE)) { + if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) { fun = NULL; + goto out; } + } + + if (!JSCompiler::compileFunctionBody(cx, fun, principals, + chars, length, filename, lineno)) { + fun = NULL; + goto out; + } + + if (obj && + funAtom && + !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)), + NULL, NULL, JSPROP_ENUMERATE)) { + fun = NULL; + } #ifdef JS_SCOPE_DEPTH_METER - if (fun && obj) { - JSObject *pobj = obj; - uintN depth = 1; + if (fun && obj) { + JSObject *pobj = obj; + uintN depth = 1; - while ((pobj = pobj->getParent()) != NULL) - ++depth; - JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth); - } + while ((pobj = pobj->getParent()) != NULL) + ++depth; + JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth); + } #endif - out: - cx->weakRoots.finalizableNewborns[FINALIZE_FUNCTION] = fun; - } + out: + cx->weakRoots.finalizableNewborns[FINALIZE_FUNCTION] = fun; + JS_POP_TEMP_ROOT(cx, &tvr); out2: LAST_FRAME_CHECKS(cx, fun); @@ -4936,7 +4937,7 @@ JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, { CHECK_REQUEST(cx); - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); JSBool ok = atom && js_GetMethod(cx, obj, ATOM_TO_JSID(atom), diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index d288561df8e..edf0b43348c 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -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; diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 02833fcee67..f96e701acd6 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1161,6 +1161,97 @@ typedef struct JSResolvingEntry { #define JSRESFLAG_LOOKUP 0x1 /* resolving id from lookup */ #define JSRESFLAG_WATCH 0x2 /* resolving id from watch */ + +/* + * Macros to push/pop JSTempValueRooter instances to context-linked stack of + * temporary GC roots. If you need to protect a result value that flows out of + * a C function across several layers of other functions, use the + * js_LeaveLocalRootScopeWithResult internal API (see further below) instead. + * + * The macros also provide a simple way to get a single rooted pointer via + * JS_PUSH_TEMP_ROOT_(cx, NULL, &tvr). Then &tvr.u. gives the + * necessary pointer. + * + * JSTempValueRooter.count defines the type of the rooted value referenced by + * JSTempValueRooter.u union of type JSTempValueUnion. When count is positive + * or zero, u.array points to a vector of jsvals. Otherwise it must be one of + * the following constants: + */ +#define JSTVU_SINGLE (-1) /* u.value or u. is single jsval + or non-JSString GC-thing pointer */ +#define JSTVU_TRACE (-2) /* u.trace is a hook to trace a custom + * structure */ +#define JSTVU_SPROP (-3) /* u.sprop roots property tree node */ +#define JSTVU_WEAK_ROOTS (-4) /* u.weakRoots points to saved weak roots */ +#define JSTVU_COMPILER (-5) /* u.compiler roots JSCompiler* */ +#define JSTVU_SCRIPT (-6) /* u.script roots JSScript* */ +#define JSTVU_ENUMERATOR (-7) /* a pointer to JSTempValueRooter points + to an instance of JSAutoEnumStateRooter + with u.object storing the enumeration + object */ + +/* + * Here single JSTVU_SINGLE covers both jsval and pointers to almost (see note + * below) any GC-thing via reinterpreting the thing as JSVAL_OBJECT. This works + * because the GC-thing is aligned on a 0 mod 8 boundary, and object has the 0 + * jsval tag. So any GC-heap-allocated thing pointer may be tagged as if it + * were an object and untagged, if it's then used only as an opaque pointer + * until discriminated by other means than tag bits. This is how, for example, + * js_GetGCThingTraceKind uses its |thing| parameter -- it consults GC-thing + * flags stored separately from the thing to decide the kind of thing. + * + * Note well that JSStrings may be statically allocated (see the intStringTable + * and unitStringTable static arrays), so this hack does not work for arbitrary + * GC-thing pointers. + */ +#define JS_PUSH_TEMP_ROOT_COMMON(cx,x,tvr,cnt,kind) \ + JS_BEGIN_MACRO \ + JS_ASSERT((cx)->tempValueRooters != (tvr)); \ + (tvr)->count = (cnt); \ + (tvr)->u.kind = (x); \ + (tvr)->down = (cx)->tempValueRooters; \ + (cx)->tempValueRooters = (tvr); \ + JS_END_MACRO + +#define JS_POP_TEMP_ROOT(cx,tvr) \ + JS_BEGIN_MACRO \ + JS_ASSERT((cx)->tempValueRooters == (tvr)); \ + (cx)->tempValueRooters = (tvr)->down; \ + JS_END_MACRO + +#define JS_PUSH_TEMP_ROOT(cx,cnt,arr,tvr) \ + JS_BEGIN_MACRO \ + JS_ASSERT((int)(cnt) >= 0); \ + JS_PUSH_TEMP_ROOT_COMMON(cx, arr, tvr, (ptrdiff_t) (cnt), array); \ + JS_END_MACRO + +#define JS_PUSH_SINGLE_TEMP_ROOT(cx,val,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, val, tvr, JSTVU_SINGLE, value) + +#define JS_PUSH_TEMP_ROOT_OBJECT(cx,obj,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, obj, tvr, JSTVU_SINGLE, object) + +#define JS_PUSH_TEMP_ROOT_STRING(cx,str,tvr) \ + JS_PUSH_SINGLE_TEMP_ROOT(cx, str ? STRING_TO_JSVAL(str) : JSVAL_NULL, tvr) + +#define JS_PUSH_TEMP_ROOT_XML(cx,xml_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, xml_, tvr, JSTVU_SINGLE, xml) + +#define JS_PUSH_TEMP_ROOT_TRACE(cx,trace_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, trace_, tvr, JSTVU_TRACE, trace) + +#define JS_PUSH_TEMP_ROOT_SPROP(cx,sprop_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, sprop_, tvr, JSTVU_SPROP, sprop) + +#define JS_PUSH_TEMP_ROOT_WEAK_COPY(cx,weakRoots_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, weakRoots_, tvr, JSTVU_WEAK_ROOTS, weakRoots) + +#define JS_PUSH_TEMP_ROOT_COMPILER(cx,pc,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, pc, tvr, JSTVU_COMPILER, compiler) + +#define JS_PUSH_TEMP_ROOT_SCRIPT(cx,script_,tvr) \ + JS_PUSH_TEMP_ROOT_COMMON(cx, script_, tvr, JSTVU_SCRIPT, script) + #define JSRESOLVE_INFER 0xffff /* infer bits from current bytecode */ extern const JSDebugHooks js_NullDebugHooks; /* defined in jsdbgapi.cpp */ @@ -1174,10 +1265,6 @@ struct JSGCReachableFrame { JSStackFrame *frame; }; -namespace js { -class AutoGCRooter; -} - struct JSContext { explicit JSContext(JSRuntime *rt) : runtime(rt), busyArrays(this) {} @@ -1379,8 +1466,8 @@ struct JSContext /* PDL of stack headers describing stack slots not rooted by argv, etc. */ JSStackHeader *stackHeaders; - /* Stack of thread-stack-allocated GC roots. */ - js::AutoGCRooter *autoGCRooters; + /* Stack of thread-stack-allocated temporary GC roots. */ + JSTempValueRooter *tempValueRooters; /* Debug hooks associated with the current context. */ const JSDebugHooks *debugHooks; @@ -1617,258 +1704,93 @@ FrameAtomBase(JSContext *cx, JSStackFrame *fp) : fp->script->atomMap.vector; } -namespace js { - -class AutoGCRooter { +/* FIXME(bug 332648): Move this into a public header. */ +class JSAutoTempValueRooter +{ public: - AutoGCRooter(JSContext *cx, ptrdiff_t tag) - : down(cx->autoGCRooters), tag(tag), context(cx) - { - JS_ASSERT(this != cx->autoGCRooters); - cx->autoGCRooters = this; + JSAutoTempValueRooter(JSContext *cx, size_t len, jsval *vec + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_PUSH_TEMP_ROOT(mContext, len, vec, &mTvr); + } + explicit JSAutoTempValueRooter(JSContext *cx, jsval v = JSVAL_NULL + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_PUSH_SINGLE_TEMP_ROOT(mContext, v, &mTvr); + } + JSAutoTempValueRooter(JSContext *cx, JSString *str + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_PUSH_TEMP_ROOT_STRING(mContext, str, &mTvr); + } + JSAutoTempValueRooter(JSContext *cx, JSObject *obj + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_PUSH_TEMP_ROOT_OBJECT(mContext, obj, &mTvr); + } + JSAutoTempValueRooter(JSContext *cx, JSScopeProperty *sprop + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_PUSH_TEMP_ROOT_SPROP(mContext, sprop, &mTvr); } - ~AutoGCRooter() { - JS_ASSERT(this == context->autoGCRooters); - context->autoGCRooters = down; + ~JSAutoTempValueRooter() { + JS_POP_TEMP_ROOT(mContext, &mTvr); } - inline void trace(JSTracer *trc); - - friend void ::js_TraceContext(JSTracer *trc, JSContext *acx); + jsval value() { return mTvr.u.value; } + jsval *addr() { return &mTvr.u.value; } protected: - AutoGCRooter * const down; + JSContext *mContext; - /* - * Discriminates actual subclass of this being used. If non-negative, the - * subclass roots an array of jsvals of the length stored in this field. - * If negative, meaning is indicated by the corresponding value in the enum - * below. Any other negative value indicates some deeper problem such as - * memory corruption. - */ - ptrdiff_t tag; - - JSContext * const context; - - enum { - JSVAL = -1, /* js::AutoValueRooter */ - SPROP = -2, /* JSAutoScopePropertyTreeRooter */ - WEAKROOTS = -3, /* AutoSaveWeakRoots */ - COMPILER = -4, /* JSCompiler */ - SCRIPT = -5, /* JSAutoScriptRooter */ - ENUMERATOR = -6, /* JSAutoEnumStateRooter */ - IDARRAY = -7, /* JSAutoIdArray */ - DESCRIPTORS = -8, /* AutoDescriptorArray */ - NAMESPACES = -9, /* AutoNamespaceArray */ - XML = -10, /* JSAutoXML */ - OBJECT = -11, /* JSAutoObjectRooter */ - ID = -12 /* JSAutoTempIdRooter */ - }; + private: + JSTempValueRooter mTvr; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; -class AutoSaveWeakRoots : private AutoGCRooter +class JSAutoTempIdRooter { public: - explicit AutoSaveWeakRoots(JSContext *cx - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, WEAKROOTS), savedRoots(cx->weakRoots) - { + explicit JSAutoTempIdRooter(JSContext *cx, jsid id = INT_TO_JSID(0) + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_PUSH_SINGLE_TEMP_ROOT(mContext, ID_TO_VALUE(id), &mTvr); } - friend void AutoGCRooter::trace(JSTracer *trc); + ~JSAutoTempIdRooter() { + JS_POP_TEMP_ROOT(mContext, &mTvr); + } + + jsid id() { return (jsid) mTvr.u.value; } + jsid * addr() { return (jsid *) &mTvr.u.value; } private: - JSWeakRoots savedRoots; + JSContext *mContext; + JSTempValueRooter mTvr; JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; -/* FIXME(bug 332648): Move this into a public header. */ -class AutoValueRooter : private AutoGCRooter -{ +class JSAutoIdArray { public: - explicit AutoValueRooter(JSContext *cx, jsval v = JSVAL_NULL - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, JSVAL), val(v) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - AutoValueRooter(JSContext *cx, JSString *str - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, JSVAL), val(STRING_TO_JSVAL(str)) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - AutoValueRooter(JSContext *cx, JSObject *obj - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, JSVAL), val(OBJECT_TO_JSVAL(obj)) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - - void setObject(JSObject *obj) { - JS_ASSERT(tag == JSVAL); - val = OBJECT_TO_JSVAL(obj); - } - - void setString(JSString *str) { - JS_ASSERT(tag == JSVAL); - JS_ASSERT(str); - val = STRING_TO_JSVAL(str); - } - - void setDouble(jsdouble *dp) { - JS_ASSERT(tag == JSVAL); - JS_ASSERT(dp); - val = DOUBLE_TO_JSVAL(dp); - } - - jsval value() const { - JS_ASSERT(tag == JSVAL); - return val; - } - - jsval *addr() { - JS_ASSERT(tag == JSVAL); - return &val; - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - jsval val; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class AutoObjectRooter : private AutoGCRooter { - public: - AutoObjectRooter(JSContext *cx, JSObject *obj = NULL - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, OBJECT), obj(obj) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - - void setObject(JSObject *obj) { - this->obj = obj; - } - - JSObject * object() const { - return obj; - } - - JSObject ** addr() { - return &obj; - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - JSObject *obj; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class AutoArrayRooter : private AutoGCRooter { - public: - AutoArrayRooter(JSContext *cx, size_t len, jsval *vec - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, len), array(vec) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - JS_ASSERT(tag >= 0); - } - - void changeLength(size_t newLength) { - tag = ptrdiff_t(newLength); - JS_ASSERT(tag >= 0); - } - - void changeArray(jsval *newArray, size_t newLength) { - changeLength(newLength); - array = newArray; - } - - jsval *array; - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class AutoScopePropertyRooter : private AutoGCRooter { - public: - AutoScopePropertyRooter(JSContext *cx, JSScopeProperty *sprop - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, SPROP), sprop(sprop) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - JSScopeProperty * const sprop; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class AutoScriptRooter : private AutoGCRooter { - public: - AutoScriptRooter(JSContext *cx, JSScript *script - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, SCRIPT), script(script) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - - void setScript(JSScript *script) { - this->script = script; - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - JSScript *script; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class AutoIdRooter : private AutoGCRooter -{ - public: - explicit AutoIdRooter(JSContext *cx, jsid id = INT_TO_JSID(0) - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, ID), idval(id) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - - jsid id() { - return idval; - } - - jsid * addr() { - return &idval; - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - jsid idval; - JS_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class AutoIdArray : private AutoGCRooter { - public: - AutoIdArray(JSContext *cx, JSIdArray *ida + JSAutoIdArray(JSContext *cx, JSIdArray *ida JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, ida ? ida->length : 0), idArray(ida) - { + : cx(cx), idArray(ida) { JS_GUARD_OBJECT_NOTIFIER_INIT; + if (ida) + JS_PUSH_TEMP_ROOT(cx, ida->length, ida->vector, &tvr); } - ~AutoIdArray() { - if (idArray) - JS_DestroyIdArray(context, idArray); + ~JSAutoIdArray() { + if (idArray) { + JS_POP_TEMP_ROOT(cx, &tvr); + JS_DestroyIdArray(cx, idArray); + } } bool operator!() { return idArray == NULL; @@ -1881,86 +1803,52 @@ class AutoIdArray : private AutoGCRooter { size_t length() const { return idArray->length; } - - friend void AutoGCRooter::trace(JSTracer *trc); - - protected: - inline void trace(JSTracer *trc); - private: + JSContext * const cx; JSIdArray * const idArray; + JSTempValueRooter tvr; JS_DECL_USE_GUARD_OBJECT_NOTIFIER /* No copy or assignment semantics. */ - AutoIdArray(AutoIdArray &ida); - void operator=(AutoIdArray &ida); + JSAutoIdArray(JSAutoIdArray &); + void operator=(JSAutoIdArray &); }; /* The auto-root for enumeration object and its state. */ -class AutoEnumStateRooter : private AutoGCRooter +class JSAutoEnumStateRooter : public JSTempValueRooter { public: - AutoEnumStateRooter(JSContext *cx, JSObject *obj - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, ENUMERATOR), obj(obj), stateValue(JSVAL_NULL) + JSAutoEnumStateRooter(JSContext *cx, JSObject *obj, jsval *statep + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx), mStatep(statep) { JS_GUARD_OBJECT_NOTIFIER_INIT; JS_ASSERT(obj); + JS_ASSERT(statep); + JS_PUSH_TEMP_ROOT_COMMON(cx, obj, this, JSTVU_ENUMERATOR, object); } - ~AutoEnumStateRooter() { - if (!JSVAL_IS_NULL(stateValue)) { -#ifdef DEBUG - JSBool ok = -#endif - obj->enumerate(context, JSENUMERATE_DESTROY, &stateValue, 0); - JS_ASSERT(ok); - } + ~JSAutoEnumStateRooter() { + JS_POP_TEMP_ROOT(mContext, this); } - friend void AutoGCRooter::trace(JSTracer *trc); - - jsval state() const { return stateValue; } - jsval * addr() { return &stateValue; } - - protected: - void trace(JSTracer *trc) { - JS_CALL_OBJECT_TRACER(trc, obj, "js::AutoEnumStateRooter.obj"); - js_MarkEnumeratorState(trc, obj, stateValue); + void mark(JSTracer *trc) { + JS_CALL_OBJECT_TRACER(trc, u.object, "enumerator_obj"); + js_MarkEnumeratorState(trc, u.object, *mStatep); } - JSObject * const obj; - private: - jsval stateValue; + JSContext *mContext; + jsval *mStatep; JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; -#ifdef JS_HAS_XML_SUPPORT -class AutoXMLRooter : private AutoGCRooter { - public: - AutoXMLRooter(JSContext *cx, JSXML *xml) - : AutoGCRooter(cx, XML), xml(xml) - { - JS_ASSERT(xml); - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - JSXML * const xml; -}; -#endif /* JS_HAS_XML_SUPPORT */ - -} - class JSAutoResolveFlags { public: JSAutoResolveFlags(JSContext *cx, uintN flags JS_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx), mSaved(cx->resolveFlags) - { + : mContext(cx), mSaved(cx->resolveFlags) { JS_GUARD_OBJECT_NOTIFIER_INIT; cx->resolveFlags = flags; } diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h deleted file mode 100644 index ca28d7682f2..00000000000 --- a/js/src/jscntxtinlines.h +++ /dev/null @@ -1,147 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is SpiderMonkey code. - * - * The Initial Developer of the Original Code is - * Mozilla Corporation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Jeff Walden (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef jscntxtinlines_h___ -#define jscntxtinlines_h___ - -#include "jscntxt.h" -#include "jsxml.h" - -#include "jsobjinlines.h" - -namespace js { - -void -AutoIdArray::trace(JSTracer *trc) { - JS_ASSERT(tag == IDARRAY); - js::TraceValues(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray"); -} - -class AutoNamespaces : protected AutoGCRooter { - protected: - AutoNamespaces(JSContext *cx) : AutoGCRooter(cx, NAMESPACES) { - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - public: - JSXMLArray array; -}; - -inline void -AutoGCRooter::trace(JSTracer *trc) -{ - switch (tag) { - case JSVAL: - JS_SET_TRACING_NAME(trc, "js::AutoValueRooter.val"); - js_CallValueTracerIfGCThing(trc, static_cast(this)->val); - return; - - case SPROP: - static_cast(this)->sprop->trace(trc); - return; - - case WEAKROOTS: - static_cast(this)->savedRoots.mark(trc); - return; - - case COMPILER: - static_cast(this)->trace(trc); - return; - - case SCRIPT: - if (JSScript *script = static_cast(this)->script) - js_TraceScript(trc, script); - return; - - case ENUMERATOR: - static_cast(this)->trace(trc); - return; - - case IDARRAY: { - JSIdArray *ida = static_cast(this)->idArray; - TraceValues(trc, ida->length, ida->vector, "js::AutoIdArray.idArray"); - return; - } - - case DESCRIPTORS: { - PropertyDescriptorArray &descriptors = - static_cast(this)->descriptors; - for (size_t i = 0, len = descriptors.length(); i < len; i++) { - PropertyDescriptor &desc = descriptors[i]; - - JS_CALL_VALUE_TRACER(trc, desc.value, "PropertyDescriptor::value"); - JS_CALL_VALUE_TRACER(trc, desc.get, "PropertyDescriptor::get"); - JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set"); - js_TraceId(trc, desc.id); - } - return; - } - - case NAMESPACES: { - JSXMLArray &array = static_cast(this)->array; - TraceObjectVector(trc, reinterpret_cast(array.vector), array.length); - array.cursors->trace(trc); - return; - } - - case XML: - js_TraceXML(trc, static_cast(this)->xml); - return; - - case OBJECT: - if (JSObject *obj = static_cast(this)->obj) { - JS_SET_TRACING_NAME(trc, "js::AutoObjectRooter.obj"); - js_CallGCMarker(trc, obj, JSTRACE_OBJECT); - } - return; - - case ID: - JS_SET_TRACING_NAME(trc, "js::AutoIdRooter.val"); - js_CallValueTracerIfGCThing(trc, static_cast(this)->idval); - return; - } - - JS_ASSERT(tag >= 0); - TraceValues(trc, tag, static_cast(this)->array, "js::AutoArrayRooter.array"); -} - -} - -#endif /* jscntxtinlines_h___ */ diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 05ba1230a0e..a964851f364 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -1465,8 +1465,8 @@ JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, { pd->id = ID_TO_VALUE(sprop->id); - bool wasThrowing = cx->throwing; - AutoValueRooter lastException(cx, cx->exception); + JSBool wasThrowing = cx->throwing; + JSAutoTempValueRooter lastException(cx, cx->exception); cx->throwing = JS_FALSE; if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) { diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index fea99f3133f..670efd3196a 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -63,8 +63,6 @@ #include "jsscript.h" #include "jsstaticcheck.h" -using namespace js; - /* Forward declarations for js_ErrorClass's initializer. */ static JSBool Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); @@ -826,119 +824,131 @@ exn_toSource(JSContext *cx, uintN argc, jsval *vp) JSObject *obj; JSString *name, *message, *filename, *lineno_as_str, *result; jsval localroots[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; + JSTempValueRooter tvr; + JSBool ok; uint32 lineno; size_t lineno_length, name_length, message_length, filename_length, length; jschar *chars, *cp; obj = JS_THIS_OBJECT(cx, vp); if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), vp)) - return false; + return JS_FALSE; name = js_ValueToString(cx, *vp); if (!name) - return false; + return JS_FALSE; *vp = STRING_TO_JSVAL(name); - { - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroots), localroots); + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT(cx, 3, localroots, &tvr); #ifdef __GNUC__ - message = filename = NULL; + message = filename = NULL; #endif - if (!JS_GetProperty(cx, obj, js_message_str, &localroots[0]) || - !(message = js_ValueToSource(cx, localroots[0]))) { - return false; + ok = JS_GetProperty(cx, obj, js_message_str, &localroots[0]) && + (message = js_ValueToSource(cx, localroots[0])); + if (!ok) + goto out; + localroots[0] = STRING_TO_JSVAL(message); + + ok = JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) && + (filename = js_ValueToSource(cx, localroots[1])); + if (!ok) + goto out; + localroots[1] = STRING_TO_JSVAL(filename); + + ok = JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2]); + if (!ok) + goto out; + lineno = js_ValueToECMAUint32 (cx, &localroots[2]); + ok = !JSVAL_IS_NULL(localroots[2]); + if (!ok) + goto out; + + if (lineno != 0) { + lineno_as_str = js_ValueToString(cx, localroots[2]); + if (!lineno_as_str) { + ok = JS_FALSE; + goto out; } - localroots[0] = STRING_TO_JSVAL(message); + lineno_length = lineno_as_str->length(); + } else { + lineno_as_str = NULL; + lineno_length = 0; + } - if (!JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) || - !(filename = js_ValueToSource(cx, localroots[1]))) { - return false; - } - localroots[1] = STRING_TO_JSVAL(filename); + /* Magic 8, for the characters in ``(new ())''. */ + name_length = name->length(); + message_length = message->length(); + length = 8 + name_length + message_length; - if (!JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2])) - return false; - lineno = js_ValueToECMAUint32 (cx, &localroots[2]); - if (JSVAL_IS_NULL(localroots[2])) - return false; - - if (lineno != 0) { - lineno_as_str = js_ValueToString(cx, localroots[2]); - if (!lineno_as_str) - return false; - lineno_length = lineno_as_str->length(); - } else { - lineno_as_str = NULL; - lineno_length = 0; - } - - /* Magic 8, for the characters in ``(new ())''. */ - name_length = name->length(); - message_length = message->length(); - length = 8 + name_length + message_length; - - filename_length = filename->length(); - if (filename_length != 0) { - /* append filename as ``, {filename}'' */ - length += 2 + filename_length; - if (lineno_as_str) { - /* append lineno as ``, {lineno_as_str}'' */ - length += 2 + lineno_length; - } - } else { - if (lineno_as_str) { - /* - * no filename, but have line number, - * need to append ``, "", {lineno_as_str}'' - */ - length += 6 + lineno_length; - } - } - - cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar)); - if (!chars) - return false; - - *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' '; - js_strncpy(cp, name->chars(), name_length); - cp += name_length; - *cp++ = '('; - if (message_length != 0) { - js_strncpy(cp, message->chars(), message_length); - cp += message_length; - } - - if (filename_length != 0) { - /* append filename as ``, {filename}'' */ - *cp++ = ','; *cp++ = ' '; - js_strncpy(cp, filename->chars(), filename_length); - cp += filename_length; - } else { - if (lineno_as_str) { - /* - * no filename, but have line number, - * need to append ``, "", {lineno_as_str}'' - */ - *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"'; - } - } + filename_length = filename->length(); + if (filename_length != 0) { + /* append filename as ``, {filename}'' */ + length += 2 + filename_length; if (lineno_as_str) { /* append lineno as ``, {lineno_as_str}'' */ - *cp++ = ','; *cp++ = ' '; - js_strncpy(cp, lineno_as_str->chars(), lineno_length); - cp += lineno_length; + length += 2 + lineno_length; } - - *cp++ = ')'; *cp++ = ')'; *cp = 0; - - result = js_NewString(cx, chars, length); - if (!result) { - cx->free(chars); - return false; + } else { + if (lineno_as_str) { + /* + * no filename, but have line number, + * need to append ``, "", {lineno_as_str}'' + */ + length += 6 + lineno_length; } - *vp = STRING_TO_JSVAL(result); - return true; } + + cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar)); + if (!chars) { + ok = JS_FALSE; + goto out; + } + + *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' '; + js_strncpy(cp, name->chars(), name_length); + cp += name_length; + *cp++ = '('; + if (message_length != 0) { + js_strncpy(cp, message->chars(), message_length); + cp += message_length; + } + + if (filename_length != 0) { + /* append filename as ``, {filename}'' */ + *cp++ = ','; *cp++ = ' '; + js_strncpy(cp, filename->chars(), filename_length); + cp += filename_length; + } else { + if (lineno_as_str) { + /* + * no filename, but have line number, + * need to append ``, "", {lineno_as_str}'' + */ + *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"'; + } + } + if (lineno_as_str) { + /* append lineno as ``, {lineno_as_str}'' */ + *cp++ = ','; *cp++ = ' '; + js_strncpy(cp, lineno_as_str->chars(), lineno_length); + cp += lineno_length; + } + + *cp++ = ')'; *cp++ = ')'; *cp = 0; + + result = js_NewString(cx, chars, length); + if (!result) { + cx->free(chars); + ok = JS_FALSE; + goto out; + } + *vp = STRING_TO_JSVAL(result); + ok = JS_TRUE; + +out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; } #endif @@ -989,7 +999,7 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj) return NULL; memset(roots, 0, sizeof(roots)); - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); #ifdef __GNUC__ error_proto = NULL; /* quell GCC overwarning */ @@ -1099,6 +1109,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, const JSErrorFormatString *errorString; JSExnType exn; jsval tv[4]; + JSTempValueRooter tvr; JSBool ok; JSObject *errProto, *errObject; JSString *messageStr, *filenameStr; @@ -1147,7 +1158,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, /* Protect the newly-created strings below from nesting GCs. */ memset(tv, 0, sizeof tv); - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tv), tv); + JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(tv), tv, &tvr); /* * Try to get an appropriate prototype by looking up the corresponding @@ -1191,6 +1202,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, reportp->flags |= JSREPORT_EXCEPTION; out: + JS_POP_TEMP_ROOT(cx, &tvr); cx->generatingError = JS_FALSE; return ok; } @@ -1201,18 +1213,20 @@ js_ReportUncaughtException(JSContext *cx) jsval exn; JSObject *exnObject; jsval roots[5]; + JSTempValueRooter tvr; JSErrorReport *reportp, report; JSString *str; const char *bytes; + JSBool ok; if (!JS_IsExceptionPending(cx)) - return true; + return JS_TRUE; if (!JS_GetPendingException(cx, &exn)) - return false; + return JS_FALSE; memset(roots, 0, sizeof roots); - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr); /* * Because js_ValueToString below could error and an exception object @@ -1237,36 +1251,51 @@ js_ReportUncaughtException(JSContext *cx) } else { roots[1] = STRING_TO_JSVAL(str); bytes = js_GetStringBytes(cx, str); - if (!bytes) - return false; + if (!bytes) { + ok = JS_FALSE; + goto out; + } } + ok = JS_TRUE; - if (!reportp && exnObject && OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) { + if (!reportp && + exnObject && + OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) { const char *filename; uint32 lineno; - if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2])) - return false; + ok = JS_GetProperty(cx, exnObject, js_message_str, &roots[2]); + if (!ok) + goto out; if (JSVAL_IS_STRING(roots[2])) { bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2])); - if (!bytes) - return false; + if (!bytes) { + ok = JS_FALSE; + goto out; + } } - if (!JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3])) - return false; + ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]); + if (!ok) + goto out; str = js_ValueToString(cx, roots[3]); - if (!str) - return false; + if (!str) { + ok = JS_FALSE; + goto out; + } filename = StringToFilename(cx, str); - if (!filename) - return false; + if (!filename) { + ok = JS_FALSE; + goto out; + } - if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4])) - return false; + ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]); + if (!ok) + goto out; lineno = js_ValueToECMAUint32 (cx, &roots[4]); - if (JSVAL_IS_NULL(roots[4])) - return false; + ok = !JSVAL_IS_NULL(roots[4]); + if (!ok) + goto out; reportp = &report; memset(&report, 0, sizeof report); @@ -1287,5 +1316,7 @@ js_ReportUncaughtException(JSContext *cx) JS_ClearPendingException(cx); } - return true; +out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; } diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index ccd61484a10..d4c0cefc077 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -351,7 +351,7 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSObject *funobj, JSFunctio funobj, scopeChain); if (!wfunobj) return NULL; - AutoValueRooter tvr(cx, wfunobj); + JSAutoTempValueRooter tvr(cx, wfunobj); JSFunction *wfun = (JSFunction *) wfunobj; wfunobj->setPrivate(wfun); @@ -599,7 +599,7 @@ ArgSetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) if (!JS_ValueToId(cx, idval, &id)) return false; - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); return js_DeleteProperty(cx, obj, id, tvr.addr()) && js_SetProperty(cx, obj, id, vp); } @@ -1584,6 +1584,8 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) uintN nargs, nvars, nupvars, n; uint32 localsword; /* word for argument and variable counts */ uint32 flagsword; /* word for fun->u.i.nupvars and fun->flags */ + JSTempValueRooter tvr; + JSBool ok; cx = xdr->cx; if (xdr->mode == JSXDR_ENCODE) { @@ -1592,13 +1594,13 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION, JS_GetFunctionName(fun)); - return false; + return JS_FALSE; } if (fun->u.i.wrapper) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XDR_CLOSURE_WRAPPER, JS_GetFunctionName(fun)); - return false; + return JS_FALSE; } JS_ASSERT((fun->u.i.wrapper & ~1U) == 0); firstword = (fun->u.i.skipmin << 2) | (fun->u.i.wrapper << 1) | !!fun->atom; @@ -1610,7 +1612,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) } else { fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL); if (!fun) - return false; + return JS_FALSE; FUN_OBJECT(fun)->clearParent(); FUN_OBJECT(fun)->clearProto(); #ifdef __GNUC__ @@ -1618,15 +1620,18 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) #endif } - AutoValueRooter tvr(cx, FUN_OBJECT(fun)); + /* From here on, control flow must flow through label out. */ + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr); + ok = JS_TRUE; if (!JS_XDRUint32(xdr, &firstword)) - return false; + goto bad; if ((firstword & 1U) && !js_XDRStringAtom(xdr, &fun->atom)) - return false; + goto bad; if (!JS_XDRUint32(xdr, &localsword) || !JS_XDRUint32(xdr, &flagsword)) { - return false; + goto bad; } if (xdr->mode == JSXDR_DECODE) { @@ -1650,7 +1655,6 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) JSAtom *name; JSLocalKind localKind; - bool ok = true; mark = JS_ARENA_MARK(&xdr->cx->tempPool); /* @@ -1669,13 +1673,13 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) bitmapLength * sizeof *bitmap); if (!bitmap) { js_ReportOutOfScriptQuota(xdr->cx); - ok = false; + ok = JS_FALSE; goto release_mark; } if (xdr->mode == JSXDR_ENCODE) { names = js_GetLocalNameArray(xdr->cx, fun, &xdr->cx->tempPool); if (!names) { - ok = false; + ok = JS_FALSE; goto release_mark; } memset(bitmap, 0, bitmapLength * sizeof *bitmap); @@ -1730,18 +1734,19 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) goto release_mark; } } + ok = JS_TRUE; release_mark: JS_ARENA_RELEASE(&xdr->cx->tempPool, mark); if (!ok) - return false; + goto out; if (xdr->mode == JSXDR_DECODE) js_FreezeLocalNames(cx, fun); } if (!js_XDRScript(xdr, &fun->u.i.script, false, NULL)) - return false; + goto bad; if (xdr->mode == JSXDR_DECODE) { *objp = FUN_OBJECT(fun); @@ -1753,7 +1758,13 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) } } - return true; +out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; + +bad: + ok = JS_FALSE; + goto out; } #else /* !JS_HAS_XDR */ @@ -2670,26 +2681,26 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) JSStackFrame *fp; uintN error; const char *name, *source; + JSTempValueRooter tvr; for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down) continue; name = source = NULL; - - AutoValueRooter tvr(cx); + JS_PUSH_TEMP_ROOT_STRING(cx, NULL, &tvr); if (flags & JSV2F_ITERATOR) { error = JSMSG_BAD_ITERATOR; name = js_iterator_str; JSString *src = js_ValueToSource(cx, *vp); if (!src) - return; - tvr.setString(src); + goto out; + tvr.u.value = STRING_TO_JSVAL(src); JSString *qsrc = js_QuoteString(cx, src, 0); if (!qsrc) - return; - tvr.setString(qsrc); + goto out; + tvr.u.value = STRING_TO_JSVAL(qsrc); source = js_GetStringBytes(cx, qsrc); if (!source) - return; + goto out; } else if (flags & JSV2F_CONSTRUCT) { error = JSMSG_NOT_CONSTRUCTOR; } else { @@ -2705,6 +2716,9 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) : JSDVG_IGNORE_STACK, *vp, NULL, name, source); + + out: + JS_POP_TEMP_ROOT(cx, &tvr); } /* diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index f604570d8d4..422260b931f 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -87,7 +87,6 @@ #include "jsdtracef.h" #endif -#include "jscntxtinlines.h" #include "jsobjinlines.h" /* @@ -110,6 +109,14 @@ using namespace js; +/* + * Check JSTempValueUnion has the size of jsval and void * so we can + * reinterpret jsval as void* GC-thing pointer and use JSTVU_SINGLE for + * different GC-things. + */ +JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(jsval)); +JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(void *)); + /* * Check that JSTRACE_XML follows JSTRACE_OBJECT, JSTRACE_DOUBLE and * JSTRACE_STRING. @@ -2252,20 +2259,19 @@ gc_lock_traversal(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, return JS_DHASH_NEXT; } -namespace js { - -void -TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len) -{ - for (uint32 i = 0; i < len; i++) { - if (JSObject *obj = vec[i]) { - JS_SET_TRACING_INDEX(trc, "vector", i); - js_CallGCMarker(trc, obj, JSTRACE_OBJECT); - } - } -} - -} +#define TRACE_JSVALS(trc, len, vec, name) \ + JS_BEGIN_MACRO \ + jsval _v, *_vp, *_end; \ + \ + for (_vp = vec, _end = _vp + len; _vp < _end; _vp++) { \ + _v = *_vp; \ + if (JSVAL_IS_TRACEABLE(_v)) { \ + JS_SET_TRACING_INDEX(trc, name, _vp - (vec)); \ + js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(_v), \ + JSVAL_TRACE_KIND(_v)); \ + } \ + } \ + JS_END_MACRO void js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) @@ -2291,7 +2297,7 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) } else { nslots = fp->script->nfixed; } - js::TraceValues(trc, nslots, fp->slots, "slot"); + TRACE_JSVALS(trc, nslots, fp->slots, "slot"); } } else { JS_ASSERT(!fp->slots); @@ -2316,7 +2322,7 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) if (fp->fun->flags & JSFRAME_ROOTED_ARGV) skip = 2 + fp->argc; } - js::TraceValues(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand"); + TRACE_JSVALS(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand"); } JS_CALL_VALUE_TRACER(trc, fp->rval, "rval"); @@ -2371,6 +2377,7 @@ JS_REQUIRES_STACK JS_FRIEND_API(void) js_TraceContext(JSTracer *trc, JSContext *acx) { JSStackHeader *sh; + JSTempValueRooter *tvr; /* * Trace active and suspended callstacks. @@ -2420,11 +2427,38 @@ js_TraceContext(JSTracer *trc, JSContext *acx) for (sh = acx->stackHeaders; sh; sh = sh->down) { METER(trc->context->runtime->gcStats.stackseg++); METER(trc->context->runtime->gcStats.segslots += sh->nslots); - js::TraceValues(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack"); + TRACE_JSVALS(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack"); } - for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down) - gcr->trace(trc); + for (tvr = acx->tempValueRooters; tvr; tvr = tvr->down) { + switch (tvr->count) { + case JSTVU_SINGLE: + JS_SET_TRACING_NAME(trc, "tvr->u.value"); + js_CallValueTracerIfGCThing(trc, tvr->u.value); + break; + case JSTVU_TRACE: + tvr->u.trace(trc, tvr); + break; + case JSTVU_SPROP: + tvr->u.sprop->trace(trc); + break; + case JSTVU_WEAK_ROOTS: + tvr->u.weakRoots->mark(trc); + break; + case JSTVU_COMPILER: + tvr->u.compiler->trace(trc); + break; + case JSTVU_SCRIPT: + js_TraceScript(trc, tvr->u.script); + break; + case JSTVU_ENUMERATOR: + static_cast(tvr)->mark(trc); + break; + default: + JS_ASSERT(tvr->count >= 0); + TRACE_JSVALS(trc, tvr->count, tvr->u.array, "tvr->u.array"); + } + } if (acx->sharpObjectMap.depth > 0) js_TraceSharpMap(trc, &acx->sharpObjectMap); @@ -2435,7 +2469,7 @@ js_TraceContext(JSTracer *trc, JSContext *acx) InterpState* state = acx->interpState; while (state) { if (state->nativeVp) - js::TraceValues(trc, state->nativeVpLen, state->nativeVp, "nativeVp"); + TRACE_JSVALS(trc, state->nativeVpLen, state->nativeVp, "nativeVp"); state = state->prev; } #endif @@ -3331,30 +3365,33 @@ out: * interlock mechanism here. */ if (gckind != GC_SET_SLOT_REQUEST && (callback = rt->gcCallback)) { - if (!(gckind & GC_KEEP_ATOMS)) { - (void) callback(cx, JSGC_END); + JSWeakRoots savedWeakRoots; + JSTempValueRooter tvr; - /* - * On shutdown iterate until JSGC_END callback stops creating - * garbage. - */ - if (gckind == GC_LAST_CONTEXT && rt->gcPoke) - goto restart_at_beginning; - } else { + if (gckind & GC_KEEP_ATOMS) { /* * We allow JSGC_END implementation to force a full GC or allocate * new GC things. Thus we must protect the weak roots from garbage * collection and overwrites. */ - AutoSaveWeakRoots save(cx); - + savedWeakRoots = cx->weakRoots; + JS_PUSH_TEMP_ROOT_WEAK_COPY(cx, &savedWeakRoots, &tvr); JS_KEEP_ATOMS(rt); JS_UNLOCK_GC(rt); + } - (void) callback(cx, JSGC_END); + (void) callback(cx, JSGC_END); + if (gckind & GC_KEEP_ATOMS) { JS_LOCK_GC(rt); JS_UNKEEP_ATOMS(rt); + JS_POP_TEMP_ROOT(cx, &tvr); + } else if (gckind == GC_LAST_CONTEXT && rt->gcPoke) { + /* + * On shutdown iterate until JSGC_END callback stops creating + * garbage. + */ + goto restart_at_beginning; } } } diff --git a/js/src/jsgc.h b/js/src/jsgc.h index dbf645feeb2..058dafdb49c 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -454,23 +454,4 @@ js_MarkTraps(JSTracer *trc); JS_END_EXTERN_C -namespace js { - -void -TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len); - -inline void -TraceValues(JSTracer *trc, size_t len, jsval *vec, const char *name) -{ - for (jsval *vp = vec, *end = vp + len; vp < end; vp++) { - jsval v = *vp; - if (JSVAL_IS_TRACEABLE(v)) { - JS_SET_TRACING_INDEX(trc, name, vp - vec); - js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); - } - } -} - -} - #endif /* jsgc_h___ */ diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 72cc90bf21d..19115c6b2a0 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -800,7 +800,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp) JSObject *innermostNewChild = js_CloneBlockObject(cx, sharedBlock, fp); if (!innermostNewChild) return NULL; - AutoValueRooter tvr(cx, innermostNewChild); + JSAutoTempValueRooter tvr(cx, innermostNewChild); /* * Clone our way towards outer scopes until we reach the innermost @@ -1005,7 +1005,7 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp) JSObject *obj = JSVAL_TO_OBJECT(vp[1]); jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom); - AutoValueRooter tvr(cx, JSVAL_NULL); + JSAutoTempValueRooter tvr(cx, JSVAL_NULL); if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, tvr.addr())) return false; if (JSVAL_IS_PRIMITIVE(tvr.value())) { diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 619f895274a..eaa3c872cd6 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -215,11 +215,18 @@ Iterator(JSContext *cx, JSObject *iterobj, uintN argc, jsval *argv, jsval *rval) static JSBool NewKeyValuePair(JSContext *cx, jsid key, jsval val, jsval *rval) { - jsval vec[2] = { ID_TO_VALUE(key), val }; - AutoArrayRooter tvr(cx, 2, vec); + jsval vec[2]; + JSTempValueRooter tvr; + JSObject *aobj; - JSObject *aobj = js_NewArrayObject(cx, 2, vec); + vec[0] = ID_TO_VALUE(key); + vec[1] = val; + + JS_PUSH_TEMP_ROOT(cx, 2, vec, &tvr); + aobj = js_NewArrayObject(cx, 2, vec); *rval = OBJECT_TO_JSVAL(aobj); + JS_POP_TEMP_ROOT(cx, &tvr); + return aobj != NULL; } @@ -340,19 +347,21 @@ JS_FRIEND_API(JSBool) js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) { JSObject *obj; + JSTempValueRooter tvr; JSAtom *atom; JSClass *clasp; JSExtendedClass *xclasp; + JSBool ok; JSObject *iterobj; jsval arg; - JS_ASSERT(!(flags & ~(JSITER_ENUMERATE | JSITER_FOREACH | JSITER_KEYVALUE))); + JS_ASSERT(!(flags & ~(JSITER_ENUMERATE | + JSITER_FOREACH | + JSITER_KEYVALUE))); /* JSITER_KEYVALUE must always come with JSITER_FOREACH */ JS_ASSERT(!(flags & JSITER_KEYVALUE) || (flags & JSITER_FOREACH)); - AutoValueRooter tvr(cx); - /* XXX work around old valueOf call hidden beneath js_ValueToObject */ if (!JSVAL_IS_PRIMITIVE(*vp)) { obj = JSVAL_TO_OBJECT(*vp); @@ -365,29 +374,30 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) */ if ((flags & JSITER_ENUMERATE)) { if (!js_ValueToObject(cx, *vp, &obj)) - return false; + return JS_FALSE; if (!obj) goto default_iter; } else { obj = js_ValueToNonNullObject(cx, *vp); if (!obj) - return false; + return JS_FALSE; } } - tvr.setObject(obj); + JS_ASSERT(obj); + JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr); clasp = OBJ_GET_CLASS(cx, obj); if ((clasp->flags & JSCLASS_IS_EXTENDED) && (xclasp = (JSExtendedClass *) clasp)->iteratorObject) { iterobj = xclasp->iteratorObject(cx, obj, !(flags & JSITER_FOREACH)); if (!iterobj) - return false; + goto bad; *vp = OBJECT_TO_JSVAL(iterobj); } else { atom = cx->runtime->atomState.iteratorAtom; if (!js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, vp)) - return false; + goto bad; if (JSVAL_IS_VOID(*vp)) { default_iter: /* @@ -400,29 +410,36 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) */ iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL); if (!iterobj) - return false; + goto bad; /* Store in *vp to protect it from GC (callers must root vp). */ *vp = OBJECT_TO_JSVAL(iterobj); if (!InitNativeIterator(cx, iterobj, obj, flags)) - return false; + goto bad; } else { LeaveTrace(cx); arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0); if (!js_InternalInvoke(cx, obj, *vp, JSINVOKE_ITERATOR, 1, &arg, vp)) { - return false; + goto bad; } if (JSVAL_IS_PRIMITIVE(*vp)) { js_ReportValueError(cx, JSMSG_BAD_ITERATOR_RETURN, JSDVG_SEARCH_STACK, *vp, NULL); - return false; + goto bad; } } } - return true; + ok = JS_TRUE; + out: + if (obj) + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; + bad: + ok = JS_FALSE; + goto out; } JS_FRIEND_API(JSBool) JS_FASTCALL diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 119a0705c7b..91e69fd3cfe 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -989,11 +989,11 @@ js_ValueToNumber(JSContext *cx, jsval *vp) * vp roots obj so we cannot use it as an extra root for * obj->defaultValue result when calling the hook. */ - AutoValueRooter gcr(cx, v); - if (!obj->defaultValue(cx, JSTYPE_NUMBER, gcr.addr())) + JSAutoTempValueRooter tvr(cx, v); + if (!obj->defaultValue(cx, JSTYPE_NUMBER, tvr.addr())) obj = NULL; else - v = *vp = gcr.value(); + v = *vp = tvr.value(); if (!obj) { *vp = JSVAL_NULL; return 0.0; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index c9b766820f2..498c6357e26 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -245,24 +245,32 @@ obj_setSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp) static JSBool obj_getCount(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { + jsval iter_state; jsid num_properties; + JSBool ok; if (JS_HAS_STRICT_OPTION(cx) && !ReportStrictSlot(cx, JSSLOT_COUNT)) - return false; + return JS_FALSE; + + iter_state = JSVAL_NULL; + JSAutoEnumStateRooter tvr(cx, obj, &iter_state); /* Get the number of properties to enumerate. */ - AutoEnumStateRooter iterState(cx, obj); - if (!obj->enumerate(cx, JSENUMERATE_INIT, iterState.addr(), &num_properties)) - return false; + ok = obj->enumerate(cx, JSENUMERATE_INIT, &iter_state, &num_properties); + if (!ok) + goto out; if (!JSVAL_IS_INT(num_properties)) { JS_ASSERT(0); *vp = JSVAL_ZERO; - return true; + goto out; } *vp = num_properties; - return true; +out: + if (!JSVAL_IS_NULL(iter_state)) + ok &= obj->enumerate(cx, JSENUMERATE_DESTROY, &iter_state, 0); + return ok; } #else /* !JS_HAS_OBJ_PROTO_PROP */ @@ -656,13 +664,15 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) #endif jsval *val; jsval localroot[4] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; + JSTempValueRooter tvr; JSString *gsopold[2]; JSString *gsop[2]; JSString *idstr, *valstr, *str; JS_CHECK_RECURSION(cx, return JS_FALSE); - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroot), localroot); + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT(cx, 4, localroot, &tvr); /* If outermost, we need parentheses to be an expression, not a block. */ outermost = (cx->sharpObjectMap.depth == 0); @@ -1027,6 +1037,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) *vp = STRING_TO_JSVAL(str); ok = JS_TRUE; out: + JS_POP_TEMP_ROOT(cx, &tvr); return ok; overflow: @@ -1955,7 +1966,7 @@ obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) JSObject *obj = JSVAL_TO_OBJECT(vp[2]); - AutoIdRooter nameidr(cx); + JSAutoTempIdRooter nameidr(cx); if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr())) return JS_FALSE; @@ -1975,7 +1986,7 @@ obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) } jsval roots[] = { JSVAL_VOID, JSVAL_VOID }; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) { if (OBJ_IS_NATIVE(obj)) { JSScopeProperty *sprop = reinterpret_cast(prop); @@ -2036,7 +2047,7 @@ obj_keys(JSContext *cx, uintN argc, jsval *vp) } JSObject *obj = JSVAL_TO_OBJECT(v); - AutoIdArray ida(cx, JS_Enumerate(cx, obj)); + JSAutoIdArray ida(cx, JS_Enumerate(cx, obj)); if (!ida) return JS_FALSE; @@ -2201,6 +2212,50 @@ PropertyDescriptor::initialize(JSContext* cx, jsid id, jsval v) return true; } +typedef js::Vector PropertyDescriptorArray; + +class AutoDescriptorArray : private JSTempValueRooter +{ + private: + JSContext *cx; + PropertyDescriptorArray descriptors; + + public: + AutoDescriptorArray(JSContext *cx) + : cx(cx), descriptors(cx) + { + JS_PUSH_TEMP_ROOT_TRACE(cx, trace, this); + } + ~AutoDescriptorArray() { + JS_POP_TEMP_ROOT(cx, this); + } + + PropertyDescriptor *append() { + if (!descriptors.append(PropertyDescriptor())) + return NULL; + return &descriptors.back(); + } + + PropertyDescriptor& operator[](size_t i) { + JS_ASSERT(i < descriptors.length()); + return descriptors[i]; + } + + private: + static void trace(JSTracer *trc, JSTempValueRooter *tvr) { + PropertyDescriptorArray &descs = + static_cast(tvr)->descriptors; + for (size_t i = 0, len = descs.length(); i < len; i++) { + PropertyDescriptor &desc = descs[i]; + + JS_CALL_VALUE_TRACER(trc, desc.value, "PropertyDescriptor::value"); + JS_CALL_VALUE_TRACER(trc, desc.get, "PropertyDescriptor::get"); + JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set"); + js_TraceId(trc, desc.id); + } + } +}; + static JSBool Reject(JSContext *cx, uintN errorNumber, bool throwError, jsid id, bool *rval) { @@ -2584,7 +2639,7 @@ obj_defineProperty(JSContext* cx, uintN argc, jsval* vp) JSObject* obj = JSVAL_TO_OBJECT(*vp); /* 15.2.3.6 step 2. */ - AutoIdRooter nameidr(cx); + JSAutoTempIdRooter nameidr(cx); if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr())) return JS_FALSE; @@ -2621,7 +2676,7 @@ obj_defineProperties(JSContext* cx, uintN argc, jsval* vp) return JS_FALSE; vp[3] = OBJECT_TO_JSVAL(props); - AutoIdArray ida(cx, JS_Enumerate(cx, props)); + JSAutoIdArray ida(cx, JS_Enumerate(cx, props)); if (!ida) return JS_FALSE; @@ -2685,7 +2740,7 @@ obj_create(JSContext *cx, uintN argc, jsval *vp) } JSObject *props = JSVAL_TO_OBJECT(vp[3]); - AutoIdArray ida(cx, JS_Enumerate(cx, props)); + JSAutoIdArray ida(cx, JS_Enumerate(cx, props)); if (!ida) return JS_FALSE; @@ -2883,7 +2938,7 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, * builtin. See bug 481444. */ if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) { - AutoValueRooter tvr(cx, obj); + JSAutoTempValueRooter tvr(cx, obj); JS_KEEP_ATOMS(cx->runtime); cx->debugHooks->objectHook(cx, obj, JS_TRUE, cx->debugHooks->objectHookData); @@ -3559,7 +3614,7 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp) obj->setParent(parent); } - AutoValueRooter tvr(cx, obj); + JSAutoTempValueRooter tvr(cx, obj); if (!JS_XDRUint32(xdr, &tmp)) return false; @@ -3652,6 +3707,7 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, JSAtom *atom; JSProtoKey key; JSObject *proto, *ctor; + JSTempValueRooter tvr; jsval cval, rval; JSBool named; JSFunction *fun; @@ -3687,7 +3743,7 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, return NULL; /* After this point, control must exit via label bad or out. */ - AutoValueRooter tvr(cx, proto); + JS_PUSH_TEMP_ROOT_OBJECT(cx, proto, &tvr); if (!constructor) { /* @@ -3777,6 +3833,7 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, goto bad; out: + JS_POP_TEMP_ROOT(cx, &tvr); return proto; bad: @@ -4084,7 +4141,7 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, jsval cval, rval; JSObject *obj, *ctor; - AutoArrayRooter argtvr(cx, argc, argv); + JSAutoTempValueRooter argtvr(cx, argc, argv); JSProtoKey protoKey = GetClassProtoKey(clasp); if (!js_FindClassObject(cx, parent, protoKey, &cval, clasp)) @@ -4096,7 +4153,7 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, } /* Protect cval in case a crazy getter for .prototype uproots it. */ - AutoValueRooter tvr(cx, cval); + JSAutoTempValueRooter tvr(cx, cval); /* * If proto or parent are NULL, set them to Constructor.prototype and/or @@ -4896,6 +4953,8 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, JSScope *scope; uint32 slot; int32 sample; + JSTempValueRooter tvr, tvr2; + JSBool ok; JS_ASSERT(OBJ_IS_NATIVE(pobj)); JS_ASSERT(JS_IS_OBJ_LOCKED(cx, pobj)); @@ -4915,14 +4974,15 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, sample = cx->runtime->propertyRemovals; JS_UNLOCK_SCOPE(cx, scope); - { - AutoScopePropertyRooter tvr(cx, sprop); - AutoValueRooter tvr2(cx, pobj); - if (!sprop->get(cx, obj, pobj, vp)) - return false; - } - JS_LOCK_SCOPE(cx, scope); + JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr); + JS_PUSH_TEMP_ROOT_OBJECT(cx, pobj, &tvr2); + ok = sprop->get(cx, obj, pobj, vp); + JS_POP_TEMP_ROOT(cx, &tvr2); + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ok) + return false; + JS_LOCK_SCOPE(cx, scope); if (SLOT_IN_SCOPE(slot, scope) && (JS_LIKELY(cx->runtime->propertyRemovals == sample) || scope->hasProperty(sprop))) { @@ -4946,6 +5006,8 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added, JSScope *scope; uint32 slot; int32 sample; + JSTempValueRooter tvr; + JSBool ok; JS_ASSERT(OBJ_IS_NATIVE(obj)); JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj)); @@ -4977,11 +5039,11 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added, sample = cx->runtime->propertyRemovals; JS_UNLOCK_SCOPE(cx, scope); - { - AutoScopePropertyRooter tvr(cx, sprop); - if (!sprop->set(cx, obj, vp)) - return false; - } + JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr); + ok = sprop->set(cx, obj, vp); + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ok) + return false; JS_LOCK_SCOPE(cx, scope); if (SLOT_IN_SCOPE(slot, scope) && diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 00223a9408e..512cbaef7e5 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -52,14 +52,12 @@ #include "jspubtd.h" #include "jsprvtd.h" -namespace js { class AutoDescriptorArray; } - /* * A representation of ECMA-262 ed. 5's internal property descriptor data * structure. */ struct PropertyDescriptor { - friend class js::AutoDescriptorArray; + friend class AutoDescriptorArray; private: PropertyDescriptor(); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index b8a21d864a3..376bca89333 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -83,34 +83,4 @@ JSObject::unbrand(JSContext *cx) return true; } -namespace js { - -typedef Vector PropertyDescriptorArray; - -class AutoDescriptorArray : private AutoGCRooter -{ - public: - AutoDescriptorArray(JSContext *cx) - : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx) - { } - - PropertyDescriptor *append() { - if (!descriptors.append(PropertyDescriptor())) - return NULL; - return &descriptors.back(); - } - - PropertyDescriptor& operator[](size_t i) { - JS_ASSERT(i < descriptors.length()); - return descriptors[i]; - } - - friend void AutoGCRooter::trace(JSTracer *trc); - - private: - PropertyDescriptorArray descriptors; -}; - -} - #endif /* jsobjinlines_h___ */ diff --git a/js/src/json.cpp b/js/src/json.cpp index 44897ba6d41..af0c1bfd9df 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -65,8 +65,6 @@ #include "jsatominlines.h" -using namespace js; - #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4351) @@ -108,9 +106,10 @@ js_json_parse(JSContext *cx, uintN argc, jsval *vp) { JSString *s = NULL; jsval *argv = vp + 2; - AutoValueRooter reviver(cx, JSVAL_NULL); + jsval reviver = JSVAL_NULL; + JSAutoTempValueRooter tvr(cx, 1, &reviver); - if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, reviver.addr())) + if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, &reviver)) return JS_FALSE; JSONParser *jp = js_BeginJSONParse(cx, vp); @@ -120,7 +119,7 @@ js_json_parse(JSContext *cx, uintN argc, jsval *vp) size_t length; s->getCharsAndLength(chars, length); ok = js_ConsumeJSONText(cx, jp, chars, length); - ok &= js_FinishJSONParse(cx, jp, reviver.value()); + ok &= js_FinishJSONParse(cx, jp, reviver); } return ok; @@ -130,16 +129,18 @@ JSBool js_json_stringify(JSContext *cx, uintN argc, jsval *vp) { jsval *argv = vp + 2; - AutoValueRooter space(cx, JSVAL_NULL); - AutoObjectRooter replacer(cx); + JSObject *replacer = NULL; + jsval space = JSVAL_NULL; + JSAutoTempValueRooter tvr(cx, replacer); + JSAutoTempValueRooter tvr2(cx, 1, &space); // Must throw an Error if there isn't a first arg - if (!JS_ConvertArguments(cx, argc, argv, "v / o v", vp, replacer.addr(), space.addr())) + if (!JS_ConvertArguments(cx, argc, argv, "v / o v", vp, &replacer, &space)) return JS_FALSE; JSCharBuffer cb(cx); - if (!js_Stringify(cx, vp, replacer.object(), space.value(), cb)) + if (!js_Stringify(cx, vp, replacer, space, cb)) return JS_FALSE; // XXX This can never happen to nsJSON.cpp, but the JSON object @@ -257,7 +258,7 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx) return JS_FALSE; jsval vec[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec); + JSAutoTempValueRooter tvr(cx, 3, vec); jsval& key = vec[0]; jsval& outputValue = vec[1]; @@ -306,7 +307,7 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx) if (!ks) goto error_break; } - AutoValueRooter keyStringRoot(cx, ks); + JSAutoTempValueRooter keyStringRoot(cx, ks); // Don't include prototype properties, since this operation is // supposed to be implemented as if by ES3.1 Object.keys() @@ -392,20 +393,21 @@ JA(JSContext *cx, jsval *vp, StringifyContext *scx) if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; - AutoValueRooter outputValue(cx, JSVAL_NULL); + jsval outputValue = JSVAL_NULL; + JSAutoTempValueRooter tvr(cx, 1, &outputValue); jsid id; jsuint i; for (i = 0; i < length; i++) { id = INT_TO_JSID(i); - if (!obj->getProperty(cx, id, outputValue.addr())) + if (!obj->getProperty(cx, id, &outputValue)) return JS_FALSE; - if (!Str(cx, id, obj, scx, outputValue.addr())) + if (!Str(cx, id, obj, scx, &outputValue)) return JS_FALSE; - if (outputValue.value() == JSVAL_VOID) { + if (outputValue == JSVAL_VOID) { if (!js_AppendLiteral(scx->cb, "null")) return JS_FALSE; } @@ -568,54 +570,63 @@ static JSBool IsNumChar(jschar c) static JSBool HandleData(JSContext *cx, JSONParser *jp, JSONDataType type); static JSBool PopState(JSContext *cx, JSONParser *jp); -static bool +static JSBool +DestroyIdArrayOnError(JSContext *cx, JSIdArray *ida) { + JS_DestroyIdArray(cx, ida); + return JS_FALSE; +} + +static JSBool Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp) { - JS_CHECK_RECURSION(cx, return false); + JS_CHECK_RECURSION(cx, return JS_FALSE); if (!holder->getProperty(cx, id, vp)) - return false; + return JS_FALSE; JSObject *obj; if (!JSVAL_IS_PRIMITIVE(*vp) && !(obj = JSVAL_TO_OBJECT(*vp))->isCallable()) { - AutoValueRooter propValue(cx, JSVAL_NULL); + jsval propValue = JSVAL_NULL; + JSAutoTempValueRooter tvr(cx, 1, &propValue); if(obj->isArray()) { jsuint length = 0; if (!js_GetLengthProperty(cx, obj, &length)) - return false; + return JS_FALSE; for (jsuint i = 0; i < length; i++) { jsid index; if (!js_IndexToId(cx, i, &index)) - return false; + return JS_FALSE; - if (!Walk(cx, index, obj, reviver, propValue.addr())) - return false; + if (!Walk(cx, index, obj, reviver, &propValue)) + return JS_FALSE; - if (!obj->defineProperty(cx, index, propValue.value(), NULL, NULL, JSPROP_ENUMERATE)) - return false; + if (!obj->defineProperty(cx, index, propValue, NULL, NULL, JSPROP_ENUMERATE)) + return JS_FALSE; } } else { - AutoIdArray ida(cx, JS_Enumerate(cx, obj)); + JSIdArray *ida = JS_Enumerate(cx, obj); if (!ida) - return false; + return JS_FALSE; - for (jsint i = 0, len = ida.length(); i < len; i++) { - jsid idName = ida[i]; - if (!Walk(cx, idName, obj, reviver, propValue.addr())) - return false; - if (propValue.value() == JSVAL_VOID) { - if (!js_DeleteProperty(cx, obj, idName, propValue.addr())) - return false; + JSAutoTempValueRooter idaroot(cx, JS_ARRAY_LENGTH(ida), (jsval*)ida); + + for(jsint i = 0; i < ida->length; i++) { + jsid idName = ida->vector[i]; + if (!Walk(cx, idName, obj, reviver, &propValue)) + return DestroyIdArrayOnError(cx, ida); + if (propValue == JSVAL_VOID) { + if (!js_DeleteProperty(cx, obj, idName, &propValue)) + return DestroyIdArrayOnError(cx, ida); } else { - if (!obj->defineProperty(cx, idName, propValue.value(), NULL, NULL, - JSPROP_ENUMERATE)) { - return false; - } + if (!obj->defineProperty(cx, idName, propValue, NULL, NULL, JSPROP_ENUMERATE)) + return DestroyIdArrayOnError(cx, ida); } } + + JS_DestroyIdArray(cx, ida); } } @@ -623,29 +634,31 @@ Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp) jsval value = *vp; JSString *key = js_ValueToString(cx, ID_TO_VALUE(id)); if (!key) - return false; + return JS_FALSE; jsval vec[2] = {STRING_TO_JSVAL(key), value}; jsval reviverResult; if (!JS_CallFunctionValue(cx, holder, reviver, 2, vec, &reviverResult)) - return false; + return JS_FALSE; *vp = reviverResult; - return true; + + return JS_TRUE; } -static bool +static JSBool Revive(JSContext *cx, jsval reviver, jsval *vp) { JSObject *obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL); if (!obj) - return false; + return JS_FALSE; - AutoValueRooter tvr(cx, obj); + jsval v = OBJECT_TO_JSVAL(obj); + JSAutoTempValueRooter tvr(cx, 1, &v); if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), *vp, NULL, NULL, JSPROP_ENUMERATE)) { - return false; + return JS_FALSE; } return Walk(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), obj, reviver, vp); @@ -680,11 +693,11 @@ bad: return NULL; } -bool +JSBool js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver) { if (!jp) - return true; + return JS_TRUE; JSBool early_ok = JS_TRUE; @@ -705,20 +718,20 @@ js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver) /* This internal API is infallible, in spite of its JSBool return type. */ js_RemoveRoot(cx->runtime, &jp->objectStack); - bool ok = *jp->statep == JSON_PARSE_STATE_FINISHED; + JSBool ok = *jp->statep == JSON_PARSE_STATE_FINISHED; jsval *vp = jp->rootVal; cx->destroy(jp); if (!early_ok) - return false; + return JS_FALSE; if (!ok) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE); - return false; + return JS_FALSE; } - if (!JSVAL_IS_PRIMITIVE(reviver) && JSVAL_TO_OBJECT(reviver)->isCallable()) + if (!JSVAL_IS_PRIMITIVE(reviver) && js_IsCallable(reviver)) ok = Revive(cx, reviver, vp); return ok; @@ -796,7 +809,7 @@ PushObject(JSContext *cx, JSONParser *jp, JSObject *obj) } jsval v = OBJECT_TO_JSVAL(obj); - AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); // Check if this is the root object if (len == 0) { @@ -869,7 +882,7 @@ CloseArray(JSContext *cx, JSONParser *jp) static JSBool PushPrimitive(JSContext *cx, JSONParser *jp, jsval value) { - AutoValueRooter tvr(cx, value); + JSAutoTempValueRooter tvr(cx, 1, &value); jsuint len; if (!js_GetLengthProperty(cx, jp->objectStack, &len)) diff --git a/js/src/json.h b/js/src/json.h index e384863e160..84f392419d9 100644 --- a/js/src/json.h +++ b/js/src/json.h @@ -89,7 +89,7 @@ js_BeginJSONParse(JSContext *cx, jsval *rootVal); extern JSBool js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len); -extern bool +extern JSBool js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver); JS_END_EXTERN_C diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index ce2a168e3aa..9fa44d4d1a3 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -79,8 +79,6 @@ #include "jsautooplen.h" -using namespace js; - /* * Index limit must stay within 32 bits. */ @@ -309,7 +307,7 @@ ToDisassemblySource(JSContext *cx, jsval v) } if (clasp == &js_RegExpClass) { - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); if (!js_regexp_toString(cx, obj, tvr.addr())) return NULL; return js_GetStringBytes(cx, JSVAL_TO_STRING(tvr.value())); diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 4f279295dad..391d4b67ae4 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -88,8 +88,6 @@ #include "jsdhash.h" #endif -using namespace js; - /* * Asserts to verify assumptions behind pn_ macros. */ @@ -224,6 +222,7 @@ JSCompiler::init(const jschar *base, size_t length, /* Root atoms and objects allocated for the parsed tree. */ JS_KEEP_ATOMS(cx->runtime); + JS_PUSH_TEMP_ROOT_COMPILER(cx, this, &tempRoot); return true; } @@ -233,6 +232,8 @@ JSCompiler::~JSCompiler() if (principals) JSPRINCIPALS_DROP(cx, principals); + JS_ASSERT(tempRoot.u.compiler == this); + JS_POP_TEMP_ROOT(cx, &tempRoot); JS_UNKEEP_ATOMS(cx->runtime); tokenStream.close(cx); JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark); @@ -337,7 +338,10 @@ JSFunctionBox::shouldUnbrand(uintN methods, uintN slowMethods) const void JSCompiler::trace(JSTracer *trc) { - JSObjectBox *objbox = traceListHead; + JSObjectBox *objbox; + + JS_ASSERT(tempRoot.u.compiler == this); + objbox = traceListHead; while (objbox) { JS_CALL_OBJECT_TRACER(trc, objbox->object, "parser.object"); objbox = objbox->traceLink; @@ -8826,6 +8830,7 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) JSParseNode **pnp, *pn1, *pn2; JSString *accum, *str; uint32 i, j; + JSTempValueRooter tvr; JS_ASSERT(pn->pn_arity == PN_LIST); tt = PN_TYPE(pn); @@ -8916,12 +8921,11 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) } if (accum) { - { - AutoValueRooter tvr(cx, accum); - str = ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && i != 0) - ? js_AddAttributePart(cx, i & 1, accum, str) - : js_ConcatStrings(cx, accum, str); - } + JS_PUSH_TEMP_ROOT_STRING(cx, accum, &tvr); + str = ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && i != 0) + ? js_AddAttributePart(cx, i & 1, accum, str) + : js_ConcatStrings(cx, accum, str); + JS_POP_TEMP_ROOT(cx, &tvr); if (!str) return JS_FALSE; #ifdef DEBUG_brendanXXX diff --git a/js/src/jsparse.h b/js/src/jsparse.h index 04b15ff675d..70458319276 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -832,10 +832,8 @@ struct JSFunctionBoxQueue { #define NUM_TEMP_FREELISTS 6U /* 32 to 2048 byte size classes (32 bit) */ -class JSTreeContext; - -struct JSCompiler : private js::AutoGCRooter { - JSContext * const context; /* FIXME Bug 551291: use AutoGCRooter::context? */ +struct JSCompiler { + JSContext *context; JSAtomListElement *aleFreeList; void *tempFreeList[NUM_TEMP_FREELISTS]; JSTokenStream tokenStream; @@ -845,10 +843,10 @@ struct JSCompiler : private js::AutoGCRooter { JSParseNode *nodeList; /* list of recyclable parse-node structs */ uint32 functionCount; /* number of functions in current unit */ JSObjectBox *traceListHead; /* list of parsed object for GC tracing */ + JSTempValueRooter tempRoot; /* root to trace traceListHead */ JSCompiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL) - : js::AutoGCRooter(cx, COMPILER), context(cx), - aleFreeList(NULL), tokenStream(cx), principals(NULL), + : context(cx), aleFreeList(NULL), tokenStream(cx), principals(NULL), callerFrame(cfp), nodeList(NULL), functionCount(0), traceListHead(NULL) { memset(tempFreeList, 0, sizeof tempFreeList); @@ -858,9 +856,6 @@ struct JSCompiler : private js::AutoGCRooter { ~JSCompiler(); - friend void js::AutoGCRooter::trace(JSTracer *trc); - friend class JSTreeContext; - /* * Initialize a compiler. Parameters are passed on to init tokenStream. * The compiler owns the arena pool "tops-of-stack" space above the current diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index 664a80206a9..cd78b67bb7a 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -281,6 +281,31 @@ typedef struct JSDebugHooks { void *debugErrorHookData; } JSDebugHooks; +/* + * Type definitions for temporary GC roots that register with GC local C + * variables. See jscntxt.h for details. + */ +typedef void +(* JSTempValueTrace)(JSTracer *trc, JSTempValueRooter *tvr); + +typedef union JSTempValueUnion { + jsval value; + JSObject *object; + JSXML *xml; + JSTempValueTrace trace; + JSScopeProperty *sprop; + JSWeakRoots *weakRoots; + JSCompiler *compiler; + JSScript *script; + jsval *array; +} JSTempValueUnion; + +struct JSTempValueRooter { + JSTempValueRooter *down; + ptrdiff_t count; + JSTempValueUnion u; +}; + /* JSObjectOps function pointer typedefs. */ /* diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index e02ce42cf83..6642ae5a558 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -5232,10 +5232,10 @@ js_InitRegExpStatics(JSContext *cx) JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - AutoValueRooter *tvr) + JSTempValueRooter *tvr) { *statics = cx->regExpStatics; - tvr->setString(statics->input); + JS_PUSH_TEMP_ROOT_STRING(cx, statics->input, tvr); /* * Prevent JS_ClearRegExpStatics from freeing moreParens, since we've only * moved it elsewhere (into statics->moreParens). @@ -5246,11 +5246,12 @@ js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - AutoValueRooter *tvr) + JSTempValueRooter *tvr) { /* Clear/free any new JSRegExpStatics data before clobbering. */ JS_ClearRegExpStatics(cx); cx->regExpStatics = *statics; + JS_POP_TEMP_ROOT(cx, tvr); } void @@ -5843,7 +5844,7 @@ js_NewRegExpObject(JSContext *cx, JSTokenStream *ts, str = js_NewStringCopyN(cx, chars, length); if (!str) return NULL; - AutoValueRooter tvr(cx, str); + JSAutoTempValueRooter tvr(cx, str); re = js_NewRegExp(cx, ts, str, flags, JS_FALSE); if (!re) return NULL; diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index af08f9843de..cc30304ac46 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -65,15 +65,13 @@ struct JSRegExpStatics { JSSubString rightContext; /* input to right of last match (perl $') */ }; -namespace js { class AutoValueRooter; } - extern JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - js::AutoValueRooter *tvr); + JSTempValueRooter *tvr); extern JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - js::AutoValueRooter *tvr); + JSTempValueRooter *tvr); /* * This struct holds a bitmap representation of a class from a regexp. diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 4e38b4434c5..01aa5877adf 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -94,6 +94,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, uint32 length, lineno, nslots, magic; uint32 natoms, nsrcnotes, ntrynotes, nobjects, nupvars, nregexps, i; uint32 prologLength, version; + JSTempValueRooter tvr; JSPrincipals *principals; uint32 encodeable; JSBool filenameWasSaved; @@ -211,8 +212,6 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, if (!JS_XDRUint32(xdr, &nregexps)) return JS_FALSE; - AutoScriptRooter tvr(cx, NULL); - if (xdr->mode == JSXDR_DECODE) { script = js_NewScript(cx, length, nsrcnotes, natoms, nobjects, nupvars, nregexps, ntrynotes); @@ -226,7 +225,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, /* If we know nsrcnotes, we allocated space for notes in script. */ notes = script->notes(); *scriptp = script; - tvr.setScript(script); + JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr); } /* @@ -369,10 +368,13 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, } xdr->script = oldscript; + if (xdr->mode == JSXDR_DECODE) + JS_POP_TEMP_ROOT(cx, &tvr); return JS_TRUE; error: if (xdr->mode == JSXDR_DECODE) { + JS_POP_TEMP_ROOT(cx, &tvr); if (script->filename && !filenameWasSaved) { cx->free((void *) script->filename); script->filename = NULL; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 28f763c8496..ca9893f3960 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1603,7 +1603,7 @@ str_match(JSContext *cx, uintN argc, jsval *vp) if (!g.normalizeRegExp(false, 1, argc, vp)) return false; - AutoValueRooter array(cx, JSVAL_NULL); + JSAutoTempValueRooter array(cx, JSVAL_NULL); if (!DoMatch(cx, vp, str, g, MatchCallback, array.addr(), MATCH_ARGS)) return false; @@ -3384,7 +3384,7 @@ js_ValueToSource(JSContext *cx, jsval v) } JSAtom *atom = cx->runtime->atomState.toSourceAtom; - AutoValueRooter tvr(cx, JSVAL_NULL); + JSAutoTempValueRooter tvr(cx, JSVAL_NULL); if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v), atom, 0, NULL, tvr.addr())) return NULL; return js_ValueToString(cx, tvr.value()); diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index e39d20c3894..6c137c4966d 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -8814,12 +8814,13 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond) } } { - AutoValueRooter tvr(cx); + jsval tmp = JSVAL_NULL; + JSAutoTempValueRooter tvr(cx, 1, &tmp); - *tvr.addr() = l; - lnum = js_ValueToNumber(cx, tvr.addr()); - *tvr.addr() = r; - rnum = js_ValueToNumber(cx, tvr.addr()); + tmp = l; + lnum = js_ValueToNumber(cx, &tmp); + tmp = r; + rnum = js_ValueToNumber(cx, &tmp); } cond = EvalCmp(op, lnum, rnum); fp = true; @@ -11209,7 +11210,7 @@ TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, JSScopeProperty* sprop, static JSBool FASTCALL MethodWriteBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj) { - AutoValueRooter tvr(cx, funobj); + JSAutoTempValueRooter tvr(cx, funobj); return OBJ_SCOPE(obj)->methodWriteBarrier(cx, sprop, tvr.value()); } @@ -11573,7 +11574,7 @@ GetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp) { LeaveTraceIfGlobalObject(cx, obj); - AutoIdRooter idr(cx); + JSAutoTempIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || !obj->getProperty(cx, idr.id(), vp)) { SetBuiltinError(cx); return JS_FALSE; @@ -11912,7 +11913,7 @@ SetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp) { LeaveTraceIfGlobalObject(cx, obj); - AutoIdRooter idr(cx); + JSAutoTempIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || !obj->setProperty(cx, idr.id(), vp)) { SetBuiltinError(cx); return JS_FALSE; @@ -11927,7 +11928,7 @@ InitPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval val) { LeaveTraceIfGlobalObject(cx, obj); - AutoIdRooter idr(cx); + JSAutoTempIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || !obj->defineProperty(cx, idr.id(), val, NULL, NULL, JSPROP_ENUMERATE)) { SetBuiltinError(cx); @@ -12746,7 +12747,7 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr) static JSObject* FASTCALL MethodReadBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj) { - AutoValueRooter tvr(cx, funobj); + JSAutoTempValueRooter tvr(cx, funobj); if (!OBJ_SCOPE(obj)->methodReadBarrier(cx, sprop, tvr.addr())) return NULL; @@ -14867,7 +14868,7 @@ CallIteratorNext(JSContext *cx, uintN argc, jsval *vp) static jsval FASTCALL CallIteratorNext_tn(JSContext* cx, jsbytecode* pc, JSObject* iterobj) { - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); JSBool ok = js_CallIteratorNext(cx, iterobj, tvr.addr()); if (!ok) { diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index e2959ef3e65..0f5a8930e3e 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -1320,10 +1320,10 @@ js_IsTypedArray(JSObject *obj) JS_FRIEND_API(JSObject *) js_CreateArrayBuffer(JSContext *cx, jsuint nbytes) { - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); js_NewNumberInRootedValue(cx, jsdouble(nbytes), tvr.addr()); - AutoValueRooter rval(cx); + JSAutoTempValueRooter rval(cx); if (!ArrayBuffer::class_constructor(cx, cx->globalObject, 1, tvr.addr(), rval.addr())) @@ -1375,7 +1375,7 @@ js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements) JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); jsval vals[2]; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); + JSAutoTempValueRooter tvr(cx, 2, vals); if (!js_NewNumberInRootedValue(cx, jsdouble(nelements), &vals[0])) return NULL; @@ -1392,7 +1392,7 @@ js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg) JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); jsval vals[2]; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); + JSAutoTempValueRooter tvr(cx, 2, vals); vals[0] = OBJECT_TO_JSVAL(arrayArg); @@ -1412,7 +1412,7 @@ js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg, JS_ASSERT(length < 0 || byteoffset >= 0); jsval vals[4]; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); + JSAutoTempValueRooter tvr(cx, 4, vals); int argc = 1; vals[0] = OBJECT_TO_JSVAL(bufArg); diff --git a/js/src/jsutil.h b/js/src/jsutil.h index 82e2f6bccd5..56029438cc7 100644 --- a/js/src/jsutil.h +++ b/js/src/jsutil.h @@ -211,9 +211,9 @@ JS_END_EXTERN_C * when we have a guard object whose only purpose is its constructor and * destructor (and is never otherwise referenced), the intended use * might be: - * js::AutoValueRooter tvr(cx, 1, &val); + * JSAutoTempValueRooter tvr(cx, 1, &val); * but is is easy to accidentally write: - * js::AutoValueRooter(cx, 1, &val); + * JSAutoTempValueRooter(cx, 1, &val); * which compiles just fine, but runs the destructor well before the * intended time. * diff --git a/js/src/jsvector.h b/js/src/jsvector.h index bdd6ec1d813..7c051f7005e 100644 --- a/js/src/jsvector.h +++ b/js/src/jsvector.h @@ -359,10 +359,7 @@ class Vector : AllocPolicy /* mutators */ - /* - * If reserve(N) succeeds, additions to this vector which increase its size - * up to and including N are guaranteed to succeed. - */ + /* If reserve(N) succeeds, the N next appends are guaranteed to succeed. */ bool reserve(size_t capacity); /* Destroy elements in the range [begin() + incr, end()). */ diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 2908d205794..673b2d3abf9 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -70,14 +70,10 @@ #include "jsstaticcheck.h" #include "jsvector.h" -#include "jscntxtinlines.h" - #ifdef DEBUG #include /* for #ifdef DEBUG memset calls */ #endif -using namespace js; - /* * NOTES * - in the js shell, you must use the -x command line option, or call @@ -870,10 +866,60 @@ attr_identity(const void *a, const void *b) return qname_identity(xmla->name, xmlb->name); } +struct JSXMLArrayCursor +{ + JSXMLArray *array; + uint32 index; + JSXMLArrayCursor *next; + JSXMLArrayCursor **prevp; + void *root; + + JSXMLArrayCursor(JSXMLArray *array) + : array(array), index(0), next(array->cursors), prevp(&array->cursors), + root(NULL) + { + if (next) + next->prevp = &next; + array->cursors = this; + } + + ~JSXMLArrayCursor() { disconnect(); } + + void disconnect() { + if (!array) + return; + if (next) + next->prevp = prevp; + *prevp = next; + array = NULL; + } + + void *getNext() { + if (!array || index >= array->length) + return NULL; + return root = array->vector[index++]; + } + + void *getCurrent() { + if (!array || index >= array->length) + return NULL; + return root = array->vector[index]; + } +}; + static void XMLArrayCursorTrace(JSTracer *trc, JSXMLArrayCursor *cursor) { - cursor->trace(trc); + void *root; +#ifdef DEBUG + size_t index = 0; +#endif + + for (; cursor; cursor = cursor->next) { + root = cursor->root; + JS_SET_TRACING_INDEX(trc, "cursor_root", index++); + js_CallValueTracerIfGCThing(trc, (jsval)root); + } } /* NB: called with null cx from the GC, via xml_trace => XMLArrayTrim. */ @@ -3802,10 +3848,12 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) JSObject *kidobj, *listobj; JSObject *nameqn; jsid funid; + jsval roots[2]; + JSTempValueRooter tvr; xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL); if (!xml) - return true; + return JS_TRUE; if (js_IdIsIndex(id, &index)) { if (xml->xml_class != JSXML_CLASS_LIST) { @@ -3822,18 +3870,18 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); if (!kid) { *vp = JSVAL_VOID; - return true; + return JS_TRUE; } kidobj = js_GetXMLObject(cx, kid); if (!kidobj) - return false; + return JS_FALSE; *vp = OBJECT_TO_JSVAL(kidobj); } else { *vp = JSVAL_VOID; } } - return true; + return JS_TRUE; } /* @@ -3841,34 +3889,37 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) */ nameqn = ToXMLName(cx, id, &funid); if (!nameqn) - return false; + return JS_FALSE; if (funid) return GetXMLFunction(cx, obj, funid, vp); - jsval roots[2] = { OBJECT_TO_JSVAL(nameqn), JSVAL_NULL }; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + roots[0] = OBJECT_TO_JSVAL(nameqn); + JS_PUSH_TEMP_ROOT(cx, 1, roots, &tvr); listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); - if (!listobj) - return false; + if (listobj) { + roots[1] = OBJECT_TO_JSVAL(listobj); + tvr.count++; - roots[1] = OBJECT_TO_JSVAL(listobj); + list = (JSXML *) listobj->getPrivate(); + if (!GetNamedProperty(cx, xml, nameqn, list)) { + listobj = NULL; + } else { + /* + * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the + * given list's [[TargetProperty]] to the property that is being + * appended. This means that any use of the internal [[Get]] + * property returns a list which, when used by e.g. [[Insert]] + * duplicates the last element matched by id. See bug 336921. + */ + list->xml_target = xml; + list->xml_targetprop = nameqn; + *vp = OBJECT_TO_JSVAL(listobj); + } + } - list = (JSXML *) listobj->getPrivate(); - if (!GetNamedProperty(cx, xml, nameqn, list)) - return false; - - /* - * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the - * given list's [[TargetProperty]] to the property that is being - * appended. This means that any use of the internal [[Get]] - * property returns a list which, when used by e.g. [[Insert]] - * duplicates the last element matched by id. See bug 336921. - */ - list->xml_target = xml; - list->xml_targetprop = nameqn; - *vp = OBJECT_TO_JSVAL(listobj); - return true; + JS_POP_TEMP_ROOT(cx, &tvr); + return listobj != NULL; } static JSXML * @@ -3912,6 +3963,8 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { JSBool ok, primitiveAssign; enum { OBJ_ROOT, ID_ROOT, VAL_ROOT }; + jsval roots[3]; + JSTempValueRooter tvr; JSXML *xml, *vxml, *rxml, *kid, *attr, *parent, *copy, *kid2, *match; JSObject *vobj, *nameobj, *attrobj, *parentobj, *kidobj, *copyobj; JSObject *targetprop, *nameqn, *attrqn; @@ -3940,13 +3993,11 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) ok = js_EnterLocalRootScope(cx); if (!ok) return JS_FALSE; - MUST_FLOW_THROUGH("out"); - jsval roots[3]; roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj); roots[ID_ROOT] = id; roots[VAL_ROOT] = *vp; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + JS_PUSH_TEMP_ROOT(cx, 3, roots, &tvr); if (js_IdIsIndex(id, &index)) { if (xml->xml_class != JSXML_CLASS_LIST) { @@ -4533,6 +4584,7 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } out: + JS_POP_TEMP_ROOT(cx, &tvr); js_LeaveLocalRootScope(cx); return ok; @@ -4664,34 +4716,38 @@ HasFunctionProperty(JSContext *cx, JSObject *obj, jsid funid, JSBool *found) JSObject *pobj; JSProperty *prop; JSXML *xml; + JSTempValueRooter tvr; + JSBool ok; JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_XMLClass); if (!js_LookupProperty(cx, obj, funid, &pobj, &prop)) - return false; + return JS_FALSE; if (prop) { pobj->dropProperty(cx, prop); } else { xml = (JSXML *) obj->getPrivate(); if (HasSimpleContent(xml)) { - AutoObjectRooter tvr(cx); - /* * Search in String.prototype to set found whenever * GetXMLFunction returns existing function. */ - if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr())) - return false; - - JS_ASSERT(tvr.object()); - if (!js_LookupProperty(cx, tvr.object(), funid, &pobj, &prop)) - return false; - if (prop) - pobj->dropProperty(cx, prop); + JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr); + ok = js_GetClassPrototype(cx, NULL, JSProto_String, + &tvr.u.object); + JS_ASSERT(tvr.u.object); + if (ok) { + ok = js_LookupProperty(cx, tvr.u.object, funid, &pobj, &prop); + if (ok && prop) + pobj->dropProperty(cx, prop); + } + JS_POP_TEMP_ROOT(cx, &tvr); + if (!ok) + return JS_FALSE; } } *found = (prop != NULL); - return true; + return JS_TRUE; } /* ECMA-357 9.1.1.6 XML [[HasProperty]] and 9.2.1.5 XMLList [[HasProperty]]. */ @@ -4958,22 +5014,18 @@ xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, switch (enum_op) { case JSENUMERATE_INIT: if (length == 0) { - *statep = JSVAL_ZERO; + cursor = NULL; } else { cursor = cx->create(&xml->xml_kids); if (!cursor) return JS_FALSE; - *statep = PRIVATE_TO_JSVAL(cursor); } + *statep = PRIVATE_TO_JSVAL(cursor); if (idp) *idp = INT_TO_JSID(length); break; case JSENUMERATE_NEXT: - if (*statep == JSVAL_ZERO) { - *statep = JSVAL_NULL; - break; - } cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); if (cursor && cursor->array && (index = cursor->index) < length) { *idp = INT_TO_JSID(index); @@ -4983,11 +5035,9 @@ xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, /* FALL THROUGH */ case JSENUMERATE_DESTROY: - if (*statep != JSVAL_ZERO) { - cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); - if (cursor) - cx->destroy(cursor); - } + cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + if (cursor) + cx->destroy(cursor); *statep = JSVAL_NULL; break; } @@ -5076,7 +5126,7 @@ js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp) * As our callers have a bad habit of passing a pointer to an unrooted * local value as vp, we use a proper root here. */ - AutoValueRooter tvr(cx); + JSAutoTempValueRooter tvr(cx); JSBool ok = GetXMLFunction(cx, obj, id, tvr.addr()); *vp = tvr.value(); return ok; @@ -5099,22 +5149,20 @@ js_EnumerateXMLValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op, switch (enum_op) { case JSENUMERATE_INIT: if (length == 0) { - *statep = JSVAL_ZERO; + cursor = NULL; } else { cursor = cx->create(&xml->xml_kids); if (!cursor) return JS_FALSE; - *statep = PRIVATE_TO_JSVAL(cursor); } - JS_ASSERT(!idp); - JS_ASSERT(!vp); + *statep = PRIVATE_TO_JSVAL(cursor); + if (idp) + *idp = INT_TO_JSID(length); + if (vp) + *vp = JSVAL_VOID; break; case JSENUMERATE_NEXT: - if (*statep == JSVAL_ZERO) { - *statep = JSVAL_NULL; - break; - } cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); if (cursor && cursor->array && (index = cursor->index) < length) { while (!(kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML))) { @@ -5133,12 +5181,10 @@ js_EnumerateXMLValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op, /* FALL THROUGH */ case JSENUMERATE_DESTROY: - if (*statep != JSVAL_ZERO) { - cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); - if (cursor) { - destroy: - cx->destroy(cursor); - } + cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + if (cursor) { + destroy: + cx->destroy(cursor); } *statep = JSVAL_NULL; break; @@ -5431,7 +5477,7 @@ xml_attributes(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; name = OBJECT_TO_JSVAL(qn); - AutoValueRooter tvr(cx, name); + JSAutoTempValueRooter tvr(cx, name); return GetProperty(cx, JS_THIS_OBJECT(cx, vp), name, vp); } @@ -5837,6 +5883,81 @@ xml_hasSimpleContent(JSContext *cx, uintN argc, jsval *vp) return JS_TRUE; } +typedef struct JSTempRootedNSArray { + JSTempValueRooter tvr; + JSXMLArray array; + jsval value; /* extra root for temporaries */ +} JSTempRootedNSArray; + +static void +TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len) +{ + uint32 i; + JSObject *obj; + + for (i = 0; i < len; i++) { + obj = vec[i]; + if (obj) { + JS_SET_TRACING_INDEX(trc, "vector", i); + js_CallGCMarker(trc, obj, JSTRACE_OBJECT); + } + } +} + +static void +trace_temp_ns_array(JSTracer *trc, JSTempValueRooter *tvr) +{ + JSTempRootedNSArray *tmp = (JSTempRootedNSArray *)tvr; + + TraceObjectVector(trc, + (JSObject **) tmp->array.vector, + tmp->array.length); + XMLArrayCursorTrace(trc, tmp->array.cursors); + JS_CALL_VALUE_TRACER(trc, tmp->value, "temp_ns_array_value"); +} + +static void +InitTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp) +{ + XMLArrayInit(cx, &tmp->array, 0); + tmp->value = JSVAL_NULL; + JS_PUSH_TEMP_ROOT_TRACE(cx, trace_temp_ns_array, &tmp->tvr); +} + +static void +FinishTempNSArray(JSContext *cx, JSTempRootedNSArray *tmp) +{ + JS_ASSERT(tmp->tvr.u.trace == trace_temp_ns_array); + JS_POP_TEMP_ROOT(cx, &tmp->tvr); + XMLArrayFinish(cx, &tmp->array); +} + +/* + * Populate a new JS array with elements of JSTempRootedNSArray.array and + * place the result into rval. rval must point to a rooted location. + */ +static JSBool +TempNSArrayToJSArray(JSContext *cx, JSTempRootedNSArray *tmp, jsval *rval) +{ + JSObject *arrayobj; + uint32 i, n; + JSObject *ns; + + arrayobj = js_NewArrayObject(cx, 0, NULL); + if (!arrayobj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(arrayobj); + for (i = 0, n = tmp->array.length; i < n; i++) { + ns = XMLARRAY_MEMBER(&tmp->array, i, JSObject); + if (!ns) + continue; + tmp->value = OBJECT_TO_JSVAL(ns); + if (!arrayobj->setProperty(cx, INT_TO_JSID(i), &tmp->value)) + return JS_FALSE; + } + return JS_TRUE; +} + static JSBool FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray) { @@ -5878,48 +5999,19 @@ FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray) return JS_TRUE; } -class AutoNamespaceArray : public js::AutoNamespaces { - public: - AutoNamespaceArray(JSContext *cx) - : js::AutoNamespaces(cx) - { - XMLArrayInit(cx, &array, 0); - } - - ~AutoNamespaceArray() { - XMLArrayFinish(context, &array); - } - - /* - * Populate a new JS array with elements of array and place the result into - * rval. rval must point to a rooted location. - */ - bool toJSArray(jsval *rval) { - JSObject *arrayobj = js_NewArrayObject(context, 0, NULL); - if (!arrayobj) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(arrayobj); - - AutoValueRooter tvr(context); - for (uint32 i = 0, n = array.length; i < n; i++) { - JSObject *ns = XMLARRAY_MEMBER(&array, i, JSObject); - if (!ns) - continue; - *tvr.addr() = OBJECT_TO_JSVAL(ns); - if (!arrayobj->setProperty(context, INT_TO_JSID(i), tvr.addr())) - return JS_FALSE; - } - return JS_TRUE; - } -}; - static JSBool xml_inScopeNamespaces(JSContext *cx, uintN argc, jsval *vp) { + JSTempRootedNSArray namespaces; + JSBool ok; + NON_LIST_XML_METHOD_PROLOG; - AutoNamespaceArray namespaces(cx); - return FindInScopeNamespaces(cx, xml, &namespaces.array) && namespaces.toJSArray(vp); + InitTempNSArray(cx, &namespaces); + ok = FindInScopeNamespaces(cx, xml, &namespaces.array) && + TempNSArrayToJSArray(cx, &namespaces, vp); + FinishTempNSArray(cx, &namespaces); + return ok; } static JSBool @@ -6019,13 +6111,15 @@ static JSBool xml_namespace(JSContext *cx, uintN argc, jsval *vp) { JSString *prefix, *nsprefix; + JSTempRootedNSArray inScopeNSes; + JSBool ok; jsuint i, length; JSObject *ns; NON_LIST_XML_METHOD_PROLOG; if (argc == 0 && !JSXML_HAS_NAME(xml)) { *vp = JSVAL_NULL; - return true; + return JS_TRUE; } if (argc == 0) { @@ -6033,18 +6127,22 @@ xml_namespace(JSContext *cx, uintN argc, jsval *vp) } else { prefix = js_ValueToString(cx, vp[2]); if (!prefix) - return false; + return JS_FALSE; vp[2] = STRING_TO_JSVAL(prefix); /* local root */ } - AutoNamespaceArray inScopeNSes(cx); - if (!FindInScopeNamespaces(cx, xml, &inScopeNSes.array)) - return false; + InitTempNSArray(cx, &inScopeNSes); + MUST_FLOW_THROUGH("out"); + ok = FindInScopeNamespaces(cx, xml, &inScopeNSes.array); + if (!ok) + goto out; if (!prefix) { ns = GetNamespace(cx, xml->name, &inScopeNSes.array); - if (!ns) - return false; + if (!ns) { + ok = JS_FALSE; + goto out; + } } else { ns = NULL; for (i = 0, length = inScopeNSes.array.length; i < length; i++) { @@ -6059,44 +6157,64 @@ xml_namespace(JSContext *cx, uintN argc, jsval *vp) } *vp = (!ns) ? JSVAL_VOID : OBJECT_TO_JSVAL(ns); - return true; + + out: + FinishTempNSArray(cx, &inScopeNSes); + return JS_TRUE; } static JSBool xml_namespaceDeclarations(JSContext *cx, uintN argc, jsval *vp) { + JSBool ok; + JSTempRootedNSArray ancestors, declared; + JSXML *yml; + uint32 i, n; + JSObject *ns; + NON_LIST_XML_METHOD_PROLOG; if (JSXML_HAS_VALUE(xml)) - return true; + return JS_TRUE; - AutoNamespaceArray ancestors(cx); - AutoNamespaceArray declared(cx); + /* From here, control flow must goto out to finish these arrays. */ + ok = JS_TRUE; + InitTempNSArray(cx, &ancestors); + InitTempNSArray(cx, &declared); + yml = xml; - JSXML *yml = xml; while ((yml = yml->parent) != NULL) { JS_ASSERT(yml->xml_class == JSXML_CLASS_ELEMENT); - for (uint32 i = 0, n = yml->xml_namespaces.length; i < n; i++) { - JSObject *ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSObject); - if (ns && !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { - if (!XMLARRAY_APPEND(cx, &ancestors.array, ns)) - return false; + for (i = 0, n = yml->xml_namespaces.length; i < n; i++) { + ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSObject); + if (ns && + !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { + ok = XMLARRAY_APPEND(cx, &ancestors.array, ns); + if (!ok) + goto out; } } } - for (uint32 i = 0, n = xml->xml_namespaces.length; i < n; i++) { - JSObject *ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { + ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); if (!ns) continue; if (!IsDeclared(ns)) continue; if (!XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { - if (!XMLARRAY_APPEND(cx, &declared.array, ns)) - return false; + ok = XMLARRAY_APPEND(cx, &declared.array, ns); + if (!ok) + goto out; } } - return declared.toJSArray(vp); + ok = TempNSArrayToJSArray(cx, &declared, vp); + +out: + /* Finishing must be in reverse order of initialization to follow LIFO. */ + FinishTempNSArray(cx, &declared); + FinishTempNSArray(cx, &ancestors); + return ok; } static const char js_attribute_str[] = "attribute"; @@ -7129,9 +7247,9 @@ js_TraceXML(JSTracer *trc, JSXML *xml) if (xml->xml_targetprop) JS_CALL_OBJECT_TRACER(trc, xml->xml_targetprop, "targetprop"); } else { - js::TraceObjectVector(trc, - (JSObject **) xml->xml_namespaces.vector, - xml->xml_namespaces.length); + TraceObjectVector(trc, + (JSObject **) xml->xml_namespaces.vector, + xml->xml_namespaces.length); XMLArrayCursorTrace(trc, xml->xml_namespaces.cursors); if (IS_GC_MARKING_TRACER(trc)) XMLArrayTrim(&xml->xml_namespaces); @@ -7164,12 +7282,17 @@ js_FinalizeXML(JSContext *cx, JSXML *xml) JSObject * js_NewXMLObject(JSContext *cx, JSXMLClass xml_class) { - JSXML *xml = js_NewXML(cx, xml_class); + JSXML *xml; + JSObject *obj; + JSTempValueRooter tvr; + + xml = js_NewXML(cx, xml_class); if (!xml) return NULL; - - AutoXMLRooter root(cx, xml); - return js_GetXMLObject(cx, xml); + JS_PUSH_TEMP_ROOT_XML(cx, xml, &tvr); + obj = js_GetXMLObject(cx, xml); + JS_POP_TEMP_ROOT(cx, &tvr); + return obj; } static JSObject * @@ -7686,35 +7809,48 @@ js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp) static JSBool GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { + JSObject *target; + JSXML *xml; + JSTempValueRooter tvr; + JSBool ok; + JS_ASSERT(OBJECT_IS_XML(cx, obj)); + MUST_FLOW_THROUGH("out"); + JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr); + /* * See comments before xml_lookupProperty about the need for the proto * chain lookup. */ - JSObject *target = obj; - AutoObjectRooter tvr(cx); + target = obj; for (;;) { - if (!js_GetProperty(cx, target, id, vp)) - return false; - if (VALUE_IS_FUNCTION(cx, *vp)) - return true; + ok = js_GetProperty(cx, target, id, vp); + if (!ok) + goto out; + if (VALUE_IS_FUNCTION(cx, *vp)) { + ok = JS_TRUE; + goto out; + } target = target->getProto(); if (target == NULL) break; - tvr.setObject(target); + tvr.u.object = target; } - JSXML *xml = (JSXML *) obj->getPrivate(); - if (!HasSimpleContent(xml)) - return true; + xml = (JSXML *) obj->getPrivate(); + if (HasSimpleContent(xml)) { + /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */ + ok = js_GetClassPrototype(cx, NULL, JSProto_String, &tvr.u.object); + if (!ok) + goto out; + JS_ASSERT(tvr.u.object); + ok = tvr.u.object->getProperty(cx, id, vp); + } - /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */ - if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr())) - return false; - - JS_ASSERT(tvr.object()); - return tvr.object()->getProperty(cx, id, vp); + out: + JS_POP_TEMP_ROOT(cx, &tvr); + return ok; } static JSXML * diff --git a/js/src/jsxml.h b/js/src/jsxml.h index 37724757e26..cb7198f5986 100644 --- a/js/src/jsxml.h +++ b/js/src/jsxml.h @@ -39,7 +39,7 @@ #ifndef jsxml_h___ #define jsxml_h___ -#include "jsarray.h" +#include "jspubtd.h" JS_BEGIN_EXTERN_C @@ -63,58 +63,6 @@ struct JSXMLArray { JSXMLArrayCursor *cursors; }; -struct JSXMLArrayCursor -{ - JSXMLArray *array; - uint32 index; - JSXMLArrayCursor *next; - JSXMLArrayCursor **prevp; - void *root; - - JSXMLArrayCursor(JSXMLArray *array) - : array(array), index(0), next(array->cursors), prevp(&array->cursors), - root(NULL) - { - if (next) - next->prevp = &next; - array->cursors = this; - } - - ~JSXMLArrayCursor() { disconnect(); } - - void disconnect() { - if (!array) - return; - if (next) - next->prevp = prevp; - *prevp = next; - array = NULL; - } - - void *getNext() { - if (!array || index >= array->length) - return NULL; - return root = array->vector[index++]; - } - - void *getCurrent() { - if (!array || index >= array->length) - return NULL; - return root = array->vector[index]; - } - - void trace(JSTracer *trc) { -#ifdef DEBUG - size_t index = 0; -#endif - for (JSXMLArrayCursor *cursor = this; cursor; cursor = cursor->next) { - void *root = cursor->root; - JS_SET_TRACING_INDEX(trc, "cursor_root", index++); - js_CallValueTracerIfGCThing(trc, jsval(root)); - } - } -}; - #define JSXML_PRESET_CAPACITY JS_BIT(31) #define JSXML_CAPACITY_MASK JS_BITMASK(31) #define JSXML_CAPACITY(array) ((array)->capacity & JSXML_CAPACITY_MASK) diff --git a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp index 8444c135994..70724cadeb6 100644 --- a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp @@ -40,7 +40,7 @@ #include "xpcprivate.h" #include "nsDOMError.h" #include "jsdbgapi.h" -#include "jscntxt.h" // For js::AutoValueRooter. +#include "jscntxt.h" // For JSAutoTempValueRooter. #include "jsobj.h" #include "XPCNativeWrapper.h" #include "XPCWrapper.h" @@ -283,16 +283,17 @@ WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp) *vp = OBJECT_TO_JSVAL(wrapperObj); - js::AutoValueRooter exposedProps(cx, JSVAL_VOID); + jsval exposedProps = JSVAL_VOID; + JSAutoTempValueRooter tvr(cx, 1, &exposedProps); - if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), exposedProps.addr())) { + if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), &exposedProps)) { return JS_FALSE; } if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot, v) || - !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, JSVAL_ZERO) || - !JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, - exposedProps.value())) { + !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, + JSVAL_ZERO) || + !JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, exposedProps)) { return JS_FALSE; } @@ -777,7 +778,7 @@ XPC_COW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our COW. jsval v = OBJECT_TO_JSVAL(wrappedObj); diff --git a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp index 3b9f5f60802..9a963148278 100644 --- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp +++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp @@ -40,7 +40,7 @@ #include "xpcprivate.h" #include "nsDOMError.h" #include "jsdbgapi.h" -#include "jscntxt.h" // For js::AutoValueRooter. +#include "jscntxt.h" // For JSAutoTempValueRooter. #include "XPCWrapper.h" #include "nsIDOMWindow.h" #include "nsIDOMWindowCollection.h" @@ -830,7 +830,7 @@ GetUXPCObject(JSContext *cx, JSObject *obj) return nsnull; } - js::AutoValueRooter tvr(cx, uxpco); + JSAutoTempValueRooter tvr(cx, uxpco); jsval wrappedObj, parentScope; if (!JS_GetReservedSlot(cx, obj, sWrappedObjSlot, &wrappedObj) || @@ -1206,7 +1206,7 @@ XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our XOW. jsval v = OBJECT_TO_JSVAL(wrappedObj); diff --git a/js/src/xpconnect/src/XPCNativeWrapper.cpp b/js/src/xpconnect/src/XPCNativeWrapper.cpp index c3fe67645fd..72daa9079c5 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.cpp +++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp @@ -1118,7 +1118,7 @@ XPC_NW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our native wrapper. XPCWrappedNative *wn = static_cast(JS_GetPrivate(cx, obj)); diff --git a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp index 074cb8e4594..a0ec10566de 100644 --- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp @@ -478,7 +478,7 @@ XPC_SJOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) NS_STACK_CLASS class SafeCallGuard { public: SafeCallGuard(JSContext *cx, nsIPrincipal *principal) - : cx(cx), tvr(cx) { + : cx(cx) { nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager(); if (ssm) { // Note: We pass null as the target frame pointer because we know that @@ -517,7 +517,7 @@ public: private: JSContext *cx; JSRegExpStatics statics; - js::AutoValueRooter tvr; + JSTempValueRooter tvr; uint32 options; JSStackFrame *fp; }; @@ -957,7 +957,7 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize the wrapper. return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, unsafeObj, diff --git a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp index b4c62f09aea..406adb39c32 100644 --- a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp +++ b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp @@ -40,7 +40,7 @@ #include "xpcprivate.h" #include "nsDOMError.h" #include "jsdbgapi.h" -#include "jscntxt.h" // For js::AutoValueRooter. +#include "jscntxt.h" // For JSAutoTempValueRooter. #include "XPCNativeWrapper.h" #include "XPCWrapper.h" @@ -137,7 +137,7 @@ WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp) } *vp = OBJECT_TO_JSVAL(wrapperObj); - js::AutoValueRooter tvr(cx, *vp); + JSAutoTempValueRooter tvr(cx, *vp); if (!JS_SetReservedSlot(cx, wrapperObj, sWrappedObjSlot, v) || !JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, JSVAL_ZERO)) { @@ -437,7 +437,7 @@ XPC_SOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, return JS_FALSE; } - js::AutoArrayRooter tvr(cx, 1, vp); + JSAutoTempValueRooter tvr(cx, 1, vp); JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { @@ -649,7 +649,7 @@ XPC_SOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our SOW. jsval v = OBJECT_TO_JSVAL(wrappedObj); diff --git a/js/src/xpconnect/src/XPCWrapper.cpp b/js/src/xpconnect/src/XPCWrapper.cpp index 2d3beb3a714..b6fc00c21d7 100644 --- a/js/src/xpconnect/src/XPCWrapper.cpp +++ b/js/src/xpconnect/src/XPCWrapper.cpp @@ -153,7 +153,7 @@ IteratorNext(JSContext *cx, uintN argc, jsval *vp) } jsval vec[2] = { STRING_TO_JSVAL(str), v }; - js::AutoArrayRooter tvr(cx, 2, vec); + JSAutoTempValueRooter tvr(cx, 2, vec); JSObject *array = JS_NewArrayObject(cx, 2, vec); if (!array) { return JS_FALSE; @@ -192,7 +192,7 @@ CreateIteratorObj(JSContext *cx, JSObject *tempWrapper, return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(iterObj)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(iterObj)); // Do this sooner rather than later to avoid complications in // IteratorFinalize. @@ -213,7 +213,7 @@ CreateIteratorObj(JSContext *cx, JSObject *tempWrapper, // call enumerate, and then re-set the prototype. As we do this, we have // to protec the temporary wrapper from garbage collection. - js::AutoValueRooter tvr(cx, tempWrapper); + JSAutoTempValueRooter tvr(cx, tempWrapper); if (!JS_SetPrototype(cx, iterObj, wrapperObj) || !XPCWrapper::Enumerate(cx, iterObj, wrapperObj) || !JS_SetPrototype(cx, iterObj, tempWrapper)) { diff --git a/js/src/xpconnect/src/qsgen.py b/js/src/xpconnect/src/qsgen.py index 0f7c90d485b..a3021f15b57 100644 --- a/js/src/xpconnect/src/qsgen.py +++ b/js/src/xpconnect/src/qsgen.py @@ -833,7 +833,7 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False): if isGetter: pthisval = 'vp' elif isSetter: - f.write(" js::AutoValueRooter tvr(cx);\n") + f.write(" JSAutoTempValueRooter tvr(cx);\n") pthisval = 'tvr.addr()' else: pthisval = '&vp[1]' # as above, ok to overwrite vp[1] diff --git a/js/src/xpconnect/src/xpcconvert.cpp b/js/src/xpconnect/src/xpcconvert.cpp index d4417a050bc..544990da4c6 100644 --- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -1582,23 +1582,23 @@ XPCConvert::ConstructException(nsresult rv, const char* message, /********************************/ -class AutoExceptionRestorer +class AutoExceptionRestorer : public JSAutoTempValueRooter { public: AutoExceptionRestorer(JSContext *cx, jsval v) - : mContext(cx), tvr(cx, v) + : JSAutoTempValueRooter(cx, v), + mVal(v) { JS_ClearPendingException(mContext); } ~AutoExceptionRestorer() { - JS_SetPendingException(mContext, tvr.value()); + JS_SetPendingException(mContext, mVal); } private: - JSContext * const mContext; - js::AutoValueRooter tvr; + jsval mVal; }; // static diff --git a/js/src/xpconnect/src/xpcquickstubs.cpp b/js/src/xpconnect/src/xpcquickstubs.cpp index d30e2ef6801..cc26a222021 100644 --- a/js/src/xpconnect/src/xpcquickstubs.cpp +++ b/js/src/xpconnect/src/xpcquickstubs.cpp @@ -173,7 +173,7 @@ GeneratePropertyOp(JSContext *cx, JSObject *obj, jsval idval, uintN argc, JSObject *funobj = JS_GetFunctionObject(fun); - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(funobj)); + JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(funobj)); // Unfortunately, we cannot guarantee that JSPropertyOp is aligned. Use a // second object to work around this. @@ -198,7 +198,7 @@ ReifyPropertyOps(JSContext *cx, JSObject *obj, jsval idval, jsid interned_id, { // Generate both getter and setter and stash them in the prototype. jsval roots[2] = { JSVAL_NULL, JSVAL_NULL }; - js::AutoArrayRooter tvr(cx, 2, roots); + JSAutoTempValueRooter tvr(cx, 2, roots); uintN attrs = JSPROP_SHARED; JSObject *getterobj; diff --git a/js/src/xpconnect/src/xpcquickstubs.h b/js/src/xpconnect/src/xpcquickstubs.h index 0943aab68a1..de2446cd243 100644 --- a/js/src/xpconnect/src/xpcquickstubs.h +++ b/js/src/xpconnect/src/xpcquickstubs.h @@ -321,7 +321,7 @@ struct xpc_qsArgValArray memset(array, 0, N * sizeof(jsval)); } - js::AutoArrayRooter tvr; + JSAutoTempValueRooter tvr; jsval array[N]; }; diff --git a/js/src/xpconnect/src/xpcwrappednativejsops.cpp b/js/src/xpconnect/src/xpcwrappednativejsops.cpp index 75964e97386..fb7e1192a64 100644 --- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp +++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp @@ -1517,7 +1517,8 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) JSStackFrame *fp; nsIPrincipal *principal = secMan->GetCxSubjectPrincipalAndFrame(cx, &fp); - js::AutoValueRooter retval(cx, obj); + jsval retval = OBJECT_TO_JSVAL(obj); + JSAutoTempValueRooter atvr(cx, 1, &retval); if(principal && fp) { @@ -1534,7 +1535,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) } nsresult rv = xpc->GetWrapperForObject(cx, obj, scope, principal, flags, - retval.addr()); + &retval); if(NS_FAILED(rv)) { XPCThrower::Throw(rv, cx); @@ -1542,7 +1543,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) } } - return JSVAL_TO_OBJECT(retval.value()); + return JSVAL_TO_OBJECT(retval); } JSObjectOps * diff --git a/js/src/xpconnect/tests/TestXPC.cpp b/js/src/xpconnect/tests/TestXPC.cpp index 5c69f4c7e03..b9e6e723b8c 100644 --- a/js/src/xpconnect/tests/TestXPC.cpp +++ b/js/src/xpconnect/tests/TestXPC.cpp @@ -562,7 +562,7 @@ TestArgFormatter(JSContext* jscontext, JSObject* glob, nsIXPConnect* xpc) // Prepare an array of arguments for JS_ConvertArguments jsval argv[5]; - js::AutoArrayRooter tvr(jscontext, JS_ARRAY_LENGTH(argv), argv); + JSAutoTempValueRooter tvr(jscontext, 5, argv); if (!PushArguments(jscontext, 5, argv, "s %ip %iv %is s", diff --git a/modules/plugin/base/src/nsJSNPRuntime.cpp b/modules/plugin/base/src/nsJSNPRuntime.cpp index c595fca8f70..22062d4765d 100644 --- a/modules/plugin/base/src/nsJSNPRuntime.cpp +++ b/modules/plugin/base/src/nsJSNPRuntime.cpp @@ -673,36 +673,36 @@ doInvoke(NPObject *npobj, NPIdentifier method, const NPVariant *args, } } + JSTempValueRooter tvr; + JS_PUSH_TEMP_ROOT(cx, 0, jsargs, &tvr); + + // Convert args + for (PRUint32 i = 0; i < argCount; ++i) { + jsargs[i] = NPVariantToJSVal(npp, cx, args + i); + ++tvr.count; + } + jsval v; JSBool ok; - { - js::AutoArrayRooter tvr(cx, 0, jsargs); + if (ctorCall) { + JSObject *global = ::JS_GetGlobalForObject(cx, npjsobj->mJSObj); + JSObject *newObj = + ::JS_ConstructObjectWithArguments(cx, JS_GET_CLASS(cx, npjsobj->mJSObj), + nsnull, global, argCount, jsargs); - // Convert args - for (PRUint32 i = 0; i < argCount; ++i) { - jsargs[i] = NPVariantToJSVal(npp, cx, args + i); - tvr.changeLength(i + 1); - } - - if (ctorCall) { - JSObject *global = ::JS_GetGlobalForObject(cx, npjsobj->mJSObj); - JSObject *newObj = - ::JS_ConstructObjectWithArguments(cx, JS_GET_CLASS(cx, npjsobj->mJSObj), - nsnull, global, argCount, jsargs); - - if (newObj) { - v = OBJECT_TO_JSVAL(newObj); - ok = JS_TRUE; - } else { - ok = JS_FALSE; - } + if (newObj) { + v = OBJECT_TO_JSVAL(newObj); + ok = JS_TRUE; } else { - ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs, &v); + ok = JS_FALSE; } - + } else { + ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs, &v); } + JS_POP_TEMP_ROOT(cx, &tvr); + if (jsargs != jsargs_buf) PR_Free(jsargs); @@ -837,7 +837,7 @@ nsJSObjWrapper::NP_SetProperty(NPObject *npobj, NPIdentifier identifier, AutoJSExceptionReporter reporter(cx); jsval v = NPVariantToJSVal(npp, cx, value); - js::AutoValueRooter tvr(cx, v); + JSAutoTempValueRooter tvr(cx, v); if (JSVAL_IS_STRING(id)) { JSString *str = JSVAL_TO_STRING(id); diff --git a/modules/plugin/base/src/nsNPAPIPlugin.cpp b/modules/plugin/base/src/nsNPAPIPlugin.cpp index ac912561d0d..92843fff99f 100644 --- a/modules/plugin/base/src/nsNPAPIPlugin.cpp +++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp @@ -1693,7 +1693,7 @@ _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result) // Root obj and the rval (below). jsval vec[] = { OBJECT_TO_JSVAL(obj), JSVAL_NULL }; - js::AutoArrayRooter tvr(cx, NS_ARRAY_LENGTH(vec), vec); + JSAutoTempValueRooter tvr(cx, NS_ARRAY_LENGTH(vec), vec); jsval *rval = &vec[1]; if (result) { diff --git a/xpinstall/src/nsXPITriggerInfo.cpp b/xpinstall/src/nsXPITriggerInfo.cpp index f35807655d1..98dceafa4f2 100644 --- a/xpinstall/src/nsXPITriggerInfo.cpp +++ b/xpinstall/src/nsXPITriggerInfo.cpp @@ -247,7 +247,7 @@ XPITriggerEvent::Run() // Build arguments into rooted jsval array jsval args[2] = { JSVAL_NULL, JSVAL_NULL }; - js::AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(args), args); + JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(args), args); // args[0] is the URL JSString *str = JS_NewUCStringCopyZ(cx, URL.get());