Fix for bug 461563 (Allow WrapNative to return a jsval without the wrapper). r/sr=jst.

This commit is contained in:
Peter Van der Beken 2008-12-16 16:46:18 +01:00
parent 6e9c3576aa
commit 8473174cb4
8 changed files with 124 additions and 114 deletions

View File

@ -1638,9 +1638,9 @@ nsDOMClassInfo::WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
const nsIID& aIID, jsval *vp,
nsIXPConnectJSObjectHolder **aHolder)
{
*aHolder = nsnull;
if (!native) {
NS_ASSERTION(!aHolder || !*aHolder, "*aHolder should be null!");
*vp = JSVAL_NULL;
return NS_OK;
@ -1648,19 +1648,8 @@ nsDOMClassInfo::WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
NS_ENSURE_TRUE(sXPConnect, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = sXPConnect->WrapNative(cx, ::JS_GetGlobalForObject(cx, scope),
native, aIID, getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
JSObject* obj = nsnull;
rv = holder->GetJSObject(&obj);
NS_ENSURE_SUCCESS(rv, rv);
*vp = OBJECT_TO_JSVAL(obj);
holder.swap(*aHolder);
return rv;
return sXPConnect->WrapNativeToJSVal(cx, ::JS_GetGlobalForObject(cx, scope),
native, aIID, vp, aHolder);
}
// static
@ -7730,9 +7719,7 @@ nsArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
NS_ENSURE_SUCCESS(rv, rv);
if (array_item) {
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, obj, array_item, NS_GET_IID(nsISupports), vp,
getter_AddRefs(holder));
rv = WrapNative(cx, obj, array_item, NS_GET_IID(nsISupports), vp);
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_SUCCESS_I_DID_SOMETHING;
@ -7867,9 +7854,7 @@ nsNamedArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
NS_ENSURE_SUCCESS(rv, rv);
if (item) {
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, obj, item, NS_GET_IID(nsISupports), vp,
getter_AddRefs(holder));
rv = WrapNative(cx, obj, item, NS_GET_IID(nsISupports), vp);
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_SUCCESS_I_DID_SOMETHING;
@ -8514,9 +8499,7 @@ nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JSObject *obj,
}
if (result) {
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = nsDOMClassInfo::WrapNative(cx, obj, result, NS_GET_IID(nsISupports),
vp, getter_AddRefs(holder));
rv = WrapNative(cx, obj, result, NS_GET_IID(nsISupports), vp);
if (NS_FAILED(rv)) {
nsDOMClassInfo::ThrowJSException(cx, rv);
@ -8948,9 +8931,7 @@ nsHTMLDocumentSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
NS_ENSURE_SUCCESS(rv, rv);
if (result) {
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, obj, result, NS_GET_IID(nsISupports), vp,
getter_AddRefs(holder));
rv = WrapNative(cx, obj, result, NS_GET_IID(nsISupports), vp);
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}
@ -9090,9 +9071,7 @@ nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
if (result) {
// Wrap result, result can be either an element or a list of
// elements
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = WrapNative(cx, obj, result, NS_GET_IID(nsISupports), vp,
getter_AddRefs(holder));
nsresult rv = WrapNative(cx, obj, result, NS_GET_IID(nsISupports), vp);
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
}
@ -9104,9 +9083,7 @@ nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
form->GetElementAt(n, getter_AddRefs(control));
if (control) {
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = WrapNative(cx, obj, control, NS_GET_IID(nsISupports), vp,
getter_AddRefs(holder));
nsresult rv = WrapNative(cx, obj, control, NS_GET_IID(nsISupports), vp);
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
}
@ -9213,9 +9190,7 @@ nsHTMLSelectElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
options->Item(n, getter_AddRefs(node));
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, obj, node, NS_GET_IID(nsIDOMNode), vp,
getter_AddRefs(holder));
rv = WrapNative(cx, obj, node, NS_GET_IID(nsIDOMNode), vp);
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}

View File

@ -132,9 +132,9 @@ public:
static nsresult WrapNative(JSContext *cx, JSObject *scope,
nsISupports *native, const nsIID& aIID,
jsval *vp,
// aHolder keeps the jsval alive while
// there's a ref to it
nsIXPConnectJSObjectHolder** aHolder);
// If non-null aHolder will keep the jsval alive
// while there's a ref to it
nsIXPConnectJSObjectHolder** aHolder = nsnull);
static nsresult ThrowJSException(JSContext *cx, nsresult aResult);
static nsresult InitDOMJSClass(JSContext *cx, JSObject *obj);

View File

@ -405,7 +405,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports
{ 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
%}
[uuid(d4c6bc06-2a4f-4315-90ec-d12904aca046)]
[uuid(f8bf005e-3700-411c-ba0c-e018075f22a4)]
interface nsIXPConnect : nsISupports
{
%{ C++
@ -468,6 +468,19 @@ interface nsIXPConnect : nsISupports
in nsISupports aCOMObj,
in nsIIDRef aIID);
/**
* Same as wrapNative, but also returns the JSObject in aVal. C++ callers
* can pass in null for the aHolder argument, but in that case they must
* ensure that aVal is rooted.
*/
void
wrapNativeToJSVal(in JSContextPtr aJSContext,
in JSObjectPtr aScope,
in nsISupports aCOMObj,
in nsIIDRef aIID,
out JSVal aVal,
out nsIXPConnectJSObjectHolder aHolder);
/**
* wrapJS will yield a new or previously existing xpcom interface pointer
* to represent the JSObject passed in.

View File

@ -1099,6 +1099,7 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
!JS_SetPrototype(aJSContext, tempGlobal, nsnull))
return UnexpectedFailure(NS_ERROR_FAILURE);
jsval v;
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
{
// Scope for our auto-marker; it just needs to keep tempGlobal alive
@ -1109,7 +1110,8 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
return UnexpectedFailure(NS_ERROR_FAILURE);
nsresult rv;
if(!XPCConvert::NativeInterface2JSObject(ccx, getter_AddRefs(holder),
if(!XPCConvert::NativeInterface2JSObject(ccx, &v,
getter_AddRefs(holder),
aCOMObj, &aIID, tempGlobal,
PR_FALSE, OBJ_IS_GLOBAL, &rv))
return UnexpectedFailure(rv);
@ -1117,8 +1119,8 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
NS_ASSERTION(NS_SUCCEEDED(rv) && holder, "Didn't wrap properly");
}
JSObject* globalJSObj;
if(NS_FAILED(holder->GetJSObject(&globalJSObj)) || !globalJSObj)
JSObject* globalJSObj = JSVAL_TO_OBJECT(v);
if(!globalJSObj)
return UnexpectedFailure(NS_ERROR_FAILURE);
if(aFlags & nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT)
@ -1180,29 +1182,42 @@ nsXPConnect::WrapNative(JSContext * aJSContext,
JSObject * aScope,
nsISupports *aCOMObj,
const nsIID & aIID,
nsIXPConnectJSObjectHolder **_retval)
nsIXPConnectJSObjectHolder **aHolder)
{
NS_ASSERTION(aHolder, "bad param");
jsval v;
return WrapNativeToJSVal(aJSContext, aScope, aCOMObj, aIID, &v, aHolder);
}
/* void wrapNativeToJSVal (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDRef aIID, out JSVal aVal, out nsIXPConnectJSObjectHolder aHolder); */
NS_IMETHODIMP
nsXPConnect::WrapNativeToJSVal(JSContext * aJSContext,
JSObject * aScope,
nsISupports *aCOMObj,
const nsIID & aIID,
jsval *aVal,
nsIXPConnectJSObjectHolder **aHolder)
{
NS_ASSERTION(aJSContext, "bad param");
NS_ASSERTION(aScope, "bad param");
NS_ASSERTION(aCOMObj, "bad param");
NS_ASSERTION(_retval, "bad param");
*_retval = nsnull;
if(aHolder)
*aHolder = nsnull;
XPCCallContext ccx(NATIVE_CALLER, aJSContext);
if(!ccx.IsValid())
return UnexpectedFailure(NS_ERROR_FAILURE);
nsresult rv;
if(!XPCConvert::NativeInterface2JSObject(ccx, _retval, aCOMObj, &aIID,
if(!XPCConvert::NativeInterface2JSObject(ccx, aVal, aHolder, aCOMObj, &aIID,
aScope, PR_FALSE,
OBJ_IS_NOT_GLOBAL, &rv))
return rv;
#ifdef DEBUG
JSObject* returnObj;
(*_retval)->GetJSObject(&returnObj);
NS_ASSERTION(!XPCNativeWrapper::IsNativeWrapper(returnObj),
NS_ASSERTION(!XPCNativeWrapper::IsNativeWrapper(JSVAL_TO_OBJECT(*aVal)),
"Shouldn't be returning a native wrapper here");
#endif

View File

@ -467,24 +467,17 @@ XPCConvert::NativeData2JS(XPCCallContext& ccx, jsval* d, const void* s,
// global object will not have been collected, and
// therefore this NativeInterface2JSObject will not end up
// creating a new XPCNativeScriptableShared.
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
if(!NativeInterface2JSObject(ccx, getter_AddRefs(holder),
iface, iid, scope, PR_TRUE,
if(!NativeInterface2JSObject(ccx, d, nsnull, iface, iid,
scope, PR_TRUE,
OBJ_IS_NOT_GLOBAL, pErr))
return JS_FALSE;
if(holder)
{
JSObject* jsobj;
if(NS_FAILED(holder->GetJSObject(&jsobj)))
return JS_FALSE;
#ifdef DEBUG
if(!STOBJ_GET_PARENT(jsobj))
NS_ASSERTION(STOBJ_GET_CLASS(jsobj)->flags & JSCLASS_IS_GLOBAL,
"Why did we recreate this wrapper?");
JSObject* jsobj = JSVAL_TO_OBJECT(*d);
if(jsobj && !STOBJ_GET_PARENT(jsobj))
NS_ASSERTION(STOBJ_GET_CLASS(jsobj)->flags & JSCLASS_IS_GLOBAL,
"Why did we recreate this wrapper?");
#endif
*d = OBJECT_TO_JSVAL(jsobj);
}
}
break;
}
@ -1033,15 +1026,20 @@ XPCConvert::JSData2Native(XPCCallContext& ccx, void* d, jsval s,
return JS_TRUE;
}
JSBool
CreateHolderIfNeeded(XPCCallContext& ccx, JSObject* obj,
inline JSBool
CreateHolderIfNeeded(XPCCallContext& ccx, JSObject* obj, jsval* d,
nsIXPConnectJSObjectHolder** dest)
{
XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(ccx, obj);
if(!objHolder)
return JS_FALSE;
NS_ADDREF(*dest = objHolder);
if(dest)
{
XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(ccx, obj);
if(!objHolder)
return JS_FALSE;
NS_ADDREF(*dest = objHolder);
}
*d = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
}
@ -1050,6 +1048,7 @@ CreateHolderIfNeeded(XPCCallContext& ccx, JSObject* obj,
// static
JSBool
XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
jsval* d,
nsIXPConnectJSObjectHolder** dest,
nsISupports* src,
const nsID* iid,
@ -1058,11 +1057,12 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
PRBool isGlobal,
nsresult* pErr)
{
NS_ASSERTION(dest, "bad param");
NS_ASSERTION(iid, "bad param");
NS_ASSERTION(scope, "bad param");
*dest = nsnull;
*d = JSVAL_NULL;
if(dest)
*dest = nsnull;
if(!src)
return JS_TRUE;
if(pErr)
@ -1086,11 +1086,17 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
// verify that this wrapper is for the right interface
nsCOMPtr<nsISupports> wrapper;
if(NS_FAILED(src->QueryInterface(*iid,(void**)getter_AddRefs(wrapper))))
src->QueryInterface(*iid, (void**)getter_AddRefs(wrapper));
nsCOMPtr<nsIXPConnectJSObjectHolder> holder =
do_QueryInterface(wrapper);
JSObject* flat;
if(!holder || !(flat = holder->GetFlatJSObject()))
return JS_FALSE;
return NS_SUCCEEDED(wrapper->QueryInterface(
NS_GET_IID(nsIXPConnectJSObjectHolder),
(void**) dest));
*d = OBJECT_TO_JSVAL(flat);
if(dest)
holder.swap(*dest);
return JS_TRUE;
}
else
#endif /* XPC_DO_DOUBLE_WRAP */
@ -1107,20 +1113,26 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
nsresult rv;
XPCWrappedNative* wrapper;
nsRefPtr<XPCWrappedNative> strongWrapper;
nsWrapperCache* cache = nsnull;
CallQueryInterface(src, &cache);
if(cache &&
(wrapper = static_cast<XPCWrappedNative*>(cache->GetWrapper())))
{
NS_ADDREF(wrapper);
// If asked to return the wrapper we'll return a strong reference,
// otherwise we'll just return its JSObject in rval (which should be
// rooted in that case).
if(dest)
strongWrapper = wrapper;
wrapper->FindTearOff(ccx, iface, JS_FALSE, &rv);
if(NS_FAILED(rv))
NS_RELEASE(wrapper);
}
else
{
rv = XPCWrappedNative::GetNewOrUsed(ccx, src, xpcscope, iface,
isGlobal, &wrapper);
isGlobal,
getter_AddRefs(strongWrapper));
wrapper = strongWrapper;
}
if(pErr)
@ -1185,6 +1197,11 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
if(!JS_IsSystemObject(ccx, flat))
{
// From here on we might create new JSObjects, so we need to
// make sure that wrapper stays alive.
if(!strongWrapper)
strongWrapper = wrapper;
JSObject *destObj = nsnull;
if(flags & JSFILENAME_PROTECTED)
{
@ -1243,11 +1260,8 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
destObj = JSVAL_TO_OBJECT(v);
}
PRBool ok = destObj &&
CreateHolderIfNeeded(ccx, destObj, dest);
NS_RELEASE(wrapper);
return ok;
return destObj &&
CreateHolderIfNeeded(ccx, destObj, d, dest);
}
}
@ -1257,14 +1271,18 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
!JS_IsSystemObject(ccx, flat) &&
XPC_XOW_ClassNeedsXOW(name))
{
PRBool ok = XPC_XOW_WrapObject(ccx, scope, &v) &&
CreateHolderIfNeeded(ccx, JSVAL_TO_OBJECT(v), dest);
// From here on we might create new JSObjects, so we need to
// make sure that wrapper stays alive.
if(!strongWrapper)
strongWrapper = wrapper;
NS_RELEASE(wrapper);
return ok;
return XPC_XOW_WrapObject(ccx, scope, &v) &&
CreateHolderIfNeeded(ccx, JSVAL_TO_OBJECT(v), d, dest);
}
*dest = static_cast<nsIXPConnectJSObjectHolder*>(wrapper);
*d = v;
if(dest)
*dest = strongWrapper.forget().get();
return JS_TRUE;
}
}

View File

@ -2759,6 +2759,7 @@ public:
* @param pErr [out] relevant error code, if any.
*/
static JSBool NativeInterface2JSObject(XPCCallContext& ccx,
jsval* d,
nsIXPConnectJSObjectHolder** dest,
nsISupports* src,
const nsID* iid,

View File

@ -756,11 +756,9 @@ xpc_qsXPCOMObjectToJsval(XPCCallContext &ccx, nsISupports *p,
// global object will not have been collected, and
// therefore this NativeInterface2JSObject will not end up
// creating a new XPCNativeScriptableShared.
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv;
if(!XPCConvert::NativeInterface2JSObject(ccx, getter_AddRefs(holder),
p, &iid, scope, PR_TRUE,
OBJ_IS_NOT_GLOBAL, &rv))
if(!XPCConvert::NativeInterface2JSObject(ccx, rval, nsnull, p, &iid, scope,
PR_TRUE, OBJ_IS_NOT_GLOBAL, &rv))
{
// I can't tell if NativeInterface2JSObject throws JS exceptions
// or not. This is a sloppy stab at the right semantics; the
@ -770,22 +768,13 @@ xpc_qsXPCOMObjectToJsval(XPCCallContext &ccx, nsISupports *p,
return JS_FALSE;
}
if(holder)
{
JSObject* jsobj;
if(NS_FAILED(holder->GetJSObject(&jsobj)))
return JS_FALSE;
#ifdef DEBUG
if(!STOBJ_GET_PARENT(jsobj))
NS_ASSERTION(STOBJ_GET_CLASS(jsobj)->flags & JSCLASS_IS_GLOBAL,
"Why did we recreate this wrapper?");
JSObject* jsobj = JSVAL_TO_OBJECT(*rval);
if(jsobj && !STOBJ_GET_PARENT(jsobj))
NS_ASSERTION(STOBJ_GET_CLASS(jsobj)->flags & JSCLASS_IS_GLOBAL,
"Why did we recreate this wrapper?");
#endif
*rval = OBJECT_TO_JSVAL(jsobj);
}
else
{
*rval = JSVAL_NULL;
}
return JS_TRUE;
}

View File

@ -1346,19 +1346,18 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex,
newWrapperIID =
const_cast<nsIID*>
(&NS_GET_IID(nsISupports));
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
jsval v;
JSBool ok =
XPCConvert::NativeInterface2JSObject(ccx,
getter_AddRefs(holder), newThis,
newWrapperIID, obj, PR_FALSE, PR_FALSE,
nsnull);
&v, nsnull, newThis, newWrapperIID, obj,
PR_FALSE, PR_FALSE, nsnull);
if(newWrapperIID != &NS_GET_IID(nsISupports))
nsMemory::Free(newWrapperIID);
if(!ok ||
NS_FAILED(holder->GetJSObject(&thisObj)))
if(!ok)
{
goto pre_call_clean_up;
}
thisObj = JSVAL_TO_OBJECT(v);
}
}
}