--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1743,56 +1743,49 @@ private:
#endif
};
class NS_STACK_CLASS nsAutoGCRoot {
public:
// aPtr should be the pointer to the jsval we want to protect
nsAutoGCRoot(jsval* aPtr, nsresult* aResult
MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM) :
- mPtr(aPtr)
+ mPtr(aPtr), mRootType(RootType_JSVal)
{
MOZILLA_GUARD_OBJECT_NOTIFIER_INIT;
- mResult = *aResult = AddJSGCRoot(aPtr, "nsAutoGCRoot");
+ mResult = *aResult = AddJSGCRoot(aPtr, RootType_JSVal, "nsAutoGCRoot");
}
// aPtr should be the pointer to the JSObject* we want to protect
nsAutoGCRoot(JSObject** aPtr, nsresult* aResult
MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM) :
- mPtr(aPtr)
+ mPtr(aPtr), mRootType(RootType_Object)
{
MOZILLA_GUARD_OBJECT_NOTIFIER_INIT;
- mResult = *aResult = AddJSGCRoot(aPtr, "nsAutoGCRoot");
- }
-
- // aPtr should be the pointer to the thing we want to protect
- nsAutoGCRoot(void* aPtr, nsresult* aResult
- MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM) :
- mPtr(aPtr)
- {
- MOZILLA_GUARD_OBJECT_NOTIFIER_INIT;
- mResult = *aResult = AddJSGCRoot(aPtr, "nsAutoGCRoot");
+ mResult = *aResult = AddJSGCRoot(aPtr, RootType_Object, "nsAutoGCRoot");
}
~nsAutoGCRoot() {
if (NS_SUCCEEDED(mResult)) {
- RemoveJSGCRoot(mPtr);
+ RemoveJSGCRoot(mPtr, mRootType);
}
}
static void Shutdown();
private:
- static nsresult AddJSGCRoot(void *aPtr, const char* aName);
- static nsresult RemoveJSGCRoot(void *aPtr);
+ enum RootType { RootType_JSVal, RootType_Object };
+ static nsresult AddJSGCRoot(void *aPtr, RootType aRootType, const char* aName);
+ static nsresult RemoveJSGCRoot(void *aPtr, RootType aRootType);
static nsIJSRuntimeService* sJSRuntimeService;
static JSRuntime* sJSScriptRuntime;
void* mPtr;
+ RootType mRootType;
nsresult mResult;
MOZILLA_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class NS_STACK_CLASS nsAutoScriptBlocker {
public:
nsAutoScriptBlocker(MOZILLA_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) {
MOZILLA_GUARD_OBJECT_NOTIFIER_INIT;
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -3077,51 +3077,57 @@ nsContentUtils::GetContentPolicy()
sTriedToGetContentPolicy = PR_TRUE;
}
return sContentPolicyService;
}
// static
nsresult
-nsAutoGCRoot::AddJSGCRoot(void* aPtr, const char* aName)
+nsAutoGCRoot::AddJSGCRoot(void* aPtr, RootType aRootType, const char* aName)
{
if (!sJSScriptRuntime) {
nsresult rv = CallGetService("@mozilla.org/js/xpc/RuntimeService;1",
&sJSRuntimeService);
NS_ENSURE_TRUE(sJSRuntimeService, rv);
sJSRuntimeService->GetRuntime(&sJSScriptRuntime);
if (!sJSScriptRuntime) {
NS_RELEASE(sJSRuntimeService);
NS_WARNING("Unable to get JS runtime from JS runtime service");
return NS_ERROR_FAILURE;
}
}
PRBool ok;
- ok = ::JS_AddNamedRootRT(sJSScriptRuntime, aPtr, aName);
+ if (aRootType == RootType_JSVal)
+ ok = ::js_AddRootRT(sJSScriptRuntime, (jsval *)aPtr, aName);
+ else
+ ok = ::js_AddGCThingRootRT(sJSScriptRuntime, (void **)aPtr, aName);
if (!ok) {
NS_WARNING("JS_AddNamedRootRT failed");
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
/* static */
nsresult
-nsAutoGCRoot::RemoveJSGCRoot(void* aPtr)
+nsAutoGCRoot::RemoveJSGCRoot(void* aPtr, RootType aRootType)
{
if (!sJSScriptRuntime) {
NS_NOTREACHED("Trying to remove a JS GC root when none were added");
return NS_ERROR_UNEXPECTED;
}
- ::JS_RemoveRootRT(sJSScriptRuntime, aPtr);
+ if (aRootType == RootType_JSVal)
+ ::js_RemoveRoot(sJSScriptRuntime, (jsval *)aPtr);
+ else
+ ::js_RemoveRoot(sJSScriptRuntime, (JSObject **)aPtr);
return NS_OK;
}
// static
PRBool
nsContentUtils::IsEventAttributeName(nsIAtom* aName, PRInt32 aType)
{
--- a/content/canvas/src/NativeJSContext.cpp
+++ b/content/canvas/src/NativeJSContext.cpp
@@ -1,40 +1,20 @@
#include "NativeJSContext.h"
#include "nsServiceManagerUtils.h"
#include "nsIJSRuntimeService.h"
-nsIJSRuntimeService* NativeJSContext::sJSRuntimeService = 0;
-JSRuntime* NativeJSContext::sJSScriptRuntime = 0;
-
PRBool
-NativeJSContext::AddGCRoot(void *aPtr, const char *aName)
+NativeJSContext::AddGCRoot(JSObject **aPtr, const char *aName)
{
NS_ASSERTION(NS_SUCCEEDED(error), "class failed to initialize and caller used class without checking!");
- if (!sJSScriptRuntime) {
- nsresult rv = CallGetService("@mozilla.org/js/xpc/RuntimeService;1",
- &sJSRuntimeService);
- NS_ENSURE_SUCCESS(rv, PR_FALSE);
- NS_ABORT_IF_FALSE(sJSRuntimeService, "CallGetService succeeded but returned a null pointer?");
-
- sJSRuntimeService->GetRuntime(&sJSScriptRuntime);
- if (!sJSScriptRuntime) {
- NS_RELEASE(sJSRuntimeService);
- NS_WARNING("Unable to get JS runtime from JS runtime service");
- return PR_FALSE;
- }
- }
PRBool ok;
- return ok = ::JS_AddNamedRootRT(sJSScriptRuntime, aPtr, aName);
+ return ok = ::JS_AddNamedObjectRoot(ctx, aPtr, aName);
}
void
-NativeJSContext::ReleaseGCRoot(void *aPtr)
+NativeJSContext::ReleaseGCRoot(JSObject **aPtr)
{
NS_ASSERTION(NS_SUCCEEDED(error), "class failed to initialize and caller used class without checking!");
- if (!sJSScriptRuntime) {
- NS_NOTREACHED("Trying to remove a JS GC root when none were added");
- return;
- }
- ::JS_RemoveRootRT(sJSScriptRuntime, aPtr);
+ ::JS_RemoveObjectRoot(ctx, aPtr);
}
--- a/content/canvas/src/NativeJSContext.h
+++ b/content/canvas/src/NativeJSContext.h
@@ -57,18 +57,18 @@ public:
if (!JSVAL_IS_NULL(val) &&
JSVAL_IS_OBJECT(val) &&
::JS_IsArrayObject(ctx, JSVAL_TO_OBJECT(val)) &&
::JS_GetArrayLength(ctx, JSVAL_TO_OBJECT(val), sz))
return PR_TRUE;
return PR_FALSE;
}
- PRBool AddGCRoot (void *aPtr, const char *aName);
- void ReleaseGCRoot (void *aPtr);
+ PRBool AddGCRoot (JSObject **aPtr, const char *aName);
+ void ReleaseGCRoot (JSObject **aPtr);
void SetRetVal (PRInt32 val) {
NS_ASSERTION(NS_SUCCEEDED(error), "class failed to initialize and caller used class without checking!");
if (INT_FITS_IN_JSVAL(val))
SetRetValAsJSVal(INT_TO_JSVAL(val));
else
SetRetVal((double) val);
}
@@ -181,19 +181,16 @@ public:
void SetRetVal (JSObjectHelper& objh);
nsAXPCNativeCallContext *ncc;
nsresult error;
JSContext *ctx;
PRUint32 argc;
jsval *argv;
- static nsIJSRuntimeService* sJSRuntimeService;
- static JSRuntime* sJSScriptRuntime;
-
public:
// static JS helpers
static inline PRBool JSValToFloatArray (JSContext *ctx, jsval val,
jsuint cnt, float *array)
{
JSObject *arrayObj;
jsuint arrayLen;
--- a/js/jsd/jsd_val.c
+++ b/js/jsd/jsd_val.c
@@ -226,17 +226,17 @@ jsd_GetValueString(JSDContext* jsdc, JSD
else
{
JS_BeginRequest(cx);
exceptionState = JS_SaveExceptionState(cx);
jsdval->string = JS_ValueToString(cx, jsdval->val);
JS_RestoreExceptionState(cx, exceptionState);
if(jsdval->string)
{
- if(!JS_AddNamedRoot(cx, &jsdval->string, "ValueString"))
+ if(!JS_AddNamedStringRoot(cx, &jsdval->string, "ValueString"))
jsdval->string = NULL;
}
JS_EndRequest(cx);
}
}
return jsdval->string;
}
@@ -270,17 +270,17 @@ jsd_NewValue(JSDContext* jsdc, jsval val
if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
return NULL;
if(JSVAL_IS_GCTHING(val))
{
JSBool ok = JS_FALSE;
JS_BeginRequest(jsdc->dumbContext);
- ok = JS_AddNamedRoot(jsdc->dumbContext, &jsdval->val, "JSDValue");
+ ok = JS_AddNamedValueRoot(jsdc->dumbContext, &jsdval->val, "JSDValue");
JS_EndRequest(jsdc->dumbContext);
if(!ok)
{
free(jsdval);
return NULL;
}
}
jsdval->val = val;
@@ -295,17 +295,17 @@ jsd_DropValue(JSDContext* jsdc, JSDValue
{
JS_ASSERT(jsdval->nref > 0);
if(0 == --jsdval->nref)
{
jsd_RefreshValue(jsdc, jsdval);
if(JSVAL_IS_GCTHING(jsdval->val))
{
JS_BeginRequest(jsdc->dumbContext);
- JS_RemoveRoot(jsdc->dumbContext, &jsdval->val);
+ JS_RemoveValueRoot(jsdc->dumbContext, &jsdval->val);
JS_EndRequest(jsdc->dumbContext);
}
free(jsdval);
}
}
jsval
jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval)
@@ -417,17 +417,17 @@ jsd_RefreshValue(JSDContext* jsdc, JSDVa
JSContext* cx = jsdc->dumbContext;
if(jsdval->string)
{
/* if the jsval is a string, then we didn't need to root the string */
if(!JSVAL_IS_STRING(jsdval->val))
{
JS_BeginRequest(cx);
- JS_RemoveRoot(cx, &jsdval->string);
+ JS_RemoveStringRoot(cx, &jsdval->string);
JS_EndRequest(cx);
}
jsdval->string = NULL;
}
jsdval->funName = NULL;
jsdval->className = NULL;
DROP_CLEAR_VALUE(jsdc, jsdval->proto);
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -47,23 +47,23 @@
#include <string>
class jsvalRoot
{
public:
explicit jsvalRoot(JSContext *context, jsval value = JSVAL_NULL)
: cx(context), v(value)
{
- if (!JS_AddRoot(cx, &v)) {
+ if (!JS_AddValueRoot(cx, &v)) {
fprintf(stderr, "Out of memory in jsvalRoot constructor, aborting\n");
abort();
}
}
- ~jsvalRoot() { JS_RemoveRoot(cx, &v); }
+ ~jsvalRoot() { JS_RemoveValueRoot(cx, &v); }
operator jsval() const { return value(); }
jsvalRoot & operator=(jsval value) {
v = value;
return *this;
}
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1765,47 +1765,120 @@ JS_NewDoubleValue(JSContext *cx, jsdoubl
JS_PUBLIC_API(JSBool)
JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
{
CHECK_REQUEST(cx);
return js_NewWeaklyRootedNumber(cx, d, rval);
}
#undef JS_AddRoot
+
JS_PUBLIC_API(JSBool)
-JS_AddRoot(JSContext *cx, void *rp)
+JS_AddValueRoot(JSContext *cx, jsval *vp)
{
CHECK_REQUEST(cx);
- return js_AddRoot(cx, rp, NULL);
+ return js_AddRoot(cx, vp, NULL);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddStringRoot(JSContext *cx, JSString **rp)
+{
+ CHECK_REQUEST(cx);
+ return js_AddGCThingRoot(cx, (void **)rp, NULL);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddObjectRoot(JSContext *cx, JSObject **rp)
+{
+ CHECK_REQUEST(cx);
+ return js_AddGCThingRoot(cx, (void **)rp, NULL);
}
JS_PUBLIC_API(JSBool)
-JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name)
-{
- return js_AddRootRT(rt, rp, name);
+JS_AddDoubleRoot(JSContext *cx, jsdouble **rp)
+{
+ CHECK_REQUEST(cx);
+ return js_AddGCThingRoot(cx, (void **)rp, NULL);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddGCThingRoot(JSContext *cx, void **rp)
+{
+ CHECK_REQUEST(cx);
+ return js_AddGCThingRoot(cx, (void **)rp, NULL);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name)
+{
+ CHECK_REQUEST(cx);
+ return js_AddRoot(cx, vp, name);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name)
+{
+ CHECK_REQUEST(cx);
+ return js_AddGCThingRoot(cx, (void **)rp, name);
}
JS_PUBLIC_API(JSBool)
-JS_RemoveRoot(JSContext *cx, void *rp)
+JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name)
{
CHECK_REQUEST(cx);
- return js_RemoveRoot(cx->runtime, rp);
+ return js_AddGCThingRoot(cx, (void **)rp, name);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddNamedDoubleRoot(JSContext *cx, jsdouble **rp, const char *name)
+{
+ CHECK_REQUEST(cx);
+ return js_AddGCThingRoot(cx, (void **)rp, name);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name)
+{
+ CHECK_REQUEST(cx);
+ return js_AddGCThingRoot(cx, (void **)rp, name);
}
JS_PUBLIC_API(JSBool)
-JS_RemoveRootRT(JSRuntime *rt, void *rp)
-{
- return js_RemoveRoot(rt, rp);
+JS_RemoveValueRoot(JSContext *cx, jsval *vp)
+{
+ CHECK_REQUEST(cx);
+ return js_RemoveRoot(cx->runtime, (void *)vp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_RemoveStringRoot(JSContext *cx, JSString **rp)
+{
+ CHECK_REQUEST(cx);
+ return js_RemoveRoot(cx->runtime, (void *)rp);
}
JS_PUBLIC_API(JSBool)
-JS_AddNamedRoot(JSContext *cx, void *rp, const char *name)
+JS_RemoveObjectRoot(JSContext *cx, JSObject **rp)
{
CHECK_REQUEST(cx);
- return js_AddRoot(cx, rp, name);
+ return js_RemoveRoot(cx->runtime, (void *)rp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_RemoveDoubleRoot(JSContext *cx, jsdouble **rp)
+{
+ CHECK_REQUEST(cx);
+ return js_RemoveRoot(cx->runtime, (void *)rp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_RemoveGCThingRoot(JSContext *cx, void **rp)
+{
+ CHECK_REQUEST(cx);
+ return js_RemoveRoot(cx->runtime, (void *)rp);
}
JS_PUBLIC_API(void)
JS_ClearNewbornRoots(JSContext *cx)
{
JS_CLEAR_WEAK_ROOTS(&cx->weakRoots);
}
@@ -5319,17 +5392,17 @@ JS_RestoreExceptionState(JSContext *cx,
}
JS_PUBLIC_API(void)
JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
{
CHECK_REQUEST(cx);
if (state) {
if (state->throwing && JSVAL_IS_GCTHING(state->exception))
- JS_RemoveRoot(cx, &state->exception);
+ JS_RemoveValueRoot(cx, &state->exception);
cx->free(state);
}
}
JS_PUBLIC_API(JSErrorReport *)
JS_ErrorFromException(JSContext *cx, jsval v)
{
CHECK_REQUEST(cx);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -898,51 +898,111 @@ JS_NewDouble(JSContext *cx, jsdouble d);
extern JS_PUBLIC_API(JSBool)
JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval);
extern JS_PUBLIC_API(JSBool)
JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval);
/*
- * A JS GC root is a pointer to a JSObject *, JSString *, or jsdouble * that
- * itself points into the GC heap (more recently, we support this extension:
- * a root may be a pointer to a jsval v for which JSVAL_IS_GCTHING(v) is true).
+ * A GC root is a pointer to a jsval, JSObject * or JSString * that itself
+ * points into the GC heap. JS_AddValueRoot takes a pointer to a jsval and
+ * JS_AddGCThingRoot takes a pointer to a JSObject * or JString *.
+ *
+ * Note that, since JS_Add*Root stores the address of a variable (of type
+ * jsval, JSString *, or JSObject *), that variable must live until
+ * JS_Remove*Root is called to remove that variable. For example, after:
*
- * Therefore, you never pass JSObject *obj to JS_AddRoot(cx, obj). You always
- * call JS_AddRoot(cx, &obj), passing obj by reference. And later, before obj
- * or the structure it is embedded within goes out of scope or is freed, you
- * must call JS_RemoveRoot(cx, &obj).
+ * void some_function() {
+ * jsval v;
+ * JS_AddNamedRootedValue(cx, &v, "name");
+ *
+ * the caller must perform
*
- * Also, use JS_AddNamedRoot(cx, &structPtr->memberObj, "structPtr->memberObj")
- * in preference to JS_AddRoot(cx, &structPtr->memberObj), in order to identify
+ * JS_RemoveRootedValue(cx, &v);
+ *
+ * before some_function() returns.
+ *
+ * Also, use JS_AddNamed*Root(cx, &structPtr->memberObj, "structPtr->memberObj")
+ * in preference to JS_Add*Root(cx, &structPtr->memberObj), in order to identify
* roots by their source callsites. This way, you can find the callsite while
- * debugging if you should fail to do JS_RemoveRoot(cx, &structPtr->memberObj)
+ * debugging if you should fail to do JS_Remove*Root(cx, &structPtr->memberObj)
* before freeing structPtr's memory.
*/
extern JS_PUBLIC_API(JSBool)
-JS_AddRoot(JSContext *cx, void *rp);
+JS_AddValueRoot(JSContext *cx, jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AddStringRoot(JSContext *cx, JSString **rp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AddObjectRoot(JSContext *cx, JSObject **rp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AddDoubleRoot(JSContext *cx, jsdouble **rp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AddGCThingRoot(JSContext *cx, void **rp);
#ifdef NAME_ALL_GC_ROOTS
#define JS_DEFINE_TO_TOKEN(def) #def
#define JS_DEFINE_TO_STRING(def) JS_DEFINE_TO_TOKEN(def)
-#define JS_AddRoot(cx,rp) JS_AddNamedRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__))
+#define JS_AddValueRoot(cx,vp) JS_AddNamedValueRoot((cx), (vp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__))
+#define JS_AddStringRoot(cx,rp) JS_AddNamedStringRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__))
+#define JS_AddObjectRoot(cx,rp) JS_AddNamedObjectRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__))
+#define JS_AddDoubleRoot(cx,rp) JS_AddNamedDoubleRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__))
+#define JS_AddGCThingRoot(cx,rp) JS_AddNamedGCThingRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__))
#endif
extern JS_PUBLIC_API(JSBool)
-JS_AddNamedRoot(JSContext *cx, void *rp, const char *name);
+JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AddNamedDoubleRoot(JSContext *cx, jsdouble **rp, const char *name);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name);
+
+extern JS_PUBLIC_API(JSBool)
+JS_RemoveValueRoot(JSContext *cx, jsval *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_RemoveStringRoot(JSContext *cx, JSString **rp);
extern JS_PUBLIC_API(JSBool)
-JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name);
+JS_RemoveObjectRoot(JSContext *cx, JSObject **rp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_RemoveDoubleRoot(JSContext *cx, jsdouble **rp);
extern JS_PUBLIC_API(JSBool)
-JS_RemoveRoot(JSContext *cx, void *rp);
-
-extern JS_PUBLIC_API(JSBool)
-JS_RemoveRootRT(JSRuntime *rt, void *rp);
+JS_RemoveGCThingRoot(JSContext *cx, void **rp);
+
+/* TODO: remove these APIs */
+
+extern JS_FRIEND_API(JSBool)
+js_AddRootRT(JSRuntime *rt, jsval *vp, const char *name);
+
+extern JS_FRIEND_API(JSBool)
+js_AddGCThingRootRT(JSRuntime *rt, void **rp, const char *name);
+
+extern JS_FRIEND_API(JSBool)
+js_RemoveRoot(JSRuntime *rt, void *rp);
+
+/*
+ * This symbol may be used by embedders to detect the change from the old
+ * JS_AddRoot(JSContext *, void *) APIs to the new ones above.
+ */
+#define JS_TYPED_ROOTING_API
/*
* The last GC thing of each type (object, string, double, external string
* types) created on a given context is kept alive until another thing of the
* same type is created, using a newborn root in the context. These newborn
* roots help native code protect newly-created GC-things from GC invocations
* activated before those things can be rooted using local or global roots.
*
@@ -960,17 +1020,17 @@ JS_RemoveRootRT(JSRuntime *rt, void *rp)
*/
extern JS_PUBLIC_API(void)
JS_ClearNewbornRoots(JSContext *cx);
/*
* Scoped local root management allows native functions, getter/setters, etc.
* to avoid worrying about the newborn root pigeon-holes, overloading local
* roots allocated in argv and *rval, or ending up having to call JS_Add*Root
- * and JS_RemoveRoot to manage global roots temporarily.
+ * and JS_Remove*Root to manage global roots temporarily.
*
* Instead, calling JS_EnterLocalRootScope and JS_LeaveLocalRootScope around
* the body of the native hook causes the engine to allocate a local root for
* each newborn created in between the two API calls, using a local root stack
* associated with cx. For example:
*
* JSBool
* my_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
@@ -2222,23 +2282,23 @@ JS_CompileFileHandleForPrincipals(JSCont
/*
* NB: you must use JS_NewScriptObject and root a pointer to its return value
* in order to keep a JSScript and its atoms safe from garbage collection after
* creating the script via JS_Compile* and before a JS_ExecuteScript* call.
* E.g., and without error checks:
*
* JSScript *script = JS_CompileFile(cx, global, filename);
* JSObject *scrobj = JS_NewScriptObject(cx, script);
- * JS_AddNamedRoot(cx, &scrobj, "scrobj");
+ * JS_AddNamedObjectRoot(cx, &scrobj, "scrobj");
* do {
* jsval result;
* JS_ExecuteScript(cx, global, script, &result);
* JS_GC();
* } while (!JSVAL_IS_BOOLEAN(result) || JSVAL_TO_BOOLEAN(result));
- * JS_RemoveRoot(cx, &scrobj);
+ * JS_RemoveObjectRoot(cx, &scrobj);
*/
extern JS_PUBLIC_API(JSObject *)
JS_NewScriptObject(JSContext *cx, JSScript *script);
/*
* Infallible getter for a script's object. If JS_NewScriptObject has not been
* called on script yet, the return value will be null.
*/
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1124,46 +1124,67 @@ js_FinishGC(JSRuntime *rt)
if (!rt->gcRootsHash.empty())
CheckLeakedRoots(rt);
#endif
rt->gcRootsHash.clear();
rt->gcLocksHash.clear();
}
JSBool
-js_AddRoot(JSContext *cx, void *rp, const char *name)
+js_AddRoot(JSContext *cx, jsval *vp, const char *name)
{
- JSBool ok = js_AddRootRT(cx->runtime, rp, name);
+ JSBool ok = js_AddRootRT(cx->runtime, vp, name);
if (!ok)
JS_ReportOutOfMemory(cx);
return ok;
}
JSBool
-js_AddRootRT(JSRuntime *rt, void *rp, const char *name)
+js_AddGCThingRoot(JSContext *cx, void **rp, const char *name)
+{
+ JSBool ok = js_AddGCThingRootRT(cx->runtime, rp, name);
+ if (!ok)
+ JS_ReportOutOfMemory(cx);
+ return ok;
+}
+
+static JSBool
+AddRoot(JSRuntime *rt, void *rp, const char *name)
{
js::GCRoots *roots = &rt->gcRootsHash;
/*
* Due to the long-standing, but now removed, use of rt->gcLock across the
* bulk of js_GC, API users have come to depend on JS_AddRoot etc. locking
* properly with a racing GC, without calling JS_AddRoot from a request.
* We have to preserve API compatibility here, now that we avoid holding
* rt->gcLock across the mark phase (including the root hashtable mark).
*/
AutoLockGC lock(rt);
js_WaitForGC(rt);
return !!roots->put(rp, name);
}
-JSBool
+JS_FRIEND_API(JSBool)
+js_AddRootRT(JSRuntime *rt, jsval *vp, const char *name)
+{
+ return AddRoot(rt, vp, name);
+}
+
+JS_FRIEND_API(JSBool)
+js_AddGCThingRootRT(JSRuntime *rt, void **rp, const char *name)
+{
+ return AddRoot(rt, rp, name);
+}
+
+JS_FRIEND_API(JSBool)
js_RemoveRoot(JSRuntime *rt, void *rp)
{
/*
- * Due to the JS_RemoveRootRT API, we may be called outside of a request.
+ * Due to the JS_RemoveRoot API, we may be called outside of a request.
* Same synchronization drill as above in js_AddRoot.
*/
AutoLockGC lock(rt);
js_WaitForGC(rt);
rt->gcRootsHash.remove(rp);
rt->gcPoke = JS_TRUE;
return JS_TRUE;
}
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -94,23 +94,20 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes
extern void
js_FinishGC(JSRuntime *rt);
extern intN
js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop,
JSStringFinalizeOp newop);
extern JSBool
-js_AddRoot(JSContext *cx, void *rp, const char *name);
+js_AddRoot(JSContext *cx, jsval *vp, const char *name);
extern JSBool
-js_AddRootRT(JSRuntime *rt, void *rp, const char *name);
-
-extern JSBool
-js_RemoveRoot(JSRuntime *rt, void *rp);
+js_AddGCThingRoot(JSContext *cx, void **rp, const char *name);
#ifdef DEBUG
extern void
js_DumpNamedRoots(JSRuntime *rt,
void (*dump)(const char *name, void *rp, void *data),
void *data);
#endif
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -633,17 +633,17 @@ js_BeginJSONParse(JSContext *cx, jsval *
if (!arr)
return NULL;
JSONParser *jp = cx->create<JSONParser>(cx);
if (!jp)
return NULL;
jp->objectStack = arr;
- if (!js_AddRoot(cx, &jp->objectStack, "JSON parse stack"))
+ if (!JS_AddNamedObjectRoot(cx, &jp->objectStack, "JSON parse stack"))
goto bad;
jp->statep = jp->stateStack;
*jp->statep = JSON_PARSE_STATE_INIT;
jp->rootVal = rootVal;
return jp;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -222,20 +222,20 @@ public:
: cx(aCx)
, mThrow(aThrow)
{
mStr = JS_ValueToString(cx, v);
if (!aThrow && !mStr && JS_IsExceptionPending(cx)) {
if (!JS_ReportPendingException(cx))
JS_ClearPendingException(cx);
}
- JS_AddNamedRoot(cx, &mStr, "Value ToString helper");
+ JS_AddNamedStringRoot(cx, &mStr, "Value ToString helper");
}
~ToString() {
- JS_RemoveRoot(cx, &mStr);
+ JS_RemoveStringRoot(cx, &mStr);
}
JSBool threw() { return !mStr; }
jsval getJSVal() { return STRING_TO_JSVAL(mStr); }
const char *getBytes() {
return mStr ? JS_GetStringBytes(mStr) : "(error converting value)";
}
private:
JSContext *cx;
@@ -3258,44 +3258,44 @@ Scatter(JSContext *cx, uintN argc, jsval
if (!sd.cvar)
goto fail;
sd.results = (jsval *) malloc(n * sizeof(jsval));
if (!sd.results)
goto fail;
for (i = 0; i < n; i++) {
sd.results[i] = JSVAL_VOID;
- ok = JS_AddRoot(cx, &sd.results[i]);
+ ok = JS_AddValueRoot(cx, &sd.results[i]);
if (!ok) {
while (i-- > 0)
- JS_RemoveRoot(cx, &sd.results[i]);
+ JS_RemoveValueRoot(cx, &sd.results[i]);
free(sd.results);
sd.results = NULL;
goto fail;
}
}
sd.threads = (ScatterThreadData *) malloc(n * sizeof(ScatterThreadData));
if (!sd.threads)
goto fail;
for (i = 0; i < n; i++) {
sd.threads[i].index = i;
sd.threads[i].shared = &sd;
sd.threads[i].thr = NULL;
sd.threads[i].cx = NULL;
sd.threads[i].fn = JSVAL_NULL;
- ok = JS_AddRoot(cx, &sd.threads[i].fn);
+ ok = JS_AddValueRoot(cx, &sd.threads[i].fn);
if (ok && !JS_GetElement(cx, inArr, (jsint) i, &sd.threads[i].fn)) {
- JS_RemoveRoot(cx, &sd.threads[i].fn);
+ JS_RemoveValueRoot(cx, &sd.threads[i].fn);
ok = JS_FALSE;
}
if (!ok) {
while (i-- > 0)
- JS_RemoveRoot(cx, &sd.threads[i].fn);
+ JS_RemoveValueRoot(cx, &sd.threads[i].fn);
free(sd.threads);
sd.threads = NULL;
goto fail;
}
}
global = JS_GetGlobalObject(cx);
for (i = 1; i < n; i++) {
@@ -3353,28 +3353,28 @@ success:
*vp = OBJECT_TO_JSVAL(arr);
ok = JS_TRUE;
out:
if (sd.threads) {
JSContext *acx;
for (i = 0; i < n; i++) {
- JS_RemoveRoot(cx, &sd.threads[i].fn);
+ JS_RemoveValueRoot(cx, &sd.threads[i].fn);
acx = sd.threads[i].cx;
if (acx) {
JS_SetContextThread(acx);
DestroyContext(acx, true);
}
}
free(sd.threads);
}
if (sd.results) {
for (i = 0; i < n; i++)
- JS_RemoveRoot(cx, &sd.results[i]);
+ JS_RemoveValueRoot(cx, &sd.results[i]);
free(sd.results);
}
if (sd.cvar)
PR_DestroyCondVar(sd.cvar);
if (sd.lock)
PR_DestroyLock(sd.lock);
return ok;
@@ -4194,23 +4194,23 @@ its_setter(JSContext *cx, JSObject *obj,
}
val = new jsval;
if (!val) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
}
- if (!JS_AddRoot(cx, val)) {
+ if (!JS_AddValueRoot(cx, val)) {
delete val;
return JS_FALSE;
}
if (!JS_SetPrivate(cx, obj, (void*)val)) {
- JS_RemoveRoot(cx, val);
+ JS_RemoveValueRoot(cx, val);
delete val;
return JS_FALSE;
}
*val = *vp;
return JS_TRUE;
}
@@ -4432,17 +4432,17 @@ its_convert(JSContext *cx, JSObject *obj
static void
its_finalize(JSContext *cx, JSObject *obj)
{
jsval *rootedVal;
if (its_noisy)
fprintf(gOutFile, "finalizing it\n");
rootedVal = (jsval *) JS_GetPrivate(cx, obj);
if (rootedVal) {
- JS_RemoveRoot(cx, rootedVal);
+ JS_RemoveValueRoot(cx, rootedVal);
JS_SetPrivate(cx, obj, NULL);
delete rootedVal;
}
}
static JSClass its_class = {
"It", JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE | JSCLASS_HAS_PRIVATE,
its_addProperty, its_delProperty, its_getProperty, its_setProperty,
@@ -5011,27 +5011,27 @@ shell(JSContext *cx, int argc, char **ar
#endif /* JSDEBUGGER */
#ifdef JS_THREADSAFE
class ShellWorkerHooks : public js::workers::WorkerHooks {
public:
JSObject *newGlobalObject(JSContext *cx) { return NewGlobalObject(cx); }
};
ShellWorkerHooks hooks;
- if (!JS_AddNamedRoot(cx, &gWorkers, "Workers") ||
+ if (!JS_AddNamedObjectRoot(cx, &gWorkers, "Workers") ||
!js::workers::init(cx, &hooks, glob, &gWorkers)) {
return 1;
}
#endif
int result = ProcessArgs(cx, glob, argv, argc);
#ifdef JS_THREADSAFE
js::workers::finish(cx, gWorkers);
- JS_RemoveRoot(cx, &gWorkers);
+ JS_RemoveObjectRoot(cx, &gWorkers);
if (result == 0)
result = gExitCode;
#endif
#ifdef JSDEBUGGER
if (jsdc) {
#ifdef JSDEBUGGER_C_UI
if (jsdbc)
--- a/js/src/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.cpp
@@ -1389,17 +1389,17 @@ mozJSComponentLoader::GlobalForLocation(
nsCAutoString path;
aComponent->GetNativePath(path);
*aLocation = ToNewCString(path);
if (!*aLocation) {
*aGlobal = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
- JS_AddNamedRoot(cx, aGlobal, *aLocation);
+ JS_AddNamedObjectRoot(cx, aGlobal, *aLocation);
return NS_OK;
}
void
mozJSComponentLoader::UnloadModules()
{
mInitialized = PR_FALSE;
--- a/js/src/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.h
@@ -146,17 +146,17 @@ class mozJSComponentLoader : public nsIM
}
~ModuleEntry() {
module = nsnull;
if (global) {
JSAutoRequest ar(sSelf->mContext);
JS_ClearScope(sSelf->mContext, global);
- JS_RemoveRoot(sSelf->mContext, &global);
+ JS_RemoveObjectRoot(sSelf->mContext, &global);
}
if (location)
NS_Free(location);
}
nsCOMPtr<nsIModule> module;
JSObject *global;
--- a/js/src/xpconnect/public/nsAutoJSValHolder.h
+++ b/js/src/xpconnect/public/nsAutoJSValHolder.h
@@ -77,17 +77,17 @@ public:
}
/**
* Hold by rooting on the runtime.
* Note that mGCThing may be JSVAL_NULL, which is not a problem.
*/
JSBool Hold(JSRuntime* aRt) {
if (!mHeld) {
- if (JS_AddNamedRootRT(aRt, &mGCThing, "nsAutoJSValHolder")) {
+ if (js_AddGCThingRootRT(aRt, &mGCThing, "nsAutoJSValHolder")) {
mRt = aRt;
mHeld = JS_TRUE;
} else {
Release(); // out of memory
}
}
return mHeld;
}
@@ -97,17 +97,17 @@ public:
* the original jsval.
*/
jsval Release() {
NS_ASSERTION(!mHeld || mRt, "Bad!");
jsval oldval = mVal;
if (mHeld) {
- JS_RemoveRootRT(mRt, &mGCThing); // infallible
+ js_RemoveRoot(mRt, &mGCThing); // infallible
mHeld = JS_FALSE;
}
mVal = JSVAL_NULL;
mGCThing = NULL;
mRt = NULL;
return oldval;
--- a/modules/plugin/base/src/nsJSNPRuntime.cpp
+++ b/modules/plugin/base/src/nsJSNPRuntime.cpp
@@ -578,17 +578,17 @@ nsJSObjWrapper::NP_Deallocate(NPObject *
// static
void
nsJSObjWrapper::NP_Invalidate(NPObject *npobj)
{
nsJSObjWrapper *jsnpobj = (nsJSObjWrapper *)npobj;
if (jsnpobj && jsnpobj->mJSObj) {
// Unroot the object's JSObject
- ::JS_RemoveRootRT(sJSRuntime, &jsnpobj->mJSObj);
+ js_RemoveRoot(sJSRuntime, &jsnpobj->mJSObj);
if (sJSObjWrappers.ops) {
// Remove the wrapper from the hash
nsJSObjWrapperKey key(jsnpobj->mJSObj, jsnpobj->mNpp);
PL_DHashTableOperate(&sJSObjWrappers, &key, PL_DHASH_REMOVE);
}
@@ -1152,17 +1152,17 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JS
entry->mJSObjWrapper = wrapper;
NS_ASSERTION(wrapper->mNpp == npp, "nsJSObjWrapper::mNpp not initialized!");
JSAutoRequest ar(cx);
// Root the JSObject, its lifetime is now tied to that of the
// NPObject.
- if (!::JS_AddNamedRoot(cx, &wrapper->mJSObj, "nsJSObjWrapper::mJSObject")) {
+ if (!::JS_AddNamedObjectRoot(cx, &wrapper->mJSObj, "nsJSObjWrapper::mJSObject")) {
NS_ERROR("Failed to root JSObject!");
_releaseobject(wrapper);
PL_DHashTableRawRemove(&sJSObjWrappers, entry);
return nsnull;
}
@@ -2132,17 +2132,17 @@ CreateNPObjectMember(NPP npp, JSContext
JSObject *memobj = ::JS_NewObject(cx, &sNPObjectMemberClass, nsnull, nsnull);
if (!memobj) {
PR_Free(memberPrivate);
return JS_FALSE;
}
*vp = OBJECT_TO_JSVAL(memobj);
- ::JS_AddRoot(cx, vp);
+ ::JS_AddValueRoot(cx, vp);
::JS_SetPrivate(cx, memobj, (void *)memberPrivate);
jsval fieldValue;
NPVariant npv;
NPBool hasProperty;
if (getPropertyResult) {
@@ -2151,22 +2151,22 @@ CreateNPObjectMember(NPP npp, JSContext
hasProperty = true;
}
else {
VOID_TO_NPVARIANT(npv);
NPBool hasProperty = npobj->_class->getProperty(npobj, (NPIdentifier)id,
&npv);
if (!ReportExceptionIfPending(cx)) {
- ::JS_RemoveRoot(cx, vp);
+ ::JS_RemoveValueRoot(cx, vp);
return JS_FALSE;
}
if (!hasProperty) {
- ::JS_RemoveRoot(cx, vp);
+ ::JS_RemoveValueRoot(cx, vp);
return JS_FALSE;
}
}
fieldValue = NPVariantToJSVal(npp, cx, &npv);
// npobjWrapper is the JSObject through which we make sure we don't
// outlive the underlying NPObject, so make sure it points to the
@@ -2176,17 +2176,17 @@ CreateNPObjectMember(NPP npp, JSContext
}
memberPrivate->npobjWrapper = obj;
memberPrivate->fieldValue = fieldValue;
memberPrivate->methodName = id;
memberPrivate->npp = npp;
- ::JS_RemoveRoot(cx, vp);
+ ::JS_RemoveValueRoot(cx, vp);
return JS_TRUE;
}
static JSBool
NPObjectMember_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
{
NPObjectMemberPrivate *memberPrivate =
--- a/security/manager/ssl/src/nsCrypto.cpp
+++ b/security/manager/ssl/src/nsCrypto.cpp
@@ -2154,26 +2154,26 @@ nsCryptoRunArgs::~nsCryptoRunArgs() {}
nsCryptoRunnable::nsCryptoRunnable(nsCryptoRunArgs *args)
{
nsNSSShutDownPreventionLock locker;
NS_ASSERTION(args,"Passed nsnull to nsCryptoRunnable constructor.");
m_args = args;
NS_IF_ADDREF(m_args);
- JS_AddNamedRoot(args->m_cx, &args->m_scope,"nsCryptoRunnable::mScope");
+ JS_AddNamedObjectRoot(args->m_cx, &args->m_scope,"nsCryptoRunnable::mScope");
}
nsCryptoRunnable::~nsCryptoRunnable()
{
nsNSSShutDownPreventionLock locker;
{
JSAutoRequest ar(m_args->m_cx);
- JS_RemoveRoot(m_args->m_cx, &m_args->m_scope);
+ JS_RemoveObjectRoot(m_args->m_cx, &m_args->m_scope);
}
NS_IF_RELEASE(m_args);
}
//Implementation that runs the callback passed to
//crypto.generateCRMFRequest as an event.
NS_IMETHODIMP
--- a/xpinstall/src/nsXPITriggerInfo.cpp
+++ b/xpinstall/src/nsXPITriggerInfo.cpp
@@ -190,17 +190,17 @@ nsXPITriggerInfo::~nsXPITriggerInfo()
item = Get(i);
if (item)
delete item;
}
mItems.Clear();
if ( mCx && !JSVAL_IS_NULL(mCbval) ) {
JS_BeginRequest(mCx);
- JS_RemoveRoot( mCx, &mCbval );
+ JS_RemoveValueRoot(mCx, &mCbval );
JS_EndRequest(mCx);
}
MOZ_COUNT_DTOR(nsXPITriggerInfo);
}
void nsXPITriggerInfo::SaveCallback( JSContext *aCx, jsval aVal )
{
@@ -214,25 +214,25 @@ void nsXPITriggerInfo::SaveCallback( JSC
return;
mCx = aCx;
mCbval = aVal;
mThread = do_GetCurrentThread();
if ( !JSVAL_IS_NULL(mCbval) ) {
JS_BeginRequest(mCx);
- JS_AddRoot( mCx, &mCbval );
+ JS_AddValueRoot(mCx, &mCbval );
JS_EndRequest(mCx);
}
}
XPITriggerEvent::~XPITriggerEvent()
{
JS_BeginRequest(cx);
- JS_RemoveRoot(cx, &cbval);
+ JS_RemoveValueRoot(cx, &cbval);
JS_EndRequest(cx);
}
NS_IMETHODIMP
XPITriggerEvent::Run()
{
JSAutoRequest ar(cx);
@@ -323,17 +323,17 @@ void nsXPITriggerInfo::SendStatus(const
{
event->URL = URL;
event->status = status;
event->cx = mCx;
event->princ = mPrincipal;
event->cbval = mCbval;
JS_BeginRequest(event->cx);
- JS_AddNamedRoot(event->cx, &event->cbval,
+ JS_AddNamedValueRoot(event->cx, &event->cbval,
"XPITriggerEvent::cbval" );
JS_EndRequest(event->cx);
// Hold a strong reference to keep the underlying
// JSContext from dying before we handle this event.
event->ref = mContextWrapper;
rv = mThread->Dispatch(event, NS_DISPATCH_NORMAL);