Backed out changeset e7065853ef79; I'll be repushing this incrementally, attempting to find the precise place where things go bad, in the near future. Happy days are here again! :-\
Backed out changeset e7065853ef79; I'll be repushing this incrementally, attempting to find the precise place where things go bad, in the near future. Happy days are here again! :-\
--- a/content/canvas/src/CustomQS_WebGL.h
+++ b/content/canvas/src/CustomQS_WebGL.h
@@ -63,17 +63,17 @@ nsICanvasRenderingContextWebGL_BufferDat
{
XPC_QS_ASSERT_CONTEXT_OK(cx);
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
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;
if (argc < 3)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
@@ -129,17 +129,17 @@ nsICanvasRenderingContextWebGL_BufferSub
{
XPC_QS_ASSERT_CONTEXT_OK(cx);
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
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;
if (argc < 3)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
@@ -199,17 +199,17 @@ nsICanvasRenderingContextWebGL_TexImage2
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
nsresult rv;
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;
if (argc < 3)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
@@ -301,17 +301,17 @@ nsICanvasRenderingContextWebGL_TexSubIma
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
nsresult rv;
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;
if (argc < 7 || (argc > 7 && argc < 9))
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
@@ -402,17 +402,17 @@ helper_nsICanvasRenderingContextWebGL_Un
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
nsresult rv;
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;
if (argc < 2)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
@@ -422,17 +422,17 @@ helper_nsICanvasRenderingContextWebGL_Un
if (!JSVAL_IS_OBJECT(argv[1])) {
xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1);
return JS_FALSE;
}
JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]);
- js::AutoValueRooter obj_tvr(cx);
+ JSAutoTempValueRooter obj_tvr(cx);
js::TypedArray *wa = 0;
if (helper_isInt32Array(arg1)) {
wa = js::TypedArray::fromJSObject(arg1);
} else if (JS_IsArrayObject(cx, arg1)) {
JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_INT32, arg1);
if (!nobj) {
@@ -472,17 +472,17 @@ helper_nsICanvasRenderingContextWebGL_Un
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
nsresult rv;
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;
if (argc < 2)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
@@ -492,17 +492,17 @@ helper_nsICanvasRenderingContextWebGL_Un
if (!JSVAL_IS_OBJECT(argv[1])) {
xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1);
return JS_FALSE;
}
JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]);
- js::AutoValueRooter obj_tvr(cx);
+ JSAutoTempValueRooter obj_tvr(cx);
js::TypedArray *wa = 0;
if (helper_isFloat32Array(arg1)) {
wa = js::TypedArray::fromJSObject(arg1);
} else if (JS_IsArrayObject(cx, arg1)) {
JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg1);
if (!nobj) {
@@ -542,17 +542,17 @@ helper_nsICanvasRenderingContextWebGL_Un
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
nsresult rv;
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;
if (argc < 3)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
@@ -566,17 +566,17 @@ helper_nsICanvasRenderingContextWebGL_Un
if (!JSVAL_IS_OBJECT(argv[2])) {
xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 2);
return JS_FALSE;
}
JSObject *arg2 = JSVAL_TO_OBJECT(argv[2]);
- js::AutoValueRooter obj_tvr(cx);
+ JSAutoTempValueRooter obj_tvr(cx);
js::TypedArray *wa = 0;
if (helper_isFloat32Array(arg2)) {
wa = js::TypedArray::fromJSObject(arg2);
} else if (JS_IsArrayObject(cx, arg2)) {
JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg2);
if (!nobj) {
@@ -613,17 +613,17 @@ helper_nsICanvasRenderingContextWebGL_Ve
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
nsresult rv;
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;
if (argc < 2)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
@@ -633,17 +633,17 @@ helper_nsICanvasRenderingContextWebGL_Ve
if (!JSVAL_IS_OBJECT(argv[1])) {
xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1);
return JS_FALSE;
}
JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]);
- js::AutoValueRooter obj_tvr(cx);
+ JSAutoTempValueRooter obj_tvr(cx);
js::TypedArray *wa = 0;
if (helper_isFloat32Array(arg1)) {
wa = js::TypedArray::fromJSObject(arg1);
} else if (JS_IsArrayObject(cx, arg1)) {
JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg1);
if (!nobj) {
@@ -775,17 +775,17 @@ helper_nsICanvasRenderingContextWebGL_Un
nsICanvasRenderingContextWebGL *self;
xpc_qsSelfRef selfref;
xpc_qsArgValArray<3> vp(cx);
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) {
js_SetTraceableNativeFailed(cx);
return JSVAL_VOID;
}
- js::AutoValueRooter obj_tvr(cx);
+ JSAutoTempValueRooter obj_tvr(cx);
js::TypedArray *wa = 0;
if (helper_isInt32Array(arg)) {
wa = js::TypedArray::fromJSObject(arg);
} else if (JS_IsArrayObject(cx, arg)) {
JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_INT32, arg);
if (!nobj) {
@@ -830,17 +830,17 @@ helper_nsICanvasRenderingContextWebGL_Un
nsICanvasRenderingContextWebGL *self;
xpc_qsSelfRef selfref;
xpc_qsArgValArray<3> vp(cx);
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) {
js_SetTraceableNativeFailed(cx);
return JSVAL_VOID;
}
- js::AutoValueRooter obj_tvr(cx);
+ JSAutoTempValueRooter obj_tvr(cx);
js::TypedArray *wa = 0;
if (helper_isFloat32Array(arg)) {
wa = js::TypedArray::fromJSObject(arg);
} else if (JS_IsArrayObject(cx, arg)) {
JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg);
if (!nobj) {
@@ -885,17 +885,17 @@ helper_nsICanvasRenderingContextWebGL_Un
nsICanvasRenderingContextWebGL *self;
xpc_qsSelfRef selfref;
xpc_qsArgValArray<4> vp(cx);
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) {
js_SetTraceableNativeFailed(cx);
return JSVAL_VOID;
}
- js::AutoValueRooter obj_tvr(cx);
+ JSAutoTempValueRooter obj_tvr(cx);
js::TypedArray *wa = 0;
if (helper_isFloat32Array(arg)) {
wa = js::TypedArray::fromJSObject(arg);
} else if (JS_IsArrayObject(cx, arg)) {
JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg);
if (!nobj) {
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2106,23 +2106,24 @@ nsJSContext::CallEventHandler(nsISupport
nsIArray *aargv, nsIVariant **arv)
{
NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
if (!mScriptsEnabled) {
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;
// This one's a lot easier than EvaluateString because we don't have to
// hassle with principals: they're already compiled into the JS function.
// xxxmarkh - this comment is no longer true - principals are not used at
// all now, and never were in some cases.
@@ -2137,17 +2138,17 @@ nsJSContext::CallEventHandler(nsISupport
nsJSContext::TerminationFuncHolder holder(this);
if (NS_SUCCEEDED(rv)) {
// Convert args to jsvals.
PRUint32 argc = 0;
jsval *argv = nsnull;
js::LazilyConstructed<nsAutoPoolRelease> poolRelease;
- js::LazilyConstructed<js::AutoArrayRooter> tvr;
+ js::LazilyConstructed<JSAutoTempValueRooter> 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
// was OK because those typically have PreCreate methods that give them the
// right scope anyway, and we want to make sure that the arguments end up
// in the same scope as aTarget.
rv = ConvertSupportsTojsvals(aargv, target, &argc,
&argv, poolRelease, tvr);
@@ -2649,17 +2650,17 @@ nsresult
nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArgs)
{
PRUint32 argc;
jsval *argv = nsnull;
JSAutoRequest ar(mContext);
js::LazilyConstructed<nsAutoPoolRelease> poolRelease;
- js::LazilyConstructed<js::AutoArrayRooter> tvr;
+ js::LazilyConstructed<JSAutoTempValueRooter> tvr;
nsresult rv;
rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc,
&argv, poolRelease, tvr);
NS_ENSURE_SUCCESS(rv, rv);
jsval vargs;
@@ -2684,17 +2685,17 @@ nsJSContext::SetProperty(void *aTarget,
}
nsresult
nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs,
void *aScope,
PRUint32 *aArgc,
jsval **aArgv,
js::LazilyConstructed<nsAutoPoolRelease> &aPoolRelease,
- js::LazilyConstructed<js::AutoArrayRooter> &aRooter)
+ js::LazilyConstructed<JSAutoTempValueRooter> &aRooter)
{
nsresult rv = NS_OK;
// If the array implements nsIJSArgArray, just grab the values directly.
nsCOMPtr<nsIJSArgArray> fastArray = do_QueryInterface(aArgs);
if (fastArray != nsnull)
return fastArray->GetArgs(aArgc, reinterpret_cast<void **>(aArgv));
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -44,21 +44,18 @@
#include "nsIObserver.h"
#include "nsIXPCScriptNotify.h"
#include "prtime.h"
#include "nsCycleCollectionParticipant.h"
#include "nsScriptNameSpaceManager.h"
class nsIXPConnectJSObjectHolder;
class nsAutoPoolRelease;
-namespace js {
-class AutoValueRooter;
-class AutoArrayRooter;
-template <class> class LazilyConstructed;
-}
+class JSAutoTempValueRooter;
+namespace js { template <class> class LazilyConstructed; }
class nsJSContext : public nsIScriptContext,
public nsIXPCScriptNotify
{
public:
nsJSContext(JSRuntime *aRuntime);
virtual ~nsJSContext();
@@ -213,17 +210,17 @@ protected:
nsresult InitializeExternalClasses();
// Helper to convert xpcom datatypes to jsvals.
nsresult ConvertSupportsTojsvals(nsISupports *aArgs,
void *aScope,
PRUint32 *aArgc,
jsval **aArgv,
js::LazilyConstructed<nsAutoPoolRelease> &aPoolRelease,
- js::LazilyConstructed<js::AutoArrayRooter> &aRooter);
+ js::LazilyConstructed<JSAutoTempValueRooter> &aRooter);
nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv);
// given an nsISupports object (presumably an event target or some other
// DOM object), get (or create) the JSObject wrapping it.
nsresult JSObjectFromInterface(nsISupports *aSup, void *aScript,
JSObject **aRet);
--- a/js/ctypes/Function.cpp
+++ b/js/ctypes/Function.cpp
@@ -619,17 +619,17 @@ Function::Create(JSContext* aContext,
// create and root the new JS function object
JSFunction* fn = JS_NewFunction(aContext, JSNative(Function::Call),
aArgLength, JSFUN_FAST_NATIVE, NULL, aName);
if (!fn)
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())))
return NULL;
// make a strong reference to the library for GC-safety
if (!JS_SetReservedSlot(aContext, fnObj, 1, OBJECT_TO_JSVAL(aLibrary)))
return NULL;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -433,63 +433,63 @@ JS_ValueToSource(JSContext *cx, jsval v)
return js_ValueToSource(cx, v);
}
JS_PUBLIC_API(JSBool)
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());
}
JS_PUBLIC_API(JSBool)
JS_DoubleIsInt32(jsdouble d, jsint *ip)
{
return JSDOUBLE_IS_INT(d, *ip);
}
JS_PUBLIC_API(JSBool)
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());
}
JS_PUBLIC_API(JSBool)
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());
}
JS_PUBLIC_API(JSBool)
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());
}
JS_PUBLIC_API(JSBool)
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());
}
JS_PUBLIC_API(JSBool)
JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
{
CHECK_REQUEST(cx);
@@ -3054,17 +3054,17 @@ LookupResult(JSContext *cx, JSObject *ob
return JS_TRUE;
}
JSBool ok = JS_TRUE;
if (OBJ_IS_NATIVE(obj2)) {
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);
}
/* Peek at the native property's slot value, without doing a Get. */
*vp = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2))
? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot)
@@ -3805,28 +3805,29 @@ JS_ClearScope(JSContext *cx, JSObject *o
JS_SetReservedSlot(cx, obj, key, JSVAL_VOID);
}
}
JS_PUBLIC_API(JSIdArray *)
JS_Enumerate(JSContext *cx, JSObject *obj)
{
jsint i, n;
+ jsval iter_state, num_properties;
jsid id;
JSIdArray *ida;
jsval *vector;
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);
goto error;
}
/* Grow as needed if we don't know the exact amount ahead of time. */
n = JSVAL_TO_INT(num_properties);
@@ -3836,34 +3837,36 @@ JS_Enumerate(JSContext *cx, JSObject *ob
/* Create an array of jsids large enough to hold all the properties */
ida = NewIdArray(cx, n);
if (!ida)
goto error;
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) {
ida = SetIdArrayLength(cx, ida, ida->length * 2);
if (!ida)
goto error;
vector = &ida->vector[0];
}
vector[i++] = id;
}
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;
}
/*
* XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
* prop_iterator_class somehow...
@@ -3937,17 +3940,17 @@ JS_NewPropertyIterator(JSContext *cx, JS
index = -1;
} else {
/*
* Non-native case: enumerate a JSIdArray and keep it via private.
*
* 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;
pdata = ida;
index = ida->length;
}
/* iterobj cannot escape to other threads here. */
@@ -4587,37 +4590,35 @@ JS_CompileFileHandleForPrincipals(JSCont
NULL, 0, file, filename, 1);
LAST_FRAME_CHECKS(cx, script);
return script;
}
JS_PUBLIC_API(JSObject *)
JS_NewScriptObject(JSContext *cx, JSScript *script)
{
+ JSTempValueRooter tvr;
JSObject *obj;
CHECK_REQUEST(cx);
if (!script)
return js_NewObject(cx, &js_ScriptClass, NULL, NULL);
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;
}
JS_PUBLIC_API(JSObject *)
JS_GetScriptObject(JSScript *script)
{
return script->u.object;
}
@@ -4685,16 +4686,17 @@ JS_CompileUCFunction(JSContext *cx, JSOb
JS_PUBLIC_API(JSFunction *)
JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
JSPrincipals *principals, const char *name,
uintN nargs, const char **argnames,
const jschar *chars, size_t length,
const char *filename, uintN lineno)
{
JSFunction *fun;
+ JSTempValueRooter tvr;
JSAtom *funAtom, *argAtom;
uintN i;
CHECK_REQUEST(cx);
if (!name) {
funAtom = NULL;
} else {
funAtom = js_Atomize(cx, name, strlen(name), 0);
@@ -4702,58 +4704,57 @@ JS_CompileUCFunctionForPrincipals(JSCont
fun = NULL;
goto out2;
}
}
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
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;
- }
+ 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 (!JSCompiler::compileFunctionBody(cx, fun, principals,
- chars, length, filename, lineno)) {
+ if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) {
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;
- }
+ }
+
+ 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;
-
- while ((pobj = pobj->getParent()) != NULL)
- ++depth;
- JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
- }
+ if (fun && obj) {
+ JSObject *pobj = obj;
+ uintN depth = 1;
+
+ 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);
return fun;
}
JS_PUBLIC_API(JSString *)
JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
@@ -4931,17 +4932,17 @@ JS_CallFunction(JSContext *cx, JSObject
}
JS_PUBLIC_API(JSBool)
JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
jsval *argv, jsval *rval)
{
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),
JSGET_NO_METHOD_BARRIER, tvr.addr()) &&
js_InternalCall(cx, obj, tvr.value(), argc, argv, rval);
LAST_FRAME_CHECKS(cx, ok);
return ok;
}
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -226,17 +226,17 @@ ValueIsLength(JSContext *cx, jsval* vp)
JSBool
js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
{
if (obj->isArray()) {
*lengthp = obj->fslots[JSSLOT_ARRAY_LENGTH];
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;
if (JSVAL_IS_INT(tvr.value())) {
*lengthp = jsuint(jsint(JSVAL_TO_INT(tvr.value()))); /* jsuint cast does ToUint32 */
return JS_TRUE;
}
@@ -400,17 +400,17 @@ EnsureCapacity(JSContext *cx, JSObject *
}
}
return JS_TRUE;
}
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;
}
return JS_TRUE;
}
static bool
@@ -445,17 +445,17 @@ GetArrayElement(JSContext *cx, JSObject
{
JS_ASSERT(index >= 0);
if (obj->isDenseArray() && index < js_DenseArrayCapacity(obj) &&
(*vp = obj->dslots[jsuint(index)]) != JSVAL_HOLE) {
*hole = JS_FALSE;
return JS_TRUE;
}
- AutoIdRooter idr(cx);
+ JSAutoTempIdRooter idr(cx);
*hole = JS_FALSE;
if (!IndexToId(cx, obj, index, hole, idr.addr()))
return JS_FALSE;
if (*hole) {
*vp = JSVAL_VOID;
return JS_TRUE;
}
@@ -500,17 +500,17 @@ SetArrayElement(JSContext *cx, JSObject
return JS_TRUE;
}
}
if (!js_MakeArraySlow(cx, obj))
return JS_FALSE;
}
- AutoIdRooter idr(cx);
+ JSAutoTempIdRooter idr(cx);
if (!IndexToId(cx, obj, index, NULL, idr.addr(), JS_TRUE))
return JS_FALSE;
JS_ASSERT(!JSVAL_IS_VOID(idr.id()));
return obj->setProperty(cx, idr.id(), &v);
}
@@ -526,17 +526,17 @@ DeleteArrayElement(JSContext *cx, JSObje
obj->fslots[JSSLOT_ARRAY_COUNT]--;
obj->dslots[idx] = JSVAL_HOLE;
return JS_TRUE;
}
}
return JS_TRUE;
}
- AutoIdRooter idr(cx);
+ JSAutoTempIdRooter idr(cx);
if (!IndexToId(cx, obj, index, NULL, idr.addr()))
return JS_FALSE;
if (JSVAL_IS_VOID(idr.id()))
return JS_TRUE;
jsval junk;
return obj->deleteProperty(cx, idr.id(), &junk);
@@ -568,17 +568,17 @@ js_SetLengthProperty(JSContext *cx, JSOb
id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
return obj->setProperty(cx, id, &v);
}
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);
if (!ok)
return false;
*lengthp = ValueIsLength(cx, tvr.addr());
return !JSVAL_IS_NULL(tvr.value());
@@ -621,80 +621,90 @@ array_length_getter(JSContext *cx, JSObj
return JS_TRUE;
}
static JSBool
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);
return obj->defineProperty(cx, lengthId, *vp, NULL, NULL, JSPROP_ENUMERATE);
}
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 {
/*
* We are going to remove a lot of indexes in a presumably sparse
* array. So instead of looping through indexes between newlen and
* oldlen, we iterate through all properties and remove those that
* 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;
}
/*
* We have only indexed properties up to capacity (excepting holes), plus the
* length property. For all else, we delegate to the prototype.
*/
static inline bool
IsDenseArrayId(JSContext *cx, JSObject *obj, jsid id)
@@ -1503,17 +1513,17 @@ array_toString_sub(JSContext *cx, JSObje
}
genBefore = cx->busyArrays.generation();
} else {
/* Cycle, so return empty string. */
*rval = ATOM_KEY(cx->runtime->atomState.emptyAtom);
return true;
}
- AutoValueRooter tvr(cx, obj);
+ JSAutoTempValueRooter tvr(cx, obj);
/* After this point, all paths exit through the 'out' label. */
MUST_FLOW_THROUGH("out");
bool ok = false;
/* Get characters to use for the separator. */
static const jschar comma = ',';
const jschar *sep;
@@ -1637,17 +1647,17 @@ InitArrayElements(JSContext *cx, JSObjec
* wouldn't otherwise make the array slow.
*/
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
start <= MAXINDEX - count && !INDEX_TOO_BIG(start + count)) {
#ifdef DEBUG_jwalden
{
/* Verify that overwriteType and writeType were accurate. */
- AutoIdRooter idr(cx);
+ JSAutoTempIdRooter idr(cx, JSVAL_ZERO);
for (jsuint i = 0; i < count; i++) {
JS_ASSERT_IF(vectorType == SourceVectorAllValues, vector[i] != JSVAL_HOLE);
jsdouble index = jsdouble(start) + i;
if (targetType == TargetElementsAllHoles && index < jsuint(-1)) {
JS_ASSERT(ReallyBigIndexToId(cx, index, idr.addr()));
JSObject* obj2;
JSProperty* prop;
@@ -1703,22 +1713,22 @@ InitArrayElements(JSContext *cx, JSObjec
return JS_TRUE;
/* Finish out any remaining elements past the max array index. */
if (obj->isDenseArray() && !ENSURE_SLOW_ARRAY(cx, obj))
return JS_FALSE;
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()) ||
!obj->setProperty(cx, idr.id(), &tmp[1])) {
return JS_FALSE;
}
*dp += 1;
} while (vector != end);
@@ -1754,28 +1764,28 @@ InitArrayObject(JSContext *cx, JSObject
}
return JS_TRUE;
}
#ifdef JS_TRACER
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;
}
return JSVAL_TO_STRING(tvr.value());
}
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;
}
return JSVAL_TO_STRING(tvr.value());
}
#endif
@@ -1837,17 +1847,17 @@ array_reverse(JSContext *cx, uintN argc,
/*
* Per ECMA-262, don't update the length of the array, even if the new
* array has trailing holes (and thus the original array began with
* holes).
*/
return JS_TRUE;
}
- 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) ||
!GetArrayElement(cx, obj, i, &hole, tvr.addr()) ||
!GetArrayElement(cx, obj, len - i - 1, &hole2, vp) ||
!SetOrDeleteArrayElement(cx, obj, len - i - 1, hole, tvr.value()) ||
!SetOrDeleteArrayElement(cx, obj, i, hole2, *vp)) {
return false;
@@ -2087,254 +2097,277 @@ sort_compare_strings(void *arg, const vo
* perform initialization using memset. Other parts of SpiderMonkey likewise
* "know" that JSVAL_NULL is zero; this static assertion covers all cases.
*/
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;
}
/*
* We need a temporary array of 2 * len jsvals to hold the array elements
* and the scratch space for merge sort. Check that its size does not
* overflow size_t, which would allow for indexing beyond the end of the
* 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
* exist, allowing OS to avoiding committing RAM. See bug 330812.
*
* 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;
-
- struct AutoFreeVector {
- AutoFreeVector(JSContext *cx, jsval *&vec) : cx(cx), vec(vec) { }
- ~AutoFreeVector() {
- cx->free(vec);
- }
- JSContext * const cx;
- jsval *&vec;
- } free(cx, vec);
-
- AutoArrayRooter tvr(cx, 0, vec);
-
+ JS_PUSH_TEMP_ROOT(cx, 0, vec, &tvr);
+
+ /*
+ * 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;
+
+ /* 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;
+
+ if (hole)
+ continue;
+
+ if (JSVAL_IS_VOID(vec[newlen])) {
+ ++undefs;
+ continue;
+ }
+
+ /* 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) {
/*
- * 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.
+ * Sort using the default comparator converting all elements to
+ * strings.
*/
- undefs = 0;
- newlen = 0;
- bool allStrings = true;
- for (i = 0; i < len; i++) {
- if (!JS_CHECK_OPERATION_LIMIT(cx))
- return false;
-
- /* 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 (newlen == 0)
- return true; /* The array has only holes and undefs. */
-
- /*
- * 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.
- */
- 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;
+ vec[2 * i] = STRING_TO_JSVAL(str);
+ vec[2 * i + 1] = v;
+ } while (i != 0);
+
+ JS_ASSERT(tvr.u.array == vec);
+ vec = (jsval *) cx->realloc(vec,
+ 4 * (size_t) newlen * sizeof(jsval));
+ if (!vec) {
+ vec = tvr.u.array;
+ ok = JS_FALSE;
+ goto out;
}
- if (!allStrings) {
- /*
- * We want to make the following loop fast and to unroot the
- * cached results of toString invocations before the operation
- * callback has a chance to run the GC. For this reason we do
- * not call JS_CHECK_OPERATION_LIMIT in the loop.
- */
- i = 0;
- do {
- vec[i] = vec[2 * i + 1];
- } while (++i != newlen);
- }
- } else {
- void *mark;
-
- LeaveTrace(cx);
-
- 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;
+ tvr.u.array = vec;
+ mergesort_tmp = vec + 2 * newlen;
+ memset(mergesort_tmp, 0, newlen * 2 * sizeof(jsval));
+ tvr.count = newlen * 4;
+ elemsize = 2 * sizeof(jsval);
+ }
+ ok = js_MergeSort(vec, (size_t) newlen, elemsize,
+ sort_compare_strings, cx, mergesort_tmp);
+ if (!ok)
+ goto out;
+ if (!all_strings) {
+ /*
+ * We want to make the following loop fast and to unroot the
+ * cached results of toString invocations before the operation
+ * callback has a chance to run the GC. For this reason we do
+ * not call JS_CHECK_OPERATION_LIMIT in the loop.
+ */
+ i = 0;
+ do {
+ vec[i] = vec[2 * i + 1];
+ } while (++i != newlen);
}
-
- /*
- * 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;
+ } 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;
}
/*
* Perl-inspired push, pop, shift, unshift, and splice methods.
*/
static JSBool
array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
@@ -2398,17 +2431,17 @@ js_ArrayCompPush(JSContext *cx, JSObject
}
JS_DEFINE_CALLINFO_3(extern, BOOL, js_ArrayCompPush, CONTEXT, OBJECT, JSVAL, 0,
nanojit::ACC_STORE_ANY)
#ifdef JS_TRACER
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())) {
return tvr.value();
}
SetBuiltinError(cx);
return JSVAL_VOID;
}
@@ -2470,17 +2503,17 @@ array_pop_dense(JSContext *cx, JSObject*
obj->fslots[JSSLOT_ARRAY_LENGTH] = index;
return JS_TRUE;
}
#ifdef JS_TRACER
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())) {
return tvr.value();
}
SetBuiltinError(cx);
return JSVAL_VOID;
}
@@ -2534,17 +2567,17 @@ array_shift(JSContext *cx, uintN argc, j
*vp = JSVAL_VOID;
}
} else {
/* Get the to-be-deleted property's value into vp ASAP. */
if (!GetArrayElement(cx, obj, 0, &hole, vp))
return JS_FALSE;
/* Slide down the array above the first element. */
- 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()) ||
!SetOrDeleteArrayElement(cx, obj, i, hole, tvr.value())) {
return JS_FALSE;
}
}
@@ -2579,17 +2612,17 @@ array_unshift(JSContext *cx, uintN argc,
if (!EnsureCapacity(cx, obj, length + argc))
return JS_FALSE;
memmove(obj->dslots + argc, obj->dslots, length * sizeof(jsval));
for (uint32 i = 0; i < argc; i++)
obj->dslots[i] = JSVAL_HOLE;
} else {
last = length;
jsdouble upperIndex = last + argc;
- AutoValueRooter tvr(cx);
+ JSAutoTempValueRooter tvr(cx, JSVAL_NULL);
do {
--last, --upperIndex;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
!SetOrDeleteArrayElement(cx, obj, upperIndex, hole, tvr.value())) {
return JS_FALSE;
}
} while (last != 0);
@@ -2669,17 +2702,17 @@ array_splice(JSContext *cx, uintN argc,
else if (d > delta)
d = delta;
count = (jsuint)d;
end = begin + count;
argc--;
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) {
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
!js_PrototypeHasIndexedProperties(cx, obj2) &&
end <= js_DenseArrayCapacity(obj)) {
if (!InitArrayObject(cx, obj2, count, obj->dslots + begin,
obj->fslots[JSSLOT_ARRAY_COUNT] !=
@@ -2808,17 +2841,17 @@ array_concat(JSContext *cx, uintN argc,
} else {
nobj = js_NewArrayObject(cx, 0, NULL);
if (!nobj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(nobj);
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++) {
if (!JS_CHECK_OPERATION_LIMIT(cx))
return false;
v = argv[i];
if (!JSVAL_IS_PRIMITIVE(v)) {
JSObject *wobj;
@@ -2922,17 +2955,17 @@ array_slice(JSContext *cx, uintN argc, j
}
/* Create a new Array object and root it using *vp. */
nobj = js_NewArrayObject(cx, 0, NULL);
if (!nobj)
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())) {
return JS_FALSE;
}
if (!hole && !SetArrayElement(cx, nobj, slot - begin, tvr.value()))
return JS_FALSE;
}
@@ -3432,31 +3465,33 @@ js_InitArrayClass(JSContext *cx, JSObjec
if (!proto || !InitArrayObject(cx, proto, 0, NULL))
return NULL;
return proto;
}
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;
/*
* If this fails, the global object was not initialized and its class does
* not have JSCLASS_IS_GLOBAL.
*/
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;
return obj;
}
JSObject *
js_NewSlowArrayObject(JSContext *cx)
@@ -3562,17 +3597,17 @@ js_CoerceArrayToCanvasImageData(JSObject
JS_FRIEND_API(JSObject *)
js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector)
{
JSObject *obj = js_NewArrayObject(cx, capacity, NULL);
if (!obj)
return NULL;
- AutoValueRooter tvr(cx, obj);
+ JSAutoTempValueRooter tvr(cx, obj);
if (!EnsureCapacity(cx, obj, capacity, JS_FALSE))
obj = NULL;
/* Set/clear newborn root, in case we lost it. */
cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
if (!obj)
return NULL;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1156,33 +1156,120 @@ typedef struct JSResolvingKey {
typedef struct JSResolvingEntry {
JSDHashEntryHdr hdr;
JSResolvingKey key;
uint32 flags;
} 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_<KIND>(cx, NULL, &tvr). Then &tvr.u.<kind> 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.<gcthing> 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 */
/*
* Wraps a stack frame which has been temporarily popped from its call stack
* and needs to be GC-reachable. See JSContext::{push,pop}GCReachableFrame.
*/
struct JSGCReachableFrame {
JSGCReachableFrame *next;
JSStackFrame *frame;
};
-namespace js {
-class AutoGCRooter;
-}
-
struct JSContext
{
explicit JSContext(JSRuntime *rt) : runtime(rt), busyArrays(this) {}
/*
* If this flag is set, we were asked to call back the operation callback
* as soon as possible.
*/
@@ -1374,18 +1461,18 @@ struct JSContext
#define CX_FROM_THREAD_LINKS(tl) \
((JSContext *)((char *)(tl) - offsetof(JSContext, threadLinks)))
#endif
/* 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;
/* Security callbacks that override any defined on the runtime. */
JSSecurityCallbacks *securityCallbacks;
/* Pinned regexp pool used for regular expressions. */
@@ -1612,360 +1699,161 @@ JSStackFrame::varobj(JSContext *cx)
static inline JSAtom **
FrameAtomBase(JSContext *cx, JSStackFrame *fp)
{
return fp->imacpc
? COMMON_ATOMS_START(&cx->runtime->atomState)
: fp->script->atomMap.vector;
}
-namespace js {
-
-class AutoGCRooter {
- public:
- AutoGCRooter(JSContext *cx, ptrdiff_t tag)
- : down(cx->autoGCRooters), tag(tag), context(cx)
- {
- JS_ASSERT(this != cx->autoGCRooters);
- cx->autoGCRooters = this;
- }
-
- ~AutoGCRooter() {
- JS_ASSERT(this == context->autoGCRooters);
- context->autoGCRooters = down;
- }
-
- inline void trace(JSTracer *trc);
-
- friend void ::js_TraceContext(JSTracer *trc, JSContext *acx);
-
- protected:
- AutoGCRooter * const down;
-
- /*
- * 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 */
- };
-};
-
-class AutoSaveWeakRoots : private AutoGCRooter
+/* FIXME(bug 332648): Move this into a public header. */
+class JSAutoTempValueRooter
{
public:
- explicit AutoSaveWeakRoots(JSContext *cx
- JS_GUARD_OBJECT_NOTIFIER_PARAM)
- : AutoGCRooter(cx, WEAKROOTS), savedRoots(cx->weakRoots)
- {
+ 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);
}
- friend void AutoGCRooter::trace(JSTracer *trc);
-
- private:
- JSWeakRoots savedRoots;
- JS_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
-/* FIXME(bug 332648): Move this into a public header. */
-class AutoValueRooter : private AutoGCRooter
-{
- 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;
+ ~JSAutoTempValueRooter() {
+ JS_POP_TEMP_ROOT(mContext, &mTvr);
}
- 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);
- }
+ jsval value() { return mTvr.u.value; }
+ jsval *addr() { return &mTvr.u.value; }
- 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);
+ protected:
+ JSContext *mContext;
private:
- jsval val;
+ JSTempValueRooter mTvr;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
-class AutoObjectRooter : private AutoGCRooter {
+class JSAutoTempIdRooter
+{
public:
- AutoObjectRooter(JSContext *cx, JSObject *obj = NULL
- JS_GUARD_OBJECT_NOTIFIER_PARAM)
- : AutoGCRooter(cx, OBJECT), obj(obj)
- {
+ 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);
}
- void setObject(JSObject *obj) {
- this->obj = obj;
+ ~JSAutoTempIdRooter() {
+ JS_POP_TEMP_ROOT(mContext, &mTvr);
}
- JSObject * object() const {
- return obj;
- }
-
- JSObject ** addr() {
- return &obj;
- }
-
- friend void AutoGCRooter::trace(JSTracer *trc);
+ jsid id() { return (jsid) mTvr.u.value; }
+ jsid * addr() { return (jsid *) &mTvr.u.value; }
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:
+ JSContext *mContext;
+ JSTempValueRooter mTvr;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
-class AutoScopePropertyRooter : private AutoGCRooter {
+class JSAutoIdArray {
public:
- AutoScopePropertyRooter(JSContext *cx, JSScopeProperty *sprop
- JS_GUARD_OBJECT_NOTIFIER_PARAM)
- : AutoGCRooter(cx, SPROP), sprop(sprop)
- {
+ JSAutoIdArray(JSContext *cx, JSIdArray *ida
+ JS_GUARD_OBJECT_NOTIFIER_PARAM)
+ : cx(cx), idArray(ida) {
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;
+ if (ida)
+ JS_PUSH_TEMP_ROOT(cx, ida->length, ida->vector, &tvr);
}
-
- 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
- JS_GUARD_OBJECT_NOTIFIER_PARAM)
- : AutoGCRooter(cx, ida ? ida->length : 0), idArray(ida)
- {
- JS_GUARD_OBJECT_NOTIFIER_INIT;
- }
- ~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;
}
jsid operator[](size_t i) const {
JS_ASSERT(idArray);
JS_ASSERT(i < size_t(idArray->length));
return idArray->vector[i];
}
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);
- }
- }
-
- 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);
+ ~JSAutoEnumStateRooter() {
+ JS_POP_TEMP_ROOT(mContext, this);
}
- JSObject * const obj;
+ void mark(JSTracer *trc) {
+ JS_CALL_OBJECT_TRACER(trc, u.object, "enumerator_obj");
+ js_MarkEnumeratorState(trc, u.object, *mStatep);
+ }
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;
}
~JSAutoResolveFlags() { mContext->resolveFlags = mSaved; }
private:
JSContext *mContext;
deleted file mode 100644
--- 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 <jwalden+code@mit.edu> (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<AutoValueRooter *>(this)->val);
- return;
-
- case SPROP:
- static_cast<AutoScopePropertyRooter *>(this)->sprop->trace(trc);
- return;
-
- case WEAKROOTS:
- static_cast<AutoSaveWeakRoots *>(this)->savedRoots.mark(trc);
- return;
-
- case COMPILER:
- static_cast<JSCompiler *>(this)->trace(trc);
- return;
-
- case SCRIPT:
- if (JSScript *script = static_cast<AutoScriptRooter *>(this)->script)
- js_TraceScript(trc, script);
- return;
-
- case ENUMERATOR:
- static_cast<AutoEnumStateRooter *>(this)->trace(trc);
- return;
-
- case IDARRAY: {
- JSIdArray *ida = static_cast<AutoIdArray *>(this)->idArray;
- TraceValues(trc, ida->length, ida->vector, "js::AutoIdArray.idArray");
- return;
- }
-
- case DESCRIPTORS: {
- PropertyDescriptorArray &descriptors =
- static_cast<AutoDescriptorArray *>(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<AutoNamespaces *>(this)->array;
- TraceObjectVector(trc, reinterpret_cast<JSObject **>(array.vector), array.length);
- array.cursors->trace(trc);
- return;
- }
-
- case XML:
- js_TraceXML(trc, static_cast<AutoXMLRooter *>(this)->xml);
- return;
-
- case OBJECT:
- if (JSObject *obj = static_cast<AutoObjectRooter *>(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<AutoIdRooter *>(this)->idval);
- return;
- }
-
- JS_ASSERT(tag >= 0);
- TraceValues(trc, tag, static_cast<AutoArrayRooter *>(this)->array, "js::AutoArrayRooter.array");
-}
-
-}
-
-#endif /* jscntxtinlines_h___ */
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -1460,18 +1460,18 @@ JS_PropertyIterator(JSObject *obj, JSSco
}
JS_PUBLIC_API(JSBool)
JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
JSPropertyDesc *pd)
{
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)) {
if (!cx->throwing) {
pd->flags = JSPD_ERROR;
pd->value = JSVAL_VOID;
} else {
pd->flags = JSPD_EXCEPTION;
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -58,18 +58,16 @@
#include "jsinterp.h"
#include "jsnum.h"
#include "jsobj.h"
#include "jsopcode.h"
#include "jsscope.h"
#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);
static void
exn_trace(JSTracer *trc, JSObject *obj);
static void
@@ -821,129 +819,141 @@ exn_toString(JSContext *cx, uintN argc,
* Return a string that may eval to something similar to the original object.
*/
static JSBool
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;
- }
- localroots[0] = STRING_TO_JSVAL(message);
-
- if (!JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) ||
- !(filename = js_ValueToSource(cx, localroots[1]))) {
- return false;
- }
- localroots[1] = STRING_TO_JSVAL(filename);
+ 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);
- 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;
+ 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);
- 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;
+ 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;
- 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;
- }
+ if (lineno != 0) {
+ lineno_as_str = js_ValueToString(cx, localroots[2]);
+ if (!lineno_as_str) {
+ ok = JS_FALSE;
+ goto out;
}
-
- cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar));
- if (!chars)
- return false;
+ lineno_length = lineno_as_str->length();
+ } else {
+ lineno_as_str = NULL;
+ lineno_length = 0;
+ }
- *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;
- }
+ /* Magic 8, for the characters in ``(new ())''. */
+ name_length = name->length();
+ message_length = message->length();
+ length = 8 + name_length + 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;
+ }
+ } else {
+ if (lineno_as_str) {
+ /*
+ * no filename, but have line number,
+ * need to append ``, "", {lineno_as_str}''
+ */
+ length += 6 + lineno_length;
}
+ }
- *cp++ = ')'; *cp++ = ')'; *cp = 0;
+ 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;
+ }
- result = js_NewString(cx, chars, length);
- if (!result) {
- cx->free(chars);
- return false;
+ 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++ = '"';
}
- *vp = STRING_TO_JSVAL(result);
- return true;
+ }
+ 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
static JSFunctionSpec exception_methods[] = {
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, exn_toSource, 0,0),
#endif
JS_FN(js_toString_str, exn_toString, 0,0),
@@ -984,17 +994,17 @@ js_InitExceptionClasses(JSContext *cx, J
*
* See the equivalent code to ensure that parent_proto is non-null when
* JS_InitClass calls js_NewObject, in jsapi.c.
*/
if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto))
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 */
#endif
/* Initialize the prototypes first. */
for (intN i = JSEXN_ERR; i != JSEXN_LIMIT; i++) {
JSObject *proto;
@@ -1094,16 +1104,17 @@ static struct exnname { char *name; char
JSBool
js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp,
JSErrorCallback callback, void *userRef)
{
JSErrNum errorNumber;
const JSErrorFormatString *errorString;
JSExnType exn;
jsval tv[4];
+ JSTempValueRooter tvr;
JSBool ok;
JSObject *errProto, *errObject;
JSString *messageStr, *filenameStr;
/*
* Tell our caller to report immediately if this report is just a warning.
*/
JS_ASSERT(reportp);
@@ -1142,17 +1153,17 @@ js_ErrorToException(JSContext *cx, const
if (cx->generatingError)
return JS_FALSE;
MUST_FLOW_THROUGH("out");
cx->generatingError = JS_TRUE;
/* 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
* exception constructor name in the scope chain of the current context's
* top stack frame, or in the global object if no frame is active.
*/
ok = js_GetClassPrototype(cx, NULL, GetExceptionProtoKey(exn), &errProto);
if (!ok)
@@ -1186,38 +1197,41 @@ js_ErrorToException(JSContext *cx, const
goto out;
JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject));
/* Flag the error report passed in to indicate an exception was raised. */
reportp->flags |= JSREPORT_EXCEPTION;
out:
+ JS_POP_TEMP_ROOT(cx, &tvr);
cx->generatingError = JS_FALSE;
return ok;
}
JSBool
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
* could become unrooted, we must root exnObject. Later, if exnObject is
* non-null, we need to root other intermediates, so allocate an operand
* stack segment to protect all of these values.
*/
if (JSVAL_IS_PRIMITIVE(exn)) {
@@ -1232,46 +1246,61 @@ js_ReportUncaughtException(JSContext *cx
/* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */
str = js_ValueToString(cx, exn);
if (!str) {
bytes = "unknown (can't convert to string)";
} 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);
report.filename = filename;
report.lineno = (uintN) lineno;
}
if (!reportp) {
@@ -1282,10 +1311,12 @@ js_ReportUncaughtException(JSContext *cx
reportp->flags |= JSREPORT_EXCEPTION;
/* Pass the exception object. */
JS_SetPendingException(cx, exn);
js_ReportErrorAgain(cx, bytes, reportp);
JS_ClearPendingException(cx);
}
- return true;
+out:
+ JS_POP_TEMP_ROOT(cx, &tvr);
+ return ok;
}
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -346,17 +346,17 @@ WrapEscapingClosure(JSContext *cx, JSSta
JSObject *scopeChain = js_GetScopeChain(cx, fp);
if (!scopeChain)
return NULL;
JSObject *wfunobj = js_NewObjectWithGivenProto(cx, &js_FunctionClass,
funobj, scopeChain);
if (!wfunobj)
return NULL;
- AutoValueRooter tvr(cx, wfunobj);
+ JSAutoTempValueRooter tvr(cx, wfunobj);
JSFunction *wfun = (JSFunction *) wfunobj;
wfunobj->setPrivate(wfun);
wfun->nargs = 0;
wfun->flags = fun->flags | JSFUN_HEAVYWEIGHT;
wfun->u.i.nvars = 0;
wfun->u.i.nupvars = 0;
wfun->u.i.skipmin = fun->u.i.skipmin;
@@ -594,17 +594,17 @@ ArgSetter(JSContext *cx, JSObject *obj,
* backed by the default Object getter and setter. Note the we rely on
* args_delete to clear the corresponding reserved slot so the GC can
* collect its value.
*/
jsid id;
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);
}
static JSBool
args_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
JSObject **objp)
{
@@ -1579,59 +1579,64 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
JSContext *cx;
JSFunction *fun;
uint32 firstword; /* flag telling whether fun->atom is non-null,
plus for fun->u.i.skipmin, fun->u.i.wrapper,
and 14 bits reserved for future use */
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) {
fun = GET_FUNCTION_PRIVATE(cx, *objp);
if (!FUN_INTERPRETED(fun)) {
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;
nargs = fun->nargs;
nvars = fun->u.i.nvars;
nupvars = fun->u.i.nupvars;
localsword = (nargs << 16) | nvars;
flagsword = (nupvars << 16) | fun->flags;
} 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__
nvars = nargs = nupvars = 0; /* quell GCC uninitialized warning */
#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) {
nargs = localsword >> 16;
nvars = uint16(localsword);
JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
nupvars = flagsword >> 16;
fun->flags = uint16(flagsword);
@@ -1645,17 +1650,16 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
void *mark;
uintN i;
uintN bitmapLength;
uint32 *bitmap;
jsuword *names;
JSAtom *name;
JSLocalKind localKind;
- bool ok = true;
mark = JS_ARENA_MARK(&xdr->cx->tempPool);
/*
* From this point the control must flow via the label release_mark.
*
* To xdr the names we prefix the names with a bitmap descriptor and
* then xdr the names as strings. For argument names (indexes below
* nargs) the corresponding bit in the bitmap is unset when the name
@@ -1664,23 +1668,23 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
* name is declared as const, not as ordinary var.
* */
MUST_FLOW_THROUGH("release_mark");
bitmapLength = JS_HOWMANY(n, JS_BITS_PER_UINT32);
JS_ARENA_ALLOCATE_CAST(bitmap, uint32 *, &xdr->cx->tempPool,
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);
for (i = 0; i != n; ++i) {
if (i < fun->nargs
? JS_LOCAL_NAME_TO_ATOM(names[i]) != NULL
: JS_LOCAL_NAME_IS_CONST(names[i])) {
bitmap[i >> JS_BITS_PER_UINT32_LOG2] |=
@@ -1725,40 +1729,47 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
? JSLOCAL_CONST
: JSLOCAL_VAR)
: JSLOCAL_UPVAR;
ok = js_AddLocal(xdr->cx, fun, name, localKind);
if (!ok)
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);
if (fun->u.i.script != JSScript::emptyScript()) {
#ifdef CHECK_SCRIPT_OWNER
fun->u.i.script->owner = NULL;
#endif
js_CallNewScriptHook(cx, fun->u.i.script, fun);
}
}
- return true;
+out:
+ JS_POP_TEMP_ROOT(cx, &tvr);
+ return ok;
+
+bad:
+ ok = JS_FALSE;
+ goto out;
}
#else /* !JS_HAS_XDR */
#define js_XDRFunctionObject NULL
#endif /* !JS_HAS_XDR */
@@ -2665,51 +2676,54 @@ js_ValueToCallableObject(JSContext *cx,
}
void
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 {
error = JSMSG_NOT_FUNCTION;
}
js_ReportValueError3(cx, error,
(fp && fp->regs &&
StackBase(fp) <= vp && vp < fp->regs->sp)
? vp - fp->regs->sp
: (flags & JSV2F_SEARCH_STACK)
? JSDVG_SEARCH_STACK
: JSDVG_IGNORE_STACK,
*vp, NULL,
name, source);
+
+ out:
+ JS_POP_TEMP_ROOT(cx, &tvr);
}
/*
* When a function has between 2 and MAX_ARRAY_LOCALS arguments and variables,
* their name are stored as the JSLocalNames.array.
*/
#define MAX_ARRAY_LOCALS 8
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -82,17 +82,16 @@
#if JS_HAS_XML_SUPPORT
#include "jsxml.h"
#endif
#ifdef INCLUDE_MOZILLA_DTRACE
#include "jsdtracef.h"
#endif
-#include "jscntxtinlines.h"
#include "jsobjinlines.h"
/*
* Include the headers for mmap.
*/
#if defined(XP_WIN)
# include <windows.h>
#endif
@@ -106,16 +105,24 @@
#endif
#if !defined(MAP_ANONYMOUS)
# define MAP_ANONYMOUS 0
#endif
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.
*/
JS_STATIC_ASSERT(JSTRACE_OBJECT == 0);
JS_STATIC_ASSERT(JSTRACE_DOUBLE == 1);
JS_STATIC_ASSERT(JSTRACE_STRING == 2);
JS_STATIC_ASSERT(JSTRACE_XML == 3);
@@ -2247,30 +2254,29 @@ gc_lock_traversal(JSDHashTable *table, J
uint32 traceKind;
JS_ASSERT(lhe->count >= 1);
traceKind = js_GetGCThingTraceKind(thing);
JS_CALL_TRACER(trc, thing, traceKind, "locked object");
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)
{
uintN nslots, minargs, skip;
if (fp->callobj)
JS_CALL_OBJECT_TRACER(trc, fp->callobj, "call");
@@ -2286,17 +2292,17 @@ js_TraceStackFrame(JSTracer *trc, JSStac
* popped already.
*/
if (fp->regs && fp->regs->sp) {
nslots = (uintN) (fp->regs->sp - fp->slots);
JS_ASSERT(nslots >= fp->script->nfixed);
} else {
nslots = fp->script->nfixed;
}
- js::TraceValues(trc, nslots, fp->slots, "slot");
+ TRACE_JSVALS(trc, nslots, fp->slots, "slot");
}
} else {
JS_ASSERT(!fp->slots);
JS_ASSERT(!fp->regs);
}
/* Allow for primitive this parameter due to JSFUN_THISP_* flags. */
JS_CALL_VALUE_TRACER(trc, fp->thisv, "this");
@@ -2311,17 +2317,17 @@ js_TraceStackFrame(JSTracer *trc, JSStac
nslots = minargs;
if (!FUN_INTERPRETED(fp->fun)) {
JS_ASSERT(!(fp->fun->flags & JSFUN_FAST_NATIVE));
nslots += fp->fun->u.n.extra;
}
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");
if (fp->scopeChain)
JS_CALL_OBJECT_TRACER(trc, fp->scopeChain, "scope chain");
}
void
@@ -2366,16 +2372,17 @@ TraceFrameChain(JSTracer *trc, JSStackFr
js_TraceStackFrame(trc, fp);
} while ((fp = fp->down) != NULL);
}
JS_REQUIRES_STACK JS_FRIEND_API(void)
js_TraceContext(JSTracer *trc, JSContext *acx)
{
JSStackHeader *sh;
+ JSTempValueRooter *tvr;
/*
* Trace active and suspended callstacks.
*
* Since js_GetTopStackFrame needs to dereference cx->thread to check for
* JIT frames, we check for non-null thread here and avoid null checks
* there. See bug 471197.
*/
@@ -2415,32 +2422,59 @@ js_TraceContext(JSTracer *trc, JSContext
} else {
/* Avoid keeping GC-ed junk stored in JSContext.exception. */
acx->exception = JSVAL_NULL;
}
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<JSAutoEnumStateRooter *>(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);
js_TraceRegExpStatics(trc, acx);
#ifdef JS_TRACER
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
}
JS_REQUIRES_STACK void
js_TraceRuntime(JSTracer *trc, JSBool allAtoms)
{
@@ -3326,35 +3360,38 @@ out:
#endif
/*
* Execute JSGC_END callback outside the lock. Again, sample the callback
* pointer in case it changes, since we are outside of the GC vs. requests
* interlock mechanism here.
*/
if (gckind != GC_SET_SLOT_REQUEST && (callback = rt->gcCallback)) {
- if (!(gckind & GC_KEEP_ATOMS)) {
- (void) callback(cx, JSGC_END);
-
- /*
- * On shutdown iterate until JSGC_END callback stops creating
- * garbage.
- */
- if (gckind == GC_LAST_CONTEXT && rt->gcPoke)
- goto restart_at_beginning;
- } else {
+ JSWeakRoots savedWeakRoots;
+ JSTempValueRooter tvr;
+
+ 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;
}
}
}
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -449,28 +449,9 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp);
* This function is defined in jsdbgapi.cpp but is declared here to avoid
* polluting jsdbgapi.h, a public API header, with internal functions.
*/
extern void
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___ */
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -795,17 +795,17 @@ js_GetScopeChain(JSContext *cx, JSStackF
* common with subsequent steps to include in the loop.
*
* js_CloneBlockObject leaves the clone's parent slot uninitialized. We
* populate it below.
*/
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
* enclosing function, or the innermost block we've already cloned.
*/
JSObject *newChild = innermostNewChild;
for (;;) {
JS_ASSERT(newChild->getProto() == sharedBlock);
@@ -1000,17 +1000,17 @@ JSClass js_NoSuchMethodClass = {
*/
JS_STATIC_INTERPRET JSBool
js_OnUnknownMethod(JSContext *cx, jsval *vp)
{
JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]));
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())) {
vp[0] = tvr.value();
} else {
#if JS_HAS_XML_SUPPORT
/* Extract the function name from function::name qname. */
if (!JSVAL_IS_PRIMITIVE(vp[0])) {
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -210,21 +210,28 @@ Iterator(JSContext *cx, JSObject *iterob
*rval = argv[0];
return js_ValueToIterator(cx, flags, 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;
}
static JSBool
IteratorNextImpl(JSContext *cx, JSObject *obj, jsval *rval)
{
JSObject *iterable;
jsval state;
@@ -335,99 +342,109 @@ js_GetNativeIteratorFlags(JSContext *cx,
/*
* Call ToObject(v).__iterator__(keyonly) if ToObject(v).__iterator__ exists.
* Otherwise construct the default iterator.
*/
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);
} else {
/*
* Enumerating over null and undefined gives an empty enumerator.
* This is contrary to ECMA-262 9.9 ToObject, invoked from step 3 of
* the first production in 12.6.4 and step 4 of the second production,
* but it's "web JS" compatible.
*/
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:
/*
* Fail over to the default enumerating native iterator.
*
* Create iterobj with a NULL parent to ensure that we use the
* correct scope chain to lookup the iterator's constructor. Since
* we use the parent slot to keep track of the iterable, we must
* fix it up after.
*/
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
js_CloseIterator(JSContext *cx, jsval v)
{
JSObject *obj;
JSClass *clasp;
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -984,21 +984,21 @@ js_ValueToNumber(JSContext *cx, jsval *v
JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
obj = JSVAL_TO_OBJECT(v);
/*
* 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;
}
if (!JSVAL_IS_PRIMITIVE(v))
break;
}
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -240,34 +240,42 @@ obj_setSlot(JSContext *cx, JSObject *obj
return JS_FALSE;
return js_SetProtoOrParent(cx, obj, slot, pobj, JS_TRUE);
}
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 */
#define object_props NULL
#endif /* !JS_HAS_OBJ_PROTO_PROP */
@@ -651,23 +659,25 @@ obj_toSource(JSContext *cx, uintN argc,
jsid id;
#if JS_HAS_GETTER_SETTER
JSObject *obj2;
JSProperty *prop;
uintN attrs;
#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);
obj = JS_THIS_OBJECT(cx, vp);
if (!obj || !(he = js_EnterSharpObject(cx, obj, &ida, &chars))) {
ok = JS_FALSE;
goto out;
}
@@ -1022,16 +1032,17 @@ obj_toSource(JSContext *cx, uintN argc,
if (!str) {
js_free(chars);
ok = JS_FALSE;
goto out;
}
*vp = STRING_TO_JSVAL(str);
ok = JS_TRUE;
out:
+ JS_POP_TEMP_ROOT(cx, &tvr);
return ok;
overflow:
cx->free(vsharp);
js_free(chars);
chars = NULL;
goto error;
}
@@ -1950,17 +1961,17 @@ obj_getOwnPropertyDescriptor(JSContext *
{
if (argc == 0 || JSVAL_IS_PRIMITIVE(vp[2])) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
return JS_FALSE;
}
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;
JSObject *pobj;
JSProperty *prop;
if (!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, nameidr.id(), &pobj, &prop))
return JS_FALSE;
if (!prop) {
@@ -1970,17 +1981,17 @@ obj_getOwnPropertyDescriptor(JSContext *
uintN attrs;
if (!pobj->getAttributes(cx, nameidr.id(), prop, &attrs)) {
pobj->dropProperty(cx, prop);
return JS_FALSE;
}
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<JSScopeProperty *>(prop);
if (attrs & JSPROP_GETTER)
roots[0] = sprop->getterValue();
if (attrs & JSPROP_SETTER)
roots[1] = sprop->setterValue();
}
@@ -2031,17 +2042,17 @@ obj_keys(JSContext *cx, uintN argc, jsva
{
jsval v = argc == 0 ? JSVAL_VOID : vp[2];
if (JSVAL_IS_PRIMITIVE(v)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
return JS_FALSE;
}
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;
JSObject *proto;
if (!js_GetClassPrototype(cx, NULL, JSProto_Array, &proto))
return JS_FALSE;
vp[1] = OBJECT_TO_JSVAL(proto);
@@ -2196,16 +2207,60 @@ PropertyDescriptor::initialize(JSContext
if ((hasGet || hasSet) && (hasValue || hasWritable)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INVALID_DESCRIPTOR);
return false;
}
return true;
}
+typedef js::Vector<PropertyDescriptor, 1> 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<AutoDescriptorArray *>(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)
{
if (throwError) {
jsid idstr;
if (!js_ValueToStringId(cx, ID_TO_VALUE(id), &idstr))
return JS_FALSE;
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber,
@@ -2579,17 +2634,17 @@ obj_defineProperty(JSContext* cx, uintN
if (JSVAL_IS_PRIMITIVE(v)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
return JS_FALSE;
}
*vp = vp[2];
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;
/* 15.2.3.6 step 3. */
AutoDescriptorArray descs(cx);
PropertyDescriptor *desc = descs.append();
if (!desc || !desc->initialize(cx, nameidr.id(), argc >= 3 ? vp[4] : JSVAL_VOID))
return JS_FALSE;
@@ -2616,17 +2671,17 @@ obj_defineProperties(JSContext* cx, uint
return JS_FALSE;
}
JSObject* props = js_ValueToNonNullObject(cx, vp[3]);
if (!props)
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;
AutoDescriptorArray descs(cx);
size_t len = ida.length();
for (size_t i = 0; i < len; i++) {
jsid id = ida[i];
PropertyDescriptor* desc = descs.append();
@@ -2680,17 +2735,17 @@ obj_create(JSContext *cx, uintN argc, js
/* 15.2.3.5 step 4. */
if (argc > 1 && vp[3] != JSVAL_VOID) {
if (JSVAL_IS_PRIMITIVE(vp[3])) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
return JS_FALSE;
}
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;
AutoDescriptorArray descs(cx);
size_t len = ida.length();
for (size_t i = 0; i < len; i++) {
jsid id = ida[i];
PropertyDescriptor *desc = descs.append();
@@ -2878,17 +2933,17 @@ js_NewObjectWithGivenProto(JSContext *cx
obj->map = const_cast<JSObjectMap *>(ops->objectMap);
}
/*
* Do not call debug hooks on trace, because we might be in a non-_FAIL
* 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);
JS_UNKEEP_ATOMS(cx->runtime);
cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
}
out:
@@ -3554,17 +3609,17 @@ js_XDRBlockObject(JSXDRState *xdr, JSObj
*/
if (parentId == NO_PARENT_INDEX)
parent = NULL;
else
parent = xdr->script->getObject(parentId);
obj->setParent(parent);
}
- AutoValueRooter tvr(cx, obj);
+ JSAutoTempValueRooter tvr(cx, obj);
if (!JS_XDRUint32(xdr, &tmp))
return false;
if (xdr->mode == JSXDR_DECODE) {
depth = (uint16)(tmp >> 16);
count = (uint16)tmp;
STOBJ_SET_SLOT(obj, JSSLOT_BLOCK_DEPTH, INT_TO_JSVAL(depth));
@@ -3647,16 +3702,17 @@ JSObject *
js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
JSClass *clasp, JSNative constructor, uintN nargs,
JSPropertySpec *ps, JSFunctionSpec *fs,
JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
{
JSAtom *atom;
JSProtoKey key;
JSObject *proto, *ctor;
+ JSTempValueRooter tvr;
jsval cval, rval;
JSBool named;
JSFunction *fun;
atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
if (!atom)
return NULL;
@@ -3682,17 +3738,17 @@ js_InitClass(JSContext *cx, JSObject *ob
}
/* Create a prototype object for this class. */
proto = js_NewObject(cx, clasp, parent_proto, obj);
if (!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) {
/*
* Lacking a constructor, name the prototype (e.g., Math) unless this
* class (a) is anonymous, i.e. for internal use only; (b) the class
* of obj (the global object) is has a reserved slot indexed by key;
* and (c) key is not the null key.
*/
@@ -3772,16 +3828,17 @@ js_InitClass(JSContext *cx, JSObject *ob
if (!OBJ_SCOPE(proto)->ensureEmptyScope(cx, clasp))
goto bad;
/* If this is a standard class, cache its prototype. */
if (key != JSProto_Null && !js_SetClassObject(cx, obj, key, ctor))
goto bad;
out:
+ JS_POP_TEMP_ROOT(cx, &tvr);
return proto;
bad:
if (named)
(void) obj->deleteProperty(cx, ATOM_TO_JSID(atom), &rval);
proto = NULL;
goto out;
}
@@ -4079,29 +4136,29 @@ js_FindClassObject(JSContext *cx, JSObje
JSObject *
js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
JSObject *parent, uintN argc, jsval *argv)
{
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))
return NULL;
if (JSVAL_IS_PRIMITIVE(cval)) {
js_ReportIsNotFunction(cx, &cval, JSV2F_CONSTRUCT | JSV2F_SEARCH_STACK);
return NULL;
}
/* 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
* Constructor.__parent__, just like JSOP_NEW does.
*/
ctor = JSVAL_TO_OBJECT(cval);
if (!parent)
parent = ctor->getParent();
@@ -4891,16 +4948,18 @@ JSBool
js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj,
JSScopeProperty *sprop, uintN getHow, jsval *vp)
{
LeaveTraceIfGlobalObject(cx, 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));
scope = OBJ_SCOPE(pobj);
slot = sprop->slot;
*vp = (slot != SPROP_INVALID_SLOT)
? LOCKED_OBJ_GET_SLOT(pobj, slot)
@@ -4910,24 +4969,25 @@ js_NativeGet(JSContext *cx, JSObject *ob
if (JS_UNLIKELY(sprop->isMethod()) && (getHow & JSGET_NO_METHOD_BARRIER)) {
JS_ASSERT(sprop->methodValue() == *vp);
return true;
}
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_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))) {
jsval v = *vp;
if (!scope->methodWriteBarrier(cx, sprop, v)) {
JS_UNLOCK_SCOPE(cx, scope);
return false;
}
@@ -4941,16 +5001,18 @@ JSBool
js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added,
jsval *vp)
{
LeaveTraceIfGlobalObject(cx, obj);
JSScope *scope;
uint32 slot;
int32 sample;
+ JSTempValueRooter tvr;
+ JSBool ok;
JS_ASSERT(OBJ_IS_NATIVE(obj));
JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj));
scope = OBJ_SCOPE(obj);
slot = sprop->slot;
if (slot != SPROP_INVALID_SLOT) {
OBJ_CHECK_SLOT(obj, slot);
@@ -4972,21 +5034,21 @@ js_NativeSet(JSContext *cx, JSObject *ob
* or throw if we're in strict mode.
*/
if (!(sprop->attrs & JSPROP_GETTER) && SPROP_HAS_STUB_SETTER(sprop))
return js_ReportGetterOnlyAssignment(cx);
}
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) &&
(JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
scope->hasProperty(sprop))) {
jsval v = *vp;
if (!added && !scope->methodWriteBarrier(cx, sprop, v)) {
JS_UNLOCK_SCOPE(cx, scope);
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -47,24 +47,22 @@
* ordered property names, called the map; and a dense vector of property
* values, called slots. The map/slot pointer pair is GC'ed, while the map
* is reference counted and the slot vector is malloc'ed.
*/
#include "jshash.h" /* Added by JSIFY */
#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();
public:
/* 8.10.5 ToPropertyDescriptor(Obj) */
bool initialize(JSContext* cx, jsid id, jsval v);
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -78,39 +78,9 @@ JSObject::unbrand(JSContext *cx)
}
}
scope->setGeneric();
JS_UNLOCK_SCOPE(cx, scope);
}
return true;
}
-namespace js {
-
-typedef Vector<PropertyDescriptor, 1> 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___ */
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -60,18 +60,16 @@
#include "jsutil.h"
#include "jsxml.h"
#include "jsvector.h"
#include "json.h"
#include "jsatominlines.h"
-using namespace js;
-
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4351)
#endif
struct JSONParser
{
JSONParser(JSContext *cx)
@@ -103,48 +101,51 @@ JSClass js_JSONClass = {
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSBool
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);
JSBool ok = jp != NULL;
if (ok) {
const jschar *chars;
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;
}
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
// needs to support returning undefined. So this is a little awkward
// for the API, because we want to support streaming writers.
if (!cb.empty()) {
JSString *str = js_NewStringFromCharBuffer(cx, cb);
if (!str)
@@ -252,17 +253,17 @@ static JSBool
JO(JSContext *cx, jsval *vp, StringifyContext *scx)
{
JSObject *obj = JSVAL_TO_OBJECT(*vp);
if (!scx->cb.append('{'))
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];
JSObject *iterObj = NULL;
jsval *keySource = vp;
bool usingWhitelist = false;
// if the replacer is an array, we use the keys from it
@@ -301,17 +302,17 @@ JO(JSContext *cx, jsval *vp, StringifyCo
JSString *ks;
if (JSVAL_IS_STRING(key)) {
ks = JSVAL_TO_STRING(key);
} else {
ks = js_ValueToString(cx, key);
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()
jsid id;
JSObject *obj2;
JSProperty *prop;
if (!js_ValueToStringId(cx, STRING_TO_JSVAL(ks), &id) ||
!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &obj2, &prop)) {
@@ -387,30 +388,31 @@ JA(JSContext *cx, jsval *vp, StringifyCo
if (!scx->cb.append('['))
return JS_FALSE;
jsuint length;
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;
}
if (i < length - 1) {
if (!scx->cb.append(','))
return JS_FALSE;
if (!WriteIndent(cx, scx, scx->depth))
@@ -563,94 +565,105 @@ js_Stringify(JSContext *cx, jsval *vp, J
static JSBool IsNumChar(jschar c)
{
return ((c <= '9' && c >= '0') || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E');
}
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;
+
+ JSAutoTempValueRooter idaroot(cx, JS_ARRAY_LENGTH(ida), (jsval*)ida);
- 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;
+ 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);
}
}
// return reviver.call(holder, key, value);
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);
}
JSONParser *
js_BeginJSONParse(JSContext *cx, jsval *rootVal)
{
@@ -675,21 +688,21 @@ js_BeginJSONParse(JSContext *cx, jsval *
return jp;
bad:
js_FinishJSONParse(cx, jp, JSVAL_NULL);
return NULL;
}
-bool
+JSBool
js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver)
{
if (!jp)
- return true;
+ return JS_TRUE;
JSBool early_ok = JS_TRUE;
// Check for unprocessed primitives at the root. This doesn't happen for
// strings because a closing quote triggers value processing.
if ((jp->statep - jp->stateStack) == 1) {
if (*jp->statep == JSON_PARSE_STATE_KEYWORD) {
early_ok = HandleData(cx, jp, JSON_DATA_KEYWORD);
@@ -700,30 +713,30 @@ js_FinishJSONParse(JSContext *cx, JSONPa
if (early_ok)
PopState(cx, jp);
}
}
/* 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;
}
static JSBool
PushState(JSContext *cx, JSONParser *jp, JSONParserState state)
{
@@ -791,17 +804,17 @@ PushObject(JSContext *cx, JSONParser *jp
if (!js_GetLengthProperty(cx, jp->objectStack, &len))
return JS_FALSE;
if (len >= JSON_MAX_DEPTH) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE);
return JS_FALSE;
}
jsval v = OBJECT_TO_JSVAL(obj);
- AutoValueRooter tvr(cx, v);
+ JSAutoTempValueRooter tvr(cx, v);
// Check if this is the root object
if (len == 0) {
*jp->rootVal = v;
// This property must be enumerable to keep the array dense
if (!jp->objectStack->defineProperty(cx, INT_TO_JSID(0), *jp->rootVal,
NULL, NULL, JSPROP_ENUMERATE)) {
return JS_FALSE;
@@ -864,17 +877,17 @@ static JSBool
CloseArray(JSContext *cx, JSONParser *jp)
{
return CloseObject(cx, 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))
return JS_FALSE;
if (len > 0) {
jsval o;
if (!jp->objectStack->getProperty(cx, INT_TO_JSID(len - 1), &o))
--- a/js/src/json.h
+++ b/js/src/json.h
@@ -84,14 +84,14 @@ enum JSONDataType {
struct JSONParser;
extern JSONParser *
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
#endif /* json_h___ */
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -74,18 +74,16 @@
#include "jsstaticcheck.h"
#include "jstracer.h"
#include "jsvector.h"
#include "jsscriptinlines.h"
#include "jsautooplen.h"
-using namespace js;
-
/*
* Index limit must stay within 32 bits.
*/
JS_STATIC_ASSERT(sizeof(uint32) * JS_BITS_PER_BYTE >= INDEX_LIMIT_LOG2 + 1);
/* Verify JSOP_XXX_LENGTH constant definitions. */
#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
JS_STATIC_ASSERT(op##_LENGTH == length);
@@ -304,17 +302,17 @@ ToDisassemblySource(JSContext *cx, jsval
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
JSString *str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
if (!str)
return NULL;
return js_GetStringBytes(cx, str);
}
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()));
}
}
return js_ValueToPrintableSource(cx, v);
}
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -83,18 +83,16 @@
#if JS_HAS_XML_SUPPORT
#include "jsxml.h"
#endif
#if JS_HAS_DESTRUCTURING
#include "jsdhash.h"
#endif
-using namespace js;
-
/*
* Asserts to verify assumptions behind pn_ macros.
*/
#define pn_offsetof(m) offsetof(JSParseNode, m)
JS_STATIC_ASSERT(pn_offsetof(pn_link) == pn_offsetof(dn_uses));
JS_STATIC_ASSERT(pn_offsetof(pn_u.name.atom) == pn_offsetof(pn_u.apair.atom));
@@ -219,25 +217,28 @@ JSCompiler::init(const jschar *base, siz
tempPoolMark = JS_ARENA_MARK(&cx->tempPool);
if (!tokenStream.init(cx, base, length, fp, filename, lineno)) {
JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark);
return false;
}
/* Root atoms and objects allocated for the parsed tree. */
JS_KEEP_ATOMS(cx->runtime);
+ JS_PUSH_TEMP_ROOT_COMPILER(cx, this, &tempRoot);
return true;
}
JSCompiler::~JSCompiler()
{
JSContext *cx = context;
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);
}
void
JSCompiler::setPrincipals(JSPrincipals *prin)
{
@@ -332,17 +333,20 @@ JSFunctionBox::shouldUnbrand(uintN metho
}
}
return false;
}
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;
}
}
static void
UnlinkFunctionBoxes(JSParseNode *pn, JSTreeContext *tc);
@@ -8821,16 +8825,17 @@ FoldBinaryNumeric(JSContext *cx, JSOp op
static JSBool
FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
{
JSTokenType tt;
JSParseNode **pnp, *pn1, *pn2;
JSString *accum, *str;
uint32 i, j;
+ JSTempValueRooter tvr;
JS_ASSERT(pn->pn_arity == PN_LIST);
tt = PN_TYPE(pn);
pnp = &pn->pn_head;
pn1 = *pnp;
accum = NULL;
if ((pn->pn_xflags & PNX_CANTFOLD) == 0) {
if (tt == TOK_XMLETAGO)
@@ -8911,22 +8916,21 @@ FoldXMLConstants(JSContext *cx, JSParseN
}
pnp = &pn2->pn_next;
pn1 = *pnp;
accum = NULL;
continue;
}
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
printf("2: %d, %d => ", i, j);
js_FileEscapedString(stdout, str, 0);
printf(" (%u)\n", str->length());
#endif
++j;
--- a/js/src/jsparse.h
+++ b/js/src/jsparse.h
@@ -827,45 +827,40 @@ struct JSFunctionBoxQueue {
JSFunctionBox *funbox = vector[tail++ & lengthMask];
funbox->queued = false;
return funbox;
}
};
#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;
void *tempPoolMark; /* initial JSContext.tempPool mark */
JSPrincipals *principals; /* principals associated with source */
JSStackFrame *callerFrame; /* scripted caller frame for eval and dbgapi */
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);
setPrincipals(prin);
JS_ASSERT_IF(cfp, cfp->script);
}
~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
* JSContext.tempPool mark. This means you cannot allocate from tempPool
* and save the pointer beyond the next JSCompiler destructor invocation.
*/
bool init(const jschar *base, size_t length,
FILE *fp, const char *filename, uintN lineno);
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -276,16 +276,41 @@ typedef struct JSDebugHooks {
JSObjectHook objectHook;
void *objectHookData;
JSTrapHandler throwHook;
void *throwHookData;
JSDebugErrorHook debugErrorHook;
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. */
/*
* Look for id in obj and its prototype chain, returning false on error or
* exception, true on success. On success, return null in *propp if id was
* not found. If id was found, return the first object searching from obj
* along its prototype chain in which id names a direct property in *objp, and
* return a non-null, opaque property pointer in *propp.
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -5227,35 +5227,36 @@ js_InitRegExpStatics(JSContext *cx)
12 * 1024 - 40, /* FIXME: bug 421435 */
sizeof(void *), &cx->scriptStackQuota);
JS_ClearRegExpStatics(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).
*/
cx->regExpStatics.moreParens = NULL;
JS_ClearRegExpStatics(cx);
}
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
js_TraceRegExpStatics(JSTracer *trc, JSContext *acx)
{
JSRegExpStatics *res = &acx->regExpStatics;
if (res->input)
@@ -5838,17 +5839,17 @@ js_NewRegExpObject(JSContext *cx, JSToke
{
JSString *str;
JSObject *obj;
JSRegExp *re;
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;
obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL);
if (!obj) {
js_DestroyRegExp(cx, re);
return NULL;
}
--- a/js/src/jsregexp.h
+++ b/js/src/jsregexp.h
@@ -60,25 +60,23 @@ struct JSRegExpStatics {
JSSubString parens[9]; /* last set of parens matched (perl $1, $2) */
JSSubString *moreParens; /* null or realloc'd vector for $10, etc. */
JSSubString lastMatch; /* last string matched (perl $&) */
JSSubString lastParen; /* last paren matched (perl $+) */
JSSubString leftContext; /* input to left of last match (perl $`) */
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.
* There's a list of these referenced by the classList field in the JSRegExp
* struct below. The initial state has startIndex set to the offset in the
* original regexp source of the beginning of the class contents. The first
* use of the class converts the source representation into a bitmap.
*
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -89,16 +89,17 @@ js_XDRScript(JSXDRState *xdr, JSScript *
{
JSContext *cx;
JSScript *script, *oldscript;
JSBool ok;
jsbytecode *code;
uint32 length, lineno, nslots, magic;
uint32 natoms, nsrcnotes, ntrynotes, nobjects, nupvars, nregexps, i;
uint32 prologLength, version;
+ JSTempValueRooter tvr;
JSPrincipals *principals;
uint32 encodeable;
JSBool filenameWasSaved;
jssrcnote *notes, *sn;
JSSecurityCallbacks *callbacks;
cx = xdr->cx;
script = *scriptp;
@@ -206,32 +207,30 @@ js_XDRScript(JSXDRState *xdr, JSScript *
return JS_FALSE;
if (!JS_XDRUint32(xdr, &nobjects))
return JS_FALSE;
if (!JS_XDRUint32(xdr, &nupvars))
return JS_FALSE;
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);
if (!script)
return JS_FALSE;
script->main += prologLength;
script->version = JSVersion(version & 0xffff);
script->nfixed = uint16(version >> 16);
/* 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);
}
/*
* Control hereafter must goto error on failure, in order for the
* DECODE case to destroy script.
*/
oldscript = xdr->script;
code = script->code;
@@ -364,20 +363,23 @@ js_XDRScript(JSXDRState *xdr, JSScript *
if (xdr->mode == JSXDR_DECODE) {
tn->kind = (uint8)(kindAndDepth >> 16);
tn->stackDepth = (uint16)kindAndDepth;
}
} while (tn != tnfirst);
}
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;
}
js_DestroyScript(cx, script);
*scriptp = NULL;
}
xdr->script = oldscript;
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1598,17 +1598,17 @@ str_match(JSContext *cx, uintN argc, jsv
RegExpGuard g(cx);
if (!g.init(argc, vp))
return false;
if (g.tryFlatMatch(str, false, 1, argc))
return BuildFlatMatchArray(cx, str, g, 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;
/* When not global, DoMatch will leave |RegEx.exec()| in *vp. */
if (g.re()->flags & JSREG_GLOB)
*vp = array.value();
return true;
}
@@ -3379,17 +3379,17 @@ js_ValueToSource(JSContext *cx, jsval v)
static const jschar js_negzero_ucNstr[] = {'-', '0'};
return js_NewStringCopyN(cx, js_negzero_ucNstr, 2);
}
return js_ValueToString(cx, 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());
}
/*
* str is not necessarily a GC thing here.
*/
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -8809,22 +8809,23 @@ TraceRecorder::relational(LOpcode op, bo
case JSVAL_DOUBLE:
default:
JS_NOT_REACHED("JSVAL_IS_NUMBER if int/double, objects should "
"have been handled at start of method");
RETURN_STOP_A("safety belt");
}
}
{
- AutoValueRooter tvr(cx);
-
- *tvr.addr() = l;
- lnum = js_ValueToNumber(cx, tvr.addr());
- *tvr.addr() = r;
- rnum = js_ValueToNumber(cx, tvr.addr());
+ jsval tmp = JSVAL_NULL;
+ JSAutoTempValueRooter tvr(cx, 1, &tmp);
+
+ tmp = l;
+ lnum = js_ValueToNumber(cx, &tmp);
+ tmp = r;
+ rnum = js_ValueToNumber(cx, &tmp);
}
cond = EvalCmp(op, lnum, rnum);
fp = true;
/* 11.8.5 steps 6-15. */
do_comparison:
/*
* If the result is not a number or it's not a quad, we must use an integer
@@ -11204,17 +11205,17 @@ TraceRecorder::nativeSet(JSObject* obj,
}
return RECORD_CONTINUE;
}
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());
}
JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, MethodWriteBarrier, CONTEXT, OBJECT, SCOPEPROP, OBJECT,
0, ACC_STORE_ANY)
JS_REQUIRES_STACK RecordingStatus
TraceRecorder::setProp(jsval &l, JSPropCacheEntry* entry, JSScopeProperty* sprop,
@@ -11568,17 +11569,17 @@ TraceRecorder::getPropertyByName(LIns* o
return RECORD_CONTINUE;
}
static JSBool FASTCALL
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;
}
return cx->interpState->builtinStatus == 0;
}
JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyByIndex, CONTEXT, OBJECT, INT32, JSVALPTR, 0,
ACC_STORE_ANY)
@@ -11907,32 +11908,32 @@ TraceRecorder::initOrSetPropertyByName(L
return RECORD_CONTINUE;
}
static JSBool FASTCALL
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;
}
return cx->interpState->builtinStatus == 0;
}
JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, SetPropertyByIndex, CONTEXT, OBJECT, INT32, JSVALPTR, 0,
ACC_STORE_ANY)
static JSBool FASTCALL
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);
return JS_FALSE;
}
return cx->interpState->builtinStatus == 0;
}
JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, InitPropertyByIndex, CONTEXT, OBJECT, INT32, JSVAL, 0,
@@ -12741,17 +12742,17 @@ TraceRecorder::name(jsval*& vp, LIns*& i
ins = get(vp);
nr.tracked = true;
return ARECORD_CONTINUE;
}
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;
JS_ASSERT(VALUE_IS_FUNCTION(cx, tvr.value()));
return JSVAL_TO_OBJECT(tvr.value());
}
JS_DEFINE_CALLINFO_4(static, OBJECT_FAIL, MethodReadBarrier, CONTEXT, OBJECT, SCOPEPROP, OBJECT,
0, ACC_STORE_ANY)
@@ -14862,17 +14863,17 @@ static JSBool
CallIteratorNext(JSContext *cx, uintN argc, jsval *vp)
{
return js_CallIteratorNext(cx, JS_THIS_OBJECT(cx, vp), &JS_RVAL(cx, 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) {
SetBuiltinError(cx);
return JSVAL_ERROR_COOKIE;
}
return tvr.value();
}
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -1315,20 +1315,20 @@ js_IsTypedArray(JSObject *obj)
return obj &&
obj->getClass() >= &TypedArray::fastClasses[0] &&
obj->getClass() < &TypedArray::fastClasses[TypedArray::TYPE_MAX];
}
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()))
return NULL;
return JSVAL_TO_OBJECT(rval.value());
}
@@ -1370,34 +1370,34 @@ TypedArrayConstruct(JSContext *cx, jsint
}
JS_FRIEND_API(JSObject *)
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;
if (!TypedArrayConstruct(cx, atype, 1, &vals[0], &vals[1]))
return NULL;
return JSVAL_TO_OBJECT(vals[1]);
}
JS_FRIEND_API(JSObject *)
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);
if (!TypedArrayConstruct(cx, atype, 1, &vals[0], &vals[1]))
return NULL;
return JSVAL_TO_OBJECT(vals[1]);
}
@@ -1407,17 +1407,17 @@ js_CreateTypedArrayWithBuffer(JSContext
jsint byteoffset, jsint length)
{
JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
JS_ASSERT(bufArg && ArrayBuffer::fromJSObject(bufArg));
/* if byteoffset is -1, length must be -1 */
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);
if (byteoffset >= 0) {
js_NewNumberInRootedValue(cx, jsdouble(byteoffset), &vals[1]);
argc++;
}
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -206,19 +206,19 @@ JS_END_EXTERN_C
#ifdef __cplusplus
/**
* The following classes are designed to cause assertions to detect
* inadvertent use of guard objects as temporaries. In other words,
* 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.
*
* They work by adding (#ifdef DEBUG) an additional parameter to the
* guard object's constructor, with a default value, so that users of
* the guard object's API do not need to do anything. The default value
* of this parameter is a temporary object. C++ (ISO/IEC 14882:1998),
* section 12.2 [class.temporary], clauses 4 and 5 seem to assume a
--- a/js/src/jsvector.h
+++ b/js/src/jsvector.h
@@ -354,20 +354,17 @@ class Vector : AllocPolicy
const T &back() const {
JS_ASSERT(!entered && !empty());
return *(end() - 1);
}
/* 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()). */
void shrinkBy(size_t incr);
/*
* Grow the vector by incr elements. If T is a POD (as judged by
* tl::IsPodType), leave as uninitialized memory. Otherwise, default
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -65,24 +65,20 @@
#include "jsscan.h"
#include "jsscope.h"
#include "jsscript.h"
#include "jsstr.h"
#include "jsxml.h"
#include "jsstaticcheck.h"
#include "jsvector.h"
-#include "jscntxtinlines.h"
-
#ifdef DEBUG
#include <string.h> /* for #ifdef DEBUG memset calls */
#endif
-using namespace js;
-
/*
* NOTES
* - in the js shell, you must use the -x command line option, or call
* options('xml') before compiling anything that uses XML literals
*
* TODO
* - XXXbe patrol
* - Fuse objects and their JSXML* private data into single GC-things
@@ -865,20 +861,70 @@ static JSBool
attr_identity(const void *a, const void *b)
{
const JSXML *xmla = (const JSXML *) a;
const JSXML *xmlb = (const JSXML *) 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. */
static JSBool
XMLArraySetCapacity(JSContext *cx, JSXMLArray *array, uint32 capacity)
{
void **vector;
@@ -3797,83 +3843,88 @@ GetNamedProperty(JSContext *cx, JSXML *x
static JSBool
GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
JSXML *xml, *list, *kid;
uint32 index;
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) {
*vp = (index == 0) ? OBJECT_TO_JSVAL(obj) : JSVAL_VOID;
} else {
/*
* ECMA-357 9.2.1.1 starts here.
*
* Erratum: 9.2 is not completely clear that indexed properties
* correspond to kids, but that's what it seems to say, and it's
* what any sane user would want.
*/
if (index < xml->xml_kids.length) {
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;
}
/*
* ECMA-357 9.2.1.1/9.1.1.1 qname case.
*/
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;
-
- roots[1] = 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;
+ if (listobj) {
+ roots[1] = OBJECT_TO_JSVAL(listobj);
+ tvr.count++;
+
+ 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);
+ }
+ }
+
+ JS_POP_TEMP_ROOT(cx, &tvr);
+ return listobj != NULL;
}
static JSXML *
CopyOnWrite(JSContext *cx, JSXML *xml, JSObject *obj)
{
JS_ASSERT(xml->object != obj);
xml = DeepCopy(cx, xml, obj, 0);
@@ -3907,16 +3958,18 @@ static JSBool
ResolveValue(JSContext *cx, JSXML *list, JSXML **result);
/* ECMA-357 9.1.1.2 XML [[Put]] and 9.2.1.2 XMLList [[Put]]. */
static JSBool
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;
uint32 index, i, j, k, n, q, matchIndex;
jsval attrval, nsval;
jsid funid;
JSString *left, *right, *space, *uri;
JSObject *ns;
@@ -3935,23 +3988,21 @@ PutProperty(JSContext *cx, JSObject *obj
vobj = JSVAL_TO_OBJECT(*vp);
if (OBJECT_IS_XML(cx, vobj))
vxml = (JSXML *) vobj->getPrivate();
}
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) {
/* See NOTE in spec: this variation is reserved for future use. */
ReportBadXMLName(cx, id);
goto bad;
}
@@ -4528,16 +4579,17 @@ PutProperty(JSContext *cx, JSObject *obj
}
} else {
/* 15(a). */
ok = Replace(cx, xml, matchIndex, *vp);
}
}
out:
+ JS_POP_TEMP_ROOT(cx, &tvr);
js_LeaveLocalRootScope(cx);
return ok;
type_error:
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_XMLLIST_PUT,
js_ValueToPrintableString(cx, id));
bad:
@@ -4659,44 +4711,48 @@ static JSBool
HasSimpleContent(JSXML *xml);
static JSBool
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]]. */
static JSBool
HasProperty(JSContext *cx, JSObject *obj, jsval id, JSBool *found)
{
JSXML *xml;
uint32 i;
@@ -4953,46 +5009,40 @@ xml_enumerate(JSContext *cx, JSObject *o
JSXMLArrayCursor *cursor;
xml = (JSXML *)obj->getPrivate();
length = JSXML_LENGTH(xml);
switch (enum_op) {
case JSENUMERATE_INIT:
if (length == 0) {
- *statep = JSVAL_ZERO;
+ cursor = NULL;
} else {
cursor = cx->create<JSXMLArrayCursor>(&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);
cursor->index = index + 1;
break;
}
/* 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;
}
return JS_TRUE;
}
static JSType
xml_typeOf(JSContext *cx, JSObject *obj)
@@ -5071,17 +5121,17 @@ js_GetXMLMethod(JSContext *cx, JSObject
if (funid != 0)
id = funid;
}
/*
* 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;
}
JSBool
js_EnumerateXMLValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
jsval *statep, jsid *idp, jsval *vp)
@@ -5094,32 +5144,30 @@ js_EnumerateXMLValues(JSContext *cx, JSO
JS_ASSERT(JS_InstanceOf(cx, obj, &js_XMLClass, NULL));
xml = (JSXML *) obj->getPrivate();
length = JSXML_LENGTH(xml);
JS_ASSERT(INT_FITS_IN_JSVAL(length));
switch (enum_op) {
case JSENUMERATE_INIT:
if (length == 0) {
- *statep = JSVAL_ZERO;
+ cursor = NULL;
} else {
cursor = cx->create<JSXMLArrayCursor>(&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))) {
if (++index == length)
goto destroy;
}
kidobj = js_GetXMLObject(cx, kid);
if (!kidobj)
@@ -5128,22 +5176,20 @@ js_EnumerateXMLValues(JSContext *cx, JSO
*idp = INT_TO_JSID(index);
*vp = OBJECT_TO_JSVAL(kidobj);
cursor->index = index + 1;
break;
}
/* 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;
}
return JS_TRUE;
}
JSBool
@@ -5426,17 +5472,17 @@ static JSBool
xml_attributes(JSContext *cx, uintN argc, jsval *vp)
{
jsval name = ATOM_KEY(cx->runtime->atomState.starAtom);
JSObject *qn = ToAttributeName(cx, name);
if (!qn)
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);
}
static JSXML *
xml_list_helper(JSContext *cx, JSXML *xml, jsval *rval)
{
JSObject *listobj;
JSXML *list;
@@ -5832,16 +5878,91 @@ again:
static JSBool
xml_hasSimpleContent(JSContext *cx, uintN argc, jsval *vp)
{
XML_METHOD_PROLOG;
*vp = BOOLEAN_TO_JSVAL(HasSimpleContent(xml));
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)
{
uint32 length, i, j, n;
JSObject *ns, *ns2;
JSString *prefix, *prefix2;
length = nsarray->length;
@@ -5873,58 +5994,29 @@ FindInScopeNamespaces(JSContext *cx, JSX
}
}
} while ((xml = xml->parent) != NULL);
JS_ASSERT(length == nsarray->length);
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
xml_insertChildAfter(JSContext *cx, uintN argc, jsval *vp)
{
jsval arg;
JSXML *kid;
uint32 i;
@@ -6014,94 +6106,120 @@ xml_name(JSContext *cx, uintN argc, jsva
*vp = OBJECT_TO_JSVAL(xml->name);
return JS_TRUE;
}
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) {
prefix = NULL;
} 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++) {
ns = XMLARRAY_MEMBER(&inScopeNSes.array, i, JSObject);
if (ns) {
nsprefix = GetPrefix(ns);
if (nsprefix && js_EqualStrings(nsprefix, prefix))
break;
ns = NULL;
}
}
}
*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;
-
- AutoNamespaceArray ancestors(cx);
- AutoNamespaceArray declared(cx);
-
- JSXML *yml = xml;
+ return JS_TRUE;
+
+ /* From here, control flow must goto out to finish these arrays. */
+ ok = JS_TRUE;
+ InitTempNSArray(cx, &ancestors);
+ InitTempNSArray(cx, &declared);
+ 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;
- }
- }
-
- return declared.toJSArray(vp);
+ ok = XMLARRAY_APPEND(cx, &declared.array, ns);
+ if (!ok)
+ goto out;
+ }
+ }
+
+ 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";
static const char js_text_str[] = "text";
/* Exported to jsgc.c #ifdef DEBUG. */
const char *js_xml_class_str[] = {
"list",
@@ -7124,19 +7242,19 @@ js_TraceXML(JSTracer *trc, JSXML *xml)
XMLArrayTrim(&xml->xml_kids);
if (xml->xml_class == JSXML_CLASS_LIST) {
if (xml->xml_target)
JS_CALL_TRACER(trc, xml->xml_target, JSTRACE_XML, "target");
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);
xml_trace_vector(trc,
(JSXML **) xml->xml_attrs.vector,
xml->xml_attrs.length);
XMLArrayCursorTrace(trc, xml->xml_attrs.cursors);
@@ -7159,22 +7277,27 @@ js_FinalizeXML(JSContext *cx, JSXML *xml
#ifdef DEBUG_notme
JS_REMOVE_LINK(&xml->links);
#endif
}
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 *
NewXMLObject(JSContext *cx, JSXML *xml)
{
JSObject *obj;
obj = js_NewObject(cx, &js_XMLClass, NULL, NULL);
@@ -7681,45 +7804,58 @@ js_FindXMLProperty(JSContext *cx, jsval
JSMSG_UNDEFINED_XML_NAME, printable);
}
return JS_FALSE;
}
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);
- }
-
- JSXML *xml = (JSXML *) obj->getPrivate();
- if (!HasSimpleContent(xml))
- return true;
-
- /* 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);
+ tvr.u.object = target;
+ }
+
+ 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);
+ }
+
+ out:
+ JS_POP_TEMP_ROOT(cx, &tvr);
+ return ok;
}
static JSXML *
GetPrivate(JSContext *cx, JSObject *obj, const char *method)
{
JSXML *xml;
xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL);
--- a/js/src/jsxml.h
+++ b/js/src/jsxml.h
@@ -34,17 +34,17 @@
* 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 jsxml_h___
#define jsxml_h___
-#include "jsarray.h"
+#include "jspubtd.h"
JS_BEGIN_EXTERN_C
extern const char js_AnyName_str[];
extern const char js_AttributeName_str[];
extern const char js_isXMLName_str[];
extern const char js_XMLList_str[];
@@ -58,68 +58,16 @@ typedef JSBool
struct JSXMLArray {
uint32 length;
uint32 capacity;
void **vector;
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)
/*
* NB: don't reorder this enum without changing all array initializers that
* depend on it in jsxml.c.
*/
--- a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp
+++ b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp
@@ -35,17 +35,17 @@
* 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 ***** */
#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"
// This file implements a wrapper around trusted objects that allows them to
// be safely injected into untrusted code.
namespace {
@@ -278,26 +278,27 @@ WrapObject(JSContext *cx, JSObject *pare
JSObject *wrapperObj =
JS_NewObjectWithGivenProto(cx, &COWClass.base, NULL, parent);
if (!wrapperObj) {
return JS_FALSE;
}
*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;
}
return JS_TRUE;
}
} // namespace ChromeObjectWrapper
@@ -772,17 +773,17 @@ XPC_COW_Iterator(JSContext *cx, JSObject
}
JSObject *wrapperIter = JS_NewObject(cx, &COWClass.base, nsnull,
JS_GetGlobalForObject(cx, obj));
if (!wrapperIter) {
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);
if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot, v) ||
!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot,
JSVAL_ZERO)) {
return nsnull;
}
--- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
+++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
@@ -35,17 +35,17 @@
* 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 ***** */
#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"
// This file implements a wrapper around objects that allows them to be
// accessed safely from across origins.
static JSBool
@@ -825,17 +825,17 @@ GetUXPCObject(JSContext *cx, JSObject *o
}
JSObject *uxpco =
JS_NewObjectWithGivenProto(cx, &XOWClass.base, nsnull, obj->getParent());
if (!uxpco) {
return nsnull;
}
- js::AutoValueRooter tvr(cx, uxpco);
+ JSAutoTempValueRooter tvr(cx, uxpco);
jsval wrappedObj, parentScope;
if (!JS_GetReservedSlot(cx, obj, sWrappedObjSlot, &wrappedObj) ||
!JS_GetReservedSlot(cx, obj, XPC_XOW_ScopeSlot, &parentScope)) {
return nsnull;
}
if (!JS_SetReservedSlot(cx, uxpco, sWrappedObjSlot, wrappedObj) ||
@@ -1201,17 +1201,17 @@ XPC_XOW_Iterator(JSContext *cx, JSObject
}
JSObject *wrapperIter = JS_NewObject(cx, &XOWClass.base, nsnull,
JS_GetGlobalForObject(cx, obj));
if (!wrapperIter) {
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);
if (!JS_SetReservedSlot(cx, wrapperIter, sWrappedObjSlot, v) ||
!JS_SetReservedSlot(cx, wrapperIter, sFlagsSlot, JSVAL_ZERO) ||
!JS_SetReservedSlot(cx, wrapperIter, XPC_XOW_ScopeSlot,
PRIVATE_TO_JSVAL(nsnull))) {
return nsnull;
--- a/js/src/xpconnect/src/XPCNativeWrapper.cpp
+++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp
@@ -1113,17 +1113,17 @@ XPC_NW_Iterator(JSContext *cx, JSObject
JSObject *wrapperIter =
JS_NewObjectWithGivenProto(cx, XPCNativeWrapper::GetJSClass(), nsnull,
obj->getParent());
if (!wrapperIter) {
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<XPCWrappedNative *>(JS_GetPrivate(cx, obj));
JS_SetPrivate(cx, wrapperIter, wn);
if (!JS_SetReservedSlot(cx, wrapperIter, 0,
INT_TO_JSVAL(FLAG_DEEP | FLAG_EXPLICIT))) {
return nsnull;
}
--- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
+++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
@@ -473,17 +473,17 @@ XPC_SJOW_DelProperty(JSContext *cx, JSOb
}
return XPCWrapper::DelProperty(cx, unsafeObj, id, 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
// we're about to set aside the frame chain.
nsresult rv = ssm->PushContextPrincipal(cx, nsnull, principal);
if (NS_FAILED(rv)) {
NS_WARNING("Not allowing call because we're out of memory");
JS_ReportOutOfMemory(cx);
@@ -512,17 +512,17 @@ public:
ssm->PopContextPrincipal(cx);
}
}
}
private:
JSContext *cx;
JSRegExpStatics statics;
- js::AutoValueRooter tvr;
+ JSTempValueRooter tvr;
uint32 options;
JSStackFrame *fp;
};
static JSBool
XPC_SJOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
JSBool aIsSet)
{
@@ -952,17 +952,17 @@ XPC_SJOW_Iterator(JSContext *cx, JSObjec
if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot,
OBJECT_TO_JSVAL(unsafeObj)) ||
!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot,
JSVAL_ZERO)) {
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,
keysonly);
}
static JSObject *
XPC_SJOW_WrappedObject(JSContext *cx, JSObject *obj)
--- a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp
+++ b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp
@@ -35,17 +35,17 @@
* 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 ***** */
#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"
// This file implements a wrapper around trusted objects that allows them to
// be safely injected into untrusted code.
static JSBool
XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
@@ -132,17 +132,17 @@ WrapObject(JSContext *cx, JSObject *pare
JSObject *wrapperObj =
JS_NewObjectWithGivenProto(cx, &SOWClass.base, NULL, parent);
if (!wrapperObj) {
return JS_FALSE;
}
*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)) {
return JS_FALSE;
}
return JS_TRUE;
}
@@ -432,17 +432,17 @@ XPC_SOW_GetOrSetProperty(JSContext *cx,
if (!obj) {
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
}
if (!AllowedToAct(cx, id)) {
return JS_FALSE;
}
- js::AutoArrayRooter tvr(cx, 1, vp);
+ JSAutoTempValueRooter tvr(cx, 1, vp);
JSObject *wrappedObj = GetWrappedObject(cx, obj);
if (!wrappedObj) {
return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
}
if (isSet && id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_PROTO)) {
// No setting __proto__ on my object.
@@ -644,17 +644,17 @@ XPC_SOW_Iterator(JSContext *cx, JSObject
}
JSObject *wrapperIter = JS_NewObject(cx, &SOWClass.base, nsnull,
JS_GetGlobalForObject(cx, obj));
if (!wrapperIter) {
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);
if (!JS_SetReservedSlot(cx, wrapperIter, sWrappedObjSlot, v) ||
!JS_SetReservedSlot(cx, wrapperIter, sFlagsSlot, JSVAL_ZERO)) {
return nsnull;
}
--- a/js/src/xpconnect/src/XPCWrapper.cpp
+++ b/js/src/xpconnect/src/XPCWrapper.cpp
@@ -148,17 +148,17 @@ IteratorNext(JSContext *cx, uintN argc,
jsval name;
JSString *str;
if (!JS_IdToValue(cx, id, &name) ||
!(str = JS_ValueToString(cx, name))) {
return JS_FALSE;
}
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;
}
*vp = OBJECT_TO_JSVAL(array);
}
@@ -187,17 +187,17 @@ CreateIteratorObj(JSContext *cx, JSObjec
// identifiers with a next method, so we create an object that
// delegates (via the __proto__ link) to the wrapper.
JSObject *iterObj = JS_NewObject(cx, &IteratorClass, tempWrapper, wrapperObj);
if (!iterObj) {
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.
if (!JS_SetReservedSlot(cx, iterObj, 0, PRIVATE_TO_JSVAL(nsnull))) {
return nsnull;
}
// Initialize iterObj.
@@ -208,17 +208,17 @@ CreateIteratorObj(JSContext *cx, JSObjec
if (XPCNativeWrapper::IsNativeWrapper(wrapperObj)) {
// For native wrappers, expandos on the wrapper itself aren't propagated
// to the wrapped object, so we have to actually iterate the wrapper here.
// In order to do so, we set the prototype of the iter to the wrapper,
// 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)) {
return nsnull;
}
}
// Start enumerating over all of our properties.
--- a/js/src/xpconnect/src/qsgen.py
+++ b/js/src/xpconnect/src/qsgen.py
@@ -828,17 +828,17 @@ def writeQuickStub(f, customMethodCalls,
# which is vp[1]; and it's ok to overwrite it.
f.write(" if (!xpc_qsUnwrapThisFromCcx(ccx, &self, &selfref.ptr, "
"&vp[1]))\n")
f.write(" return JS_FALSE;\n")
else:
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]
if not isSetter and isInterfaceType(member.realtype):
f.write(" XPCLazyCallContext lccx(JS_CALLER, cx, obj);\n")
f.write(" if (!xpc_qsUnwrapThis(cx, obj, callee, &self, "
"&selfref.ptr, %s, &lccx))\n" % pthisval)
--- a/js/src/xpconnect/src/xpcconvert.cpp
+++ b/js/src/xpconnect/src/xpcconvert.cpp
@@ -1577,33 +1577,33 @@ XPCConvert::ConstructException(nsresult
if(sz)
JS_smprintf_free(sz);
return res;
}
/********************************/
-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
nsresult
XPCConvert::JSValToXPCException(XPCCallContext& ccx,
jsval s,
const char* ifaceName,
const char* methodName,
--- a/js/src/xpconnect/src/xpcquickstubs.cpp
+++ b/js/src/xpconnect/src/xpcquickstubs.cpp
@@ -168,17 +168,17 @@ GeneratePropertyOp(JSContext *cx, JSObje
JSFunction *fun =
JS_NewFunction(cx, reinterpret_cast<JSNative>(PropertyOpForwarder),
argc, JSFUN_FAST_NATIVE, obj, name);
if(!fun)
return JS_FALSE;
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.
JSObject *ptrobj = JS_NewObject(cx, &PointerHolderClass, nsnull, funobj);
if(!ptrobj)
return JS_FALSE;
JSPropertyOp *popp = new JSPropertyOp;
if(!popp)
@@ -193,17 +193,17 @@ GeneratePropertyOp(JSContext *cx, JSObje
static JSBool
ReifyPropertyOps(JSContext *cx, JSObject *obj, jsval idval, jsid interned_id,
const char *name, JSPropertyOp getter, JSPropertyOp setter,
JSObject **getterobjp, JSObject **setterobjp)
{
// 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;
if(getter)
{
getterobj = GeneratePropertyOp(cx, obj, idval, 0, name, getter);
if(!getterobj)
return JS_FALSE;
--- a/js/src/xpconnect/src/xpcquickstubs.h
+++ b/js/src/xpconnect/src/xpcquickstubs.h
@@ -316,17 +316,17 @@ struct xpc_qsSelfRef
template<size_t N>
struct xpc_qsArgValArray
{
xpc_qsArgValArray(JSContext *cx) : tvr(cx, N, array)
{
memset(array, 0, N * sizeof(jsval));
}
- js::AutoArrayRooter tvr;
+ JSAutoTempValueRooter tvr;
jsval array[N];
};
/**
* Convert a jsval to char*, returning JS_TRUE on success.
*
* @param cx
* A context.
--- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp
@@ -1512,42 +1512,43 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS
{
XPCThrower::Throw(NS_ERROR_FAILURE, cx);
return nsnull;
}
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)
{
JSScript* script = JS_GetFrameScript(cx, fp);
PRUint32 flags = script ? JS_GetScriptFilenameFlags(script) : 0;
NS_ASSERTION(flags != JSFILENAME_NULL, "Null filename!");
nsXPConnect *xpc = nsXPConnect::GetXPConnect();
if(!xpc)
{
XPCThrower::Throw(NS_ERROR_FAILURE, cx);
return nsnull;
}
nsresult rv = xpc->GetWrapperForObject(cx, obj, scope, principal, flags,
- retval.addr());
+ &retval);
if(NS_FAILED(rv))
{
XPCThrower::Throw(rv, cx);
return nsnull;
}
}
- return JSVAL_TO_OBJECT(retval.value());
+ return JSVAL_TO_OBJECT(retval);
}
JSObjectOps *
XPC_WN_GetObjectOpsNoCall(JSContext *cx, JSClass *clazz)
{
return &XPC_WN_NoCall_JSOps;
}
--- a/js/src/xpconnect/tests/TestXPC.cpp
+++ b/js/src/xpconnect/tests/TestXPC.cpp
@@ -557,17 +557,17 @@ TestArgFormatter(JSContext* jscontext, J
return;
}
do {
JSAutoRequest ar(jscontext);
// 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",
a_in,
&NS_GET_IID(nsITestXPCFoo2), b_in.get(),
c_in.get(),
static_cast<const nsAString*>(&d_in),
e_in))
--- a/modules/plugin/base/src/nsJSNPRuntime.cpp
+++ b/modules/plugin/base/src/nsJSNPRuntime.cpp
@@ -668,46 +668,46 @@ doInvoke(NPObject *npobj, NPIdentifier m
jsargs = (jsval *)PR_Malloc(argCount * sizeof(jsval));
if (!jsargs) {
::JS_ReportOutOfMemory(cx);
return PR_FALSE;
}
}
+ 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);
-
- // 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 (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;
- }
- } else {
- ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs, &v);
- }
-
+ } else {
+ ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs, &v);
}
+ JS_POP_TEMP_ROOT(cx, &tvr);
+
if (jsargs != jsargs_buf)
PR_Free(jsargs);
if (ok)
ok = JSValToNPVariant(npp, cx, v, result);
// return ok == JS_TRUE to quiet down compiler warning, even if
// return ok is what we really want.
@@ -832,17 +832,17 @@ nsJSObjWrapper::NP_SetProperty(NPObject
jsval id = (jsval)identifier;
JSBool ok = JS_FALSE;
AutoCXPusher pusher(cx);
JSAutoRequest ar(cx);
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);
ok = ::JS_SetUCProperty(cx, npjsobj->mJSObj, ::JS_GetStringChars(str),
::JS_GetStringLength(str), &v);
} else {
NS_ASSERTION(JSVAL_IS_INT(id), "id must be either string or int!\n");
--- a/modules/plugin/base/src/nsNPAPIPlugin.cpp
+++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp
@@ -1688,17 +1688,17 @@ bool NP_CALLBACK
nsNPObjWrapper::GetNewOrUsed(npp, cx, npobj);
if (!obj) {
return false;
}
// 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) {
// Initialize the out param to void
VOID_TO_NPVARIANT(*result);
}
if (!script || !script->UTF8Length || !script->UTF8Characters) {
--- a/xpinstall/src/nsXPITriggerInfo.cpp
+++ b/xpinstall/src/nsXPITriggerInfo.cpp
@@ -242,17 +242,17 @@ XPITriggerEvent::Run()
JSObject* innerGlobal = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(cbval));
jsval components;
if (!JS_LookupProperty(cx, innerGlobal, "Components", &components) ||
!JSVAL_IS_OBJECT(components))
return 0;
// 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());
if (!str)
return 0;
args[0] = STRING_TO_JSVAL(str);
// args[1] is the status