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

This commit is contained in:
Blake Kaplan 2010-09-17 14:54:40 -07:00
Родитель c5cde776e4
Коммит 234cbcb3a1
3 изменённых файлов: 110 добавлений и 47 удалений

Просмотреть файл

@ -78,7 +78,8 @@ public:
void SetWrapper(JSObject* aWrapper) void SetWrapper(JSObject* aWrapper)
{ {
NS_ASSERTION(!PreservingWrapper(), "Clearing a preserved wrapper!"); NS_ASSERTION(!PreservingWrapper(), "Clearing a preserved wrapper!");
mWrapperPtrBits = reinterpret_cast<PtrBits>(aWrapper); mWrapperPtrBits = reinterpret_cast<PtrBits>(aWrapper) |
(mWrapperPtrBits & WRAPPER_IS_PROXY);
} }
void ClearWrapper() void ClearWrapper()
@ -99,12 +100,23 @@ public:
PRBool PreservingWrapper() 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: private:
enum { WRAPPER_BIT_PRESERVED = 1 << 0 }; 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; PtrBits mWrapperPtrBits;
}; };

Просмотреть файл

@ -1070,7 +1070,7 @@ CreateHolderIfNeeded(XPCCallContext& ccx, JSObject* obj, jsval* d,
XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(ccx, obj); XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(ccx, obj);
if(!objHolder) if(!objHolder)
return JS_FALSE; return JS_FALSE;
NS_ADDREF(*dest = objHolder); NS_ADDREF(*dest = objHolder);
} }
@ -1079,6 +1079,48 @@ CreateHolderIfNeeded(XPCCallContext& ccx, JSObject* obj, jsval* d,
return JS_TRUE; 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 // static
JSBool JSBool
@ -1151,11 +1193,38 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
nsWrapperCache *cache = aHelper.GetWrapperCache(); nsWrapperCache *cache = aHelper.GetWrapperCache();
JSObject *callee = nsnull;
JSScript *script = nsnull;
PRBool tryConstructSlimWrapper = PR_FALSE; PRBool tryConstructSlimWrapper = PR_FALSE;
JSObject *flat; JSObject *flat;
if(cache) if(cache)
{ {
flat = cache->GetWrapper(); 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(!dest)
{ {
if(!flat) if(!flat)
@ -1196,6 +1265,22 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
// fall through because we either have a slim wrapper that needs to be // fall through because we either have a slim wrapper that needs to be
// morphed or we have an XPCWrappedNative. // morphed or we have an XPCWrappedNative.
flat = cache->GetWrapper(); 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; 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?"); "What kind of wrapper is this?");
nsresult rv; nsresult rv;
@ -1257,7 +1343,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
else else
rv = NS_OK; rv = NS_OK;
} }
else else if(!cache->IsProxy())
{ {
NS_ASSERTION(IS_SLIM_WRAPPER(flat), NS_ASSERTION(IS_SLIM_WRAPPER(flat),
"What kind of wrapper is this?"); "What kind of wrapper is this?");
@ -1299,45 +1385,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
// printf("Wrapped native accessed across scope boundary\n"); // printf("Wrapped native accessed across scope boundary\n");
JSScript* script = nsnull; ComputeWrapperInfo(ccx, &callee, &script);
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.
flags = script ? JS_GetScriptFilenameFlags(script) : 0; flags = script ? JS_GetScriptFilenameFlags(script) : 0;
NS_ASSERTION(flags != JSFILENAME_NULL, "null script filename"); NS_ASSERTION(flags != JSFILENAME_NULL, "null script filename");

Просмотреть файл

@ -3879,11 +3879,15 @@ ConstructSlimWrapper(XPCCallContext &ccx,
return JS_FALSE; return JS_FALSE;
} }
nsWrapperCache *cache = aHelper.GetWrapperCache();
JSObject* plannedParent = parent; JSObject* plannedParent = parent;
rv = classInfoHelper->PreCreate(identityObj, ccx, parent, &parent); rv = classInfoHelper->PreCreate(identityObj, ccx, parent, &parent);
if(rv != NS_SUCCESS_ALLOW_SLIM_WRAPPERS) 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; return JS_FALSE;
} }
@ -3902,7 +3906,6 @@ ConstructSlimWrapper(XPCCallContext &ccx,
// The PreCreate hook could have forced the creation of a wrapper, need // The PreCreate hook could have forced the creation of a wrapper, need
// to check for that here and return early. // to check for that here and return early.
nsWrapperCache *cache = aHelper.GetWrapperCache();
JSObject* wrapper = cache->GetWrapper(); JSObject* wrapper = cache->GetWrapper();
if(wrapper) if(wrapper)
{ {