From 234cbcb3a17701189d5c6337ad401fca0db22a1d Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Fri, 17 Sep 2010 14:54:40 -0700 Subject: [PATCH] Bug 580128 - Give objects a way to inform XPConnect that they implement their own JS object in a way that does not involve wrapped natives. r=peterv --- dom/base/nsWrapperCache.h | 18 ++- js/src/xpconnect/src/xpcconvert.cpp | 132 +++++++++++++++------- js/src/xpconnect/src/xpcwrappednative.cpp | 7 +- 3 files changed, 110 insertions(+), 47 deletions(-) diff --git a/dom/base/nsWrapperCache.h b/dom/base/nsWrapperCache.h index d7697cbbaffc..555955fec311 100644 --- a/dom/base/nsWrapperCache.h +++ b/dom/base/nsWrapperCache.h @@ -78,7 +78,8 @@ public: void SetWrapper(JSObject* aWrapper) { NS_ASSERTION(!PreservingWrapper(), "Clearing a preserved wrapper!"); - mWrapperPtrBits = reinterpret_cast(aWrapper); + mWrapperPtrBits = reinterpret_cast(aWrapper) | + (mWrapperPtrBits & WRAPPER_IS_PROXY); } void ClearWrapper() @@ -99,12 +100,23 @@ public: PRBool PreservingWrapper() { - return mWrapperPtrBits & WRAPPER_BIT_PRESERVED; + return (mWrapperPtrBits & WRAPPER_BIT_PRESERVED) != 0; + } + + void SetIsProxy() + { + mWrapperPtrBits |= WRAPPER_IS_PROXY; + } + + PRBool IsProxy() + { + return (mWrapperPtrBits & WRAPPER_IS_PROXY) != 0; } private: enum { WRAPPER_BIT_PRESERVED = 1 << 0 }; - enum { kWrapperBitMask = 0x1 }; + enum { WRAPPER_IS_PROXY = 1 << 1 }; + enum { kWrapperBitMask = (WRAPPER_BIT_PRESERVED | WRAPPER_IS_PROXY) }; PtrBits mWrapperPtrBits; }; diff --git a/js/src/xpconnect/src/xpcconvert.cpp b/js/src/xpconnect/src/xpcconvert.cpp index f5088ac6fc9e..ce99ee239359 100644 --- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -1070,7 +1070,7 @@ CreateHolderIfNeeded(XPCCallContext& ccx, JSObject* obj, jsval* d, XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(ccx, obj); if(!objHolder) return JS_FALSE; - + NS_ADDREF(*dest = objHolder); } @@ -1079,6 +1079,48 @@ CreateHolderIfNeeded(XPCCallContext& ccx, JSObject* obj, jsval* d, return JS_TRUE; } +static void +ComputeWrapperInfo(const XPCCallContext &ccx, + JSObject **callee, + JSScript **script) +{ + *callee = nsnull; + *script = nsnull; + + if(ccx.GetXPCContext()->CallerTypeIsJavaScript()) + { + // Called from JS. We're going to hand the resulting + // JSObject to said JS, so look for the script we want on + // the stack. + JSStackFrame* fp = JS_GetScriptedCaller(ccx, NULL); + if(fp) + { + *script = fp->maybeScript(); + *callee = fp->isFunctionFrame() + ? &fp->callee() + : &fp->scopeChain(); + } + } + else if(ccx.GetXPCContext()->CallerTypeIsNative()) + { + *callee = ccx.GetCallee(); + if(*callee && JS_ObjectIsFunction(ccx, *callee)) + { + // Called from c++, and calling out to |callee|, which is a JS + // function object. Look for the script for this function. + JSFunction* fun = (JSFunction*) xpc_GetJSPrivate(*callee); + NS_ASSERTION(fun, "Must have JSFunction for a Function object"); + *script = JS_GetFunctionScript(ccx, fun); + } + else + { + // Else we don't know whom we're calling, so don't + // create XPCNativeWrappers. + *callee = nsnull; + } + } +} + /***************************************************************************/ // static JSBool @@ -1151,11 +1193,38 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, nsWrapperCache *cache = aHelper.GetWrapperCache(); + JSObject *callee = nsnull; + JSScript *script = nsnull; + PRBool tryConstructSlimWrapper = PR_FALSE; JSObject *flat; if(cache) { flat = cache->GetWrapper(); + if(cache->IsProxy()) + { + if(flat) + { + XPCCallContext &ccx = lccx.GetXPCCallContext(); + if(!ccx.IsValid()) + return JS_FALSE; + + ComputeWrapperInfo(ccx, &callee, &script); + if(!callee) + callee = xpcscope->GetGlobalJSObject(); + + JSAutoCrossCompartmentCall accc; + if(!accc.enter(ccx, callee) || !JS_WrapObject(ccx, &flat)) + return JS_FALSE; + + return CreateHolderIfNeeded(ccx, flat, d, dest); + } + else + { + tryConstructSlimWrapper = PR_TRUE; + } + } + if(!dest) { if(!flat) @@ -1196,6 +1265,22 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, // fall through because we either have a slim wrapper that needs to be // morphed or we have an XPCWrappedNative. flat = cache->GetWrapper(); + if(cache->IsProxy()) + { + XPCCallContext &ccx = lccx.GetXPCCallContext(); + if(!ccx.IsValid()) + return JS_FALSE; + + ComputeWrapperInfo(ccx, &callee, &script); + if(!callee) + callee = xpcscope->GetGlobalJSObject(); + + JSAutoCrossCompartmentCall accc; + if(!accc.enter(ccx, callee) || !JS_WrapObject(ccx, &flat)) + return JS_FALSE; + + return CreateHolderIfNeeded(ccx, flat, d, dest); + } } AutoMarkingNativeInterfacePtr iface; @@ -1221,7 +1306,8 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, } } - NS_ASSERTION(!flat || IS_WRAPPER_CLASS(flat->getClass()), + NS_ASSERTION(!flat || IS_WRAPPER_CLASS(flat->getClass()) || + cache->IsProxy(), "What kind of wrapper is this?"); nsresult rv; @@ -1257,7 +1343,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, else rv = NS_OK; } - else + else if(!cache->IsProxy()) { NS_ASSERTION(IS_SLIM_WRAPPER(flat), "What kind of wrapper is this?"); @@ -1299,45 +1385,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, // printf("Wrapped native accessed across scope boundary\n"); - JSScript* script = nsnull; - JSObject* callee = nsnull; - if(ccx.GetXPCContext()->CallerTypeIsJavaScript()) - { - // Called from JS. We're going to hand the resulting - // JSObject to said JS, so look for the script we want on - // the stack. - JSContext* cx = ccx; - JSStackFrame* fp = JS_GetScriptedCaller(cx, NULL); - if(fp) - { - script = JS_GetFrameScript(cx, fp); - callee = JS_GetFrameCalleeObject(cx, fp); - } - } - else if(ccx.GetXPCContext()->CallerTypeIsNative()) - { - callee = ccx.GetCallee(); - if(callee && JS_ObjectIsFunction(ccx, callee)) - { - // Called from c++, and calling out to |callee|, which - // is a JS function object. Look for the script for - // this function. - JSFunction* fun = - (JSFunction*) xpc_GetJSPrivate(callee); - NS_ASSERTION(fun, - "Must have JSFunction for a Function " - "object"); - script = JS_GetFunctionScript(ccx, fun); - } - else - { - // Else we don't know whom we're calling, so don't - // create XPCNativeWrappers. - callee = nsnull; - } - } - // else don't create XPCNativeWrappers, since we have - // no idea what's calling what here. + ComputeWrapperInfo(ccx, &callee, &script); flags = script ? JS_GetScriptFilenameFlags(script) : 0; NS_ASSERTION(flags != JSFILENAME_NULL, "null script filename"); diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp index 9a25fe508add..c492d33132aa 100644 --- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -3879,11 +3879,15 @@ ConstructSlimWrapper(XPCCallContext &ccx, return JS_FALSE; } + nsWrapperCache *cache = aHelper.GetWrapperCache(); JSObject* plannedParent = parent; rv = classInfoHelper->PreCreate(identityObj, ccx, parent, &parent); if(rv != NS_SUCCESS_ALLOW_SLIM_WRAPPERS) { - SLIM_LOG_NOT_CREATED(ccx, identityObj, "PreCreate hook refused"); + if(cache->IsProxy()) + NS_ASSERTION(cache->GetWrapper(), "out of memory?"); + else + SLIM_LOG_NOT_CREATED(ccx, identityObj, "PreCreate hook refused"); return JS_FALSE; } @@ -3902,7 +3906,6 @@ ConstructSlimWrapper(XPCCallContext &ccx, // The PreCreate hook could have forced the creation of a wrapper, need // to check for that here and return early. - nsWrapperCache *cache = aHelper.GetWrapperCache(); JSObject* wrapper = cache->GetWrapper(); if(wrapper) {