зеркало из https://github.com/mozilla/pjs.git
Fix for bug 499199 (Try to avoid XPCCallContexts in quickstubs for wrapper-cached things). r/sr=jst.
--HG-- extra : rebase_source : 8fc828106f3cf5e82e902cefd79e55df2b8721c3
This commit is contained in:
Родитель
d201b699db
Коммит
84dc646522
|
@ -51,7 +51,6 @@
|
|||
(nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY | \
|
||||
nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY | \
|
||||
nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY | \
|
||||
nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE | \
|
||||
nsIXPCScriptable::ALLOW_PROP_MODS_TO_PROTOTYPE | \
|
||||
nsIXPCScriptable::DONT_ASK_INSTANCE_FOR_SCRIPTABLE | \
|
||||
nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES)
|
||||
|
|
|
@ -1222,6 +1222,7 @@ nsXPConnect::WrapNativeToJSVal(JSContext * aJSContext,
|
|||
XPCCallContext ccx(NATIVE_CALLER, aJSContext);
|
||||
if(!ccx.IsValid())
|
||||
return UnexpectedFailure(NS_ERROR_FAILURE);
|
||||
XPCLazyCallContext lccx(ccx);
|
||||
|
||||
nsresult rv;
|
||||
if(!XPCConvert::NativeInterface2JSObject(ccx, aVal, aHolder, aCOMObj, aIID,
|
||||
|
@ -2238,9 +2239,10 @@ nsXPConnect::VariantToJS(JSContext* ctx, JSObject* scope, nsIVariant* value, jsv
|
|||
XPCCallContext ccx(NATIVE_CALLER, ctx);
|
||||
if(!ccx.IsValid())
|
||||
return NS_ERROR_FAILURE;
|
||||
XPCLazyCallContext lccx(ccx);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if(!XPCVariant::VariantDataToJS(ccx, value, scope, &rv, _retval))
|
||||
if(!XPCVariant::VariantDataToJS(lccx, value, scope, &rv, _retval))
|
||||
{
|
||||
if(NS_FAILED(rv))
|
||||
return rv;
|
||||
|
|
|
@ -101,16 +101,6 @@
|
|||
# exposed--nsAXPCNativeCallContext does not expose
|
||||
# XPCCallContext::GetPrevCallContext.)
|
||||
#
|
||||
# - There are a few differences in how the "this" JSObject is unwrapped.
|
||||
# Ordinarily, XPConnect searches the prototype chain of the "this" JSObject
|
||||
# for an XPCOM object of the desired "proto". For details, see the parts of
|
||||
# XPCWrappedNative::GetWrappedNativeOfJSObject that use "proto". Some quick
|
||||
# stubs (methods, not getters or setters, that have XPCCallContexts) do this,
|
||||
# but most instead look for an XPCOM object that supports the desired
|
||||
# *interface*. This is more lenient. The difference is observable in some
|
||||
# cases where a getter/setter/method is taken from one object and applied to
|
||||
# another object.
|
||||
#
|
||||
# - Quick stubs never suspend the JS request. So they are only suitable for
|
||||
# main-thread-only interfaces.
|
||||
#
|
||||
|
@ -591,7 +581,7 @@ resultConvTemplates = {
|
|||
def isVariantType(t):
|
||||
return isSpecificInterfaceType(t, 'nsIVariant')
|
||||
|
||||
def writeResultConv(f, type, paramNum, jsvalPtr, jsvalRef):
|
||||
def writeResultConv(f, type, jsvalPtr, jsvalRef):
|
||||
""" Emit code to convert the C++ variable `result` to a jsval.
|
||||
|
||||
The emitted code contains a return statement; it returns JS_TRUE on
|
||||
|
@ -609,15 +599,14 @@ def writeResultConv(f, type, paramNum, jsvalPtr, jsvalRef):
|
|||
# else fall through; this type isn't supported yet
|
||||
elif isInterfaceType(type):
|
||||
if isVariantType(type):
|
||||
f.write(" return xpc_qsVariantToJsval(ccx, result, %d, %s);\n"
|
||||
% (paramNum, jsvalPtr))
|
||||
f.write(" return xpc_qsVariantToJsval(lccx, result, %s);\n"
|
||||
% jsvalPtr)
|
||||
return
|
||||
else:
|
||||
f.write(" AutoMarkingNativeInterfacePtr resultiface(ccx, "
|
||||
"%s_Interface(ccx));\n" % type.name)
|
||||
f.write(" return xpc_qsXPCOMObjectToJsval(ccx, result, "
|
||||
"xpc_qsGetWrapperCache(result), resultiface, %s);\n"
|
||||
% jsvalPtr)
|
||||
f.write(" return xpc_qsXPCOMObjectToJsval(lccx, result, "
|
||||
"xpc_qsGetWrapperCache(result), &NS_GET_IID(%s), "
|
||||
"&interfaces[k_%s], %s);\n"
|
||||
% (type.name, type.name, jsvalPtr))
|
||||
return
|
||||
|
||||
warn("Unable to convert result of type %s" % type.name)
|
||||
|
@ -678,16 +667,18 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
|
|||
" return JS_FALSE;\n")
|
||||
|
||||
# Create ccx if needed.
|
||||
haveCcx = isMethod and (isInterfaceType(member.realtype)
|
||||
or anyParamRequiresCcx(member))
|
||||
haveCcx = isMethod and anyParamRequiresCcx(member)
|
||||
if haveCcx:
|
||||
f.write(" XPCCallContext ccx(JS_CALLER, cx, obj, "
|
||||
"JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));\n")
|
||||
else:
|
||||
# In some cases we emit a ccx, but it does not count as
|
||||
# "haveCcx" because it's not complete.
|
||||
if isAttr and isInterfaceType(member.realtype):
|
||||
f.write(" XPCCallContext ccx(JS_CALLER, cx, obj);\n")
|
||||
f.write(" XPCCallContext ccx(JS_CALLER, cx, obj, "
|
||||
"JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));\n")
|
||||
if isInterfaceType(member.realtype):
|
||||
f.write(" XPCLazyCallContext lccx(ccx);\n")
|
||||
elif isInterfaceType(member.realtype):
|
||||
if isMethod:
|
||||
f.write(" JSObject *callee = "
|
||||
"JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));\n")
|
||||
elif isGetter:
|
||||
f.write(" JSObject *callee = nsnull;\n")
|
||||
|
||||
# Get the 'self' pointer.
|
||||
if customMethodCall is None or not 'thisType' in customMethodCall:
|
||||
|
@ -697,7 +688,7 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
|
|||
f.write(" xpc_qsSelfRef selfref;\n")
|
||||
# Don't use FromCcx for getters or setters; the way we construct the ccx in
|
||||
# a getter/setter causes it to find the wrong wrapper in some cases.
|
||||
if isMethod and haveCcx:
|
||||
if haveCcx:
|
||||
# Undocumented, but the interpreter puts 'this' at argv[-1],
|
||||
# which is vp[1]; and it's ok to overwrite it.
|
||||
f.write(" if (!xpc_qsUnwrapThisFromCcx(ccx, &self, &selfref.ptr, "
|
||||
|
@ -712,8 +703,13 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
|
|||
else:
|
||||
pthisval = '&vp[1]' # as above, ok to overwrite vp[1]
|
||||
|
||||
f.write(" if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, "
|
||||
"%s))\n" % pthisval)
|
||||
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)
|
||||
else:
|
||||
f.write(" if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, "
|
||||
"&selfref.ptr, %s, nsnull))\n" % pthisval)
|
||||
f.write(" return JS_FALSE;\n")
|
||||
|
||||
if isMethod:
|
||||
|
@ -807,10 +803,8 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
|
|||
f.write("#endif\n")
|
||||
|
||||
# Convert the return value.
|
||||
if isMethod:
|
||||
writeResultConv(f, member.realtype, len(member.params) + 1, 'vp', '*vp')
|
||||
elif isGetter:
|
||||
writeResultConv(f, member.realtype, None, 'vp', '*vp')
|
||||
if isMethod or isGetter:
|
||||
writeResultConv(f, member.realtype, 'vp', '*vp')
|
||||
else:
|
||||
f.write(" return JS_TRUE;\n")
|
||||
|
||||
|
@ -990,7 +984,7 @@ traceableResultConvTemplates = {
|
|||
" return rval;\n",
|
||||
}
|
||||
|
||||
def writeTraceableResultConv(f, type, paramNum):
|
||||
def writeTraceableResultConv(f, type):
|
||||
typeName = getBuiltinOrNativeTypeName(type)
|
||||
if typeName is not None:
|
||||
template = traceableResultConvTemplates.get(typeName)
|
||||
|
@ -1002,14 +996,13 @@ def writeTraceableResultConv(f, type, paramNum):
|
|||
# else fall through; this type isn't supported yet
|
||||
elif isInterfaceType(type):
|
||||
if isVariantType(type):
|
||||
f.write(" JSBool ok = xpc_qsVariantToJsval(ccx, result, %d, "
|
||||
"&vp.array[0]);\n" % paramNum)
|
||||
f.write(" JSBool ok = xpc_qsVariantToJsval(lccx, result, "
|
||||
"&vp.array[0]);\n")
|
||||
else:
|
||||
f.write(" AutoMarkingNativeInterfacePtr resultiface(ccx, "
|
||||
"%s_Interface(ccx));\n" % type.name)
|
||||
f.write(" JSBool ok = xpc_qsXPCOMObjectToJsval(ccx, result, "
|
||||
"xpc_qsGetWrapperCache(result), resultiface, &vp.array[0]);"
|
||||
"\n")
|
||||
f.write(" JSBool ok = xpc_qsXPCOMObjectToJsval(lccx, result, "
|
||||
"xpc_qsGetWrapperCache(result), &NS_GET_IID(%s), "
|
||||
"&interfaces[k_%s], &vp.array[0]);"
|
||||
"\n" % (type.name, type.name))
|
||||
f.write(" if (!ok) {\n");
|
||||
writeFailure(f, getTraceInfoDefaultReturn(type), 2)
|
||||
f.write(" return vp.array[0];\n")
|
||||
|
@ -1027,14 +1020,14 @@ def writeTraceableQuickStub(f, customMethodCalls, member, stubName):
|
|||
'params': ["CONTEXT", "THIS"]
|
||||
}
|
||||
|
||||
haveCcx = isInterfaceType(member.realtype) or anyParamRequiresCcx(member)
|
||||
haveCcx = (member.kind == 'method') and anyParamRequiresCcx(member)
|
||||
|
||||
customMethodCall = customMethodCalls.get(stubName, None)
|
||||
|
||||
# Write the function
|
||||
f.write("static %sFASTCALL\n" % getTraceType(member.type))
|
||||
f.write("%s(JSContext *cx, JSObject *obj" % (stubName + "_tn"))
|
||||
if haveCcx:
|
||||
if haveCcx or isInterfaceType(member.realtype):
|
||||
f.write(", JSObject *callee")
|
||||
traceInfo["params"].append("CALLEE")
|
||||
for i, param in enumerate(member.params):
|
||||
|
@ -1047,6 +1040,8 @@ def writeTraceableQuickStub(f, customMethodCalls, member, stubName):
|
|||
# Create ccx if needed.
|
||||
if haveCcx:
|
||||
f.write(" XPCCallContext ccx(JS_CALLER, cx, obj, callee);\n")
|
||||
if isInterfaceType(member.realtype):
|
||||
f.write(" XPCLazyCallContext lccx(ccx);\n")
|
||||
|
||||
# Get the 'self' pointer.
|
||||
if customMethodCall is None or not 'thisType' in customMethodCall:
|
||||
|
@ -1058,9 +1053,13 @@ def writeTraceableQuickStub(f, customMethodCalls, member, stubName):
|
|||
if haveCcx:
|
||||
f.write(" if (!xpc_qsUnwrapThisFromCcx(ccx, &self, &selfref.ptr, "
|
||||
"&vp.array[0])) {\n")
|
||||
elif (member.kind == 'method') and isInterfaceType(member.realtype):
|
||||
f.write(" XPCLazyCallContext lccx(JS_CALLER, cx, obj);\n")
|
||||
f.write(" if (!xpc_qsUnwrapThis(cx, obj, callee, &self, &selfref.ptr, "
|
||||
"&vp.array[0], &lccx)) {\n")
|
||||
else:
|
||||
f.write(" if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, "
|
||||
"&vp.array[0])) {\n")
|
||||
f.write(" if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, "
|
||||
"&vp.array[0], nsnull)) {\n")
|
||||
writeFailure(f, getTraceInfoDefaultReturn(member.type), 2)
|
||||
|
||||
argNames = []
|
||||
|
@ -1122,7 +1121,7 @@ def writeTraceableQuickStub(f, customMethodCalls, member, stubName):
|
|||
f.write("#endif\n")
|
||||
|
||||
# Convert the return value.
|
||||
writeTraceableResultConv(f, member.realtype, len(member.params) + 1)
|
||||
writeTraceableResultConv(f, member.realtype)
|
||||
|
||||
# Epilog.
|
||||
f.write("}\n\n")
|
||||
|
@ -1228,8 +1227,7 @@ def writeResultXPCInterfacesArray(f, conf, resulttypes):
|
|||
f.write("}\n\n")
|
||||
i = 0
|
||||
for type in resulttypes:
|
||||
f.write("XPC_QS_DEFINE_XPCNATIVEINTERFACE_GETTER(%s, interfaces[%d])\n"
|
||||
% (type, i))
|
||||
f.write("static const PRUint32 k_%s = %d;\n" % (type, i))
|
||||
i += 1
|
||||
if count > 0:
|
||||
f.write("\n\n")
|
||||
|
|
|
@ -59,6 +59,45 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
|
|||
mDestroyJSContextInDestructor(JS_FALSE),
|
||||
mCallerLanguage(callerLanguage),
|
||||
mCallee(nsnull)
|
||||
{
|
||||
Init(callerLanguage, callerLanguage == NATIVE_CALLER, obj, funobj, JS_TRUE,
|
||||
name, argc, argv, rval);
|
||||
}
|
||||
|
||||
XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
|
||||
JSContext* cx,
|
||||
JSBool callBeginRequest,
|
||||
JSObject* obj,
|
||||
JSObject* currentJSObject,
|
||||
XPCWrappedNative* wrapper,
|
||||
XPCWrappedNativeTearOff* tearOff)
|
||||
: mState(INIT_FAILED),
|
||||
mXPC(nsXPConnect::GetXPConnect()),
|
||||
mThreadData(nsnull),
|
||||
mXPCContext(nsnull),
|
||||
mJSContext(cx),
|
||||
mContextPopRequired(JS_FALSE),
|
||||
mDestroyJSContextInDestructor(JS_FALSE),
|
||||
mCallerLanguage(callerLanguage),
|
||||
mCurrentJSObject(currentJSObject),
|
||||
mWrapper(wrapper),
|
||||
mTearOff(tearOff),
|
||||
mCallee(nsnull)
|
||||
{
|
||||
Init(callerLanguage, callBeginRequest, obj, nsnull, JS_FALSE, 0, NO_ARGS,
|
||||
nsnull, nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
XPCCallContext::Init(XPCContext::LangType callerLanguage,
|
||||
JSBool callBeginRequest,
|
||||
JSObject* obj,
|
||||
JSObject* funobj,
|
||||
JSBool getWrappedNative,
|
||||
jsval name,
|
||||
uintN argc,
|
||||
jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
// Mark our internal string wrappers as not used. Make sure we do
|
||||
// this before any early returns, as the destructor will assert
|
||||
|
@ -110,7 +149,9 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
|
|||
// Get into the request as early as we can to avoid problems with scanning
|
||||
// callcontexts on other threads from within the gc callbacks.
|
||||
|
||||
if(mCallerLanguage == NATIVE_CALLER)
|
||||
NS_ASSERTION(!callBeginRequest || mCallerLanguage == NATIVE_CALLER,
|
||||
"Don't call JS_BeginRequest unless the caller is native.");
|
||||
if(callBeginRequest)
|
||||
JS_BeginRequest(mJSContext);
|
||||
|
||||
if(topJSContext != mJSContext)
|
||||
|
@ -145,10 +186,12 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
|
|||
mState = HAVE_OBJECT;
|
||||
|
||||
mTearOff = nsnull;
|
||||
mWrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(mJSContext, obj,
|
||||
funobj,
|
||||
&mCurrentJSObject,
|
||||
&mTearOff);
|
||||
|
||||
if(getWrappedNative)
|
||||
mWrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(mJSContext, obj,
|
||||
funobj,
|
||||
&mCurrentJSObject,
|
||||
&mTearOff);
|
||||
if(mWrapper)
|
||||
{
|
||||
DEBUG_CheckWrapperThreadSafety(mWrapper);
|
||||
|
@ -576,3 +619,19 @@ XPCCallContext::GetLanguage(PRUint16 *aResult)
|
|||
*aResult = GetCallerLanguage();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// static
|
||||
void
|
||||
XPCLazyCallContext::AssertContextIsTopOfStack(JSContext* cx)
|
||||
{
|
||||
XPCPerThreadData* tls = XPCPerThreadData::GetData(cx);
|
||||
XPCJSContextStack* stack = tls->GetJSContextStack();
|
||||
|
||||
JSContext* topJSContext;
|
||||
nsresult rv = stack->Peek(&topJSContext);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "XPCJSContextStack::Peek failed");
|
||||
|
||||
NS_ASSERTION(cx == topJSContext, "wrong context on XPCJSContextStack!");
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -238,14 +238,14 @@ INT64_TO_DOUBLE(const int64 &v)
|
|||
|
||||
// static
|
||||
JSBool
|
||||
XPCConvert::NativeData2JS(XPCCallContext& ccx, jsval* d, const void* s,
|
||||
XPCConvert::NativeData2JS(XPCLazyCallContext& lccx, jsval* d, const void* s,
|
||||
const nsXPTType& type, const nsID* iid,
|
||||
JSObject* scope, nsresult* pErr)
|
||||
{
|
||||
NS_PRECONDITION(s, "bad param");
|
||||
NS_PRECONDITION(d, "bad param");
|
||||
|
||||
JSContext* cx = ccx.GetJSContext();
|
||||
JSContext* cx = lccx.GetJSContext();
|
||||
|
||||
if(pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
|
||||
|
@ -456,7 +456,7 @@ XPCConvert::NativeData2JS(XPCCallContext& ccx, jsval* d, const void* s,
|
|||
if(!variant)
|
||||
return JS_FALSE;
|
||||
|
||||
return XPCVariant::VariantDataToJS(ccx, variant,
|
||||
return XPCVariant::VariantDataToJS(lccx, variant,
|
||||
scope, pErr, d);
|
||||
}
|
||||
// else...
|
||||
|
@ -466,7 +466,7 @@ 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.
|
||||
if(!NativeInterface2JSObject(ccx, d, nsnull, iface, iid,
|
||||
if(!NativeInterface2JSObject(lccx, d, nsnull, iface, iid,
|
||||
nsnull, nsnull, scope, PR_TRUE,
|
||||
OBJ_IS_NOT_GLOBAL, pErr))
|
||||
return JS_FALSE;
|
||||
|
@ -1045,12 +1045,12 @@ CreateHolderIfNeeded(XPCCallContext& ccx, JSObject* obj, jsval* d,
|
|||
/***************************************************************************/
|
||||
// static
|
||||
JSBool
|
||||
XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
|
||||
XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
|
||||
jsval* d,
|
||||
nsIXPConnectJSObjectHolder** dest,
|
||||
nsISupports* src,
|
||||
const nsID* iid,
|
||||
XPCNativeInterface* Interface,
|
||||
XPCNativeInterface** Interface,
|
||||
nsWrapperCache *cache,
|
||||
JSObject* scope,
|
||||
PRBool allowNativeWrapper,
|
||||
|
@ -1058,6 +1058,8 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
|
|||
nsresult* pErr)
|
||||
{
|
||||
NS_ASSERTION(scope, "bad param");
|
||||
NS_ASSERTION(!Interface || iid,
|
||||
"Need the iid if you pass in an XPCNativeInterface cache.");
|
||||
|
||||
*d = JSVAL_NULL;
|
||||
if(dest)
|
||||
|
@ -1085,10 +1087,7 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
|
|||
|
||||
// verify that this wrapper is for the right interface
|
||||
nsCOMPtr<nsISupports> wrapper;
|
||||
if(Interface)
|
||||
src->QueryInterface(*Interface->GetIID(),
|
||||
(void**)getter_AddRefs(wrapper));
|
||||
else if(iid)
|
||||
if(iid)
|
||||
src->QueryInterface(*iid, (void**)getter_AddRefs(wrapper));
|
||||
else
|
||||
wrapper = do_QueryInterface(src);
|
||||
|
@ -1106,13 +1105,17 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
|
|||
else
|
||||
#endif /* XPC_DO_DOUBLE_WRAP */
|
||||
{
|
||||
JSContext* cx = lccx.GetJSContext();
|
||||
|
||||
XPCWrappedNativeScope* xpcscope =
|
||||
XPCWrappedNativeScope::FindInJSObjectScope(ccx, scope);
|
||||
XPCWrappedNativeScope::FindInJSObjectScope(cx, scope);
|
||||
if(!xpcscope)
|
||||
return JS_FALSE;
|
||||
|
||||
if(!cache)
|
||||
CallQueryInterface(src, &cache);
|
||||
|
||||
PRBool tryConstructSlimWrapper = PR_FALSE;
|
||||
JSObject *flat;
|
||||
if(cache)
|
||||
{
|
||||
|
@ -1121,24 +1124,11 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
|
|||
{
|
||||
if(!flat)
|
||||
{
|
||||
jsval slim;
|
||||
if(ConstructSlimWrapper(ccx, src, cache, Interface,
|
||||
xpcscope, &slim))
|
||||
{
|
||||
*d = slim;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
// Even if ConstructSlimWrapper returns JS_FALSE it might
|
||||
// have created a wrapper (while calling the PreCreate
|
||||
// hook). In that case we need to fall through because we
|
||||
// either have a slim wrapper that needs to be morphed or
|
||||
// we have an XPCWrappedNative.
|
||||
flat = cache->GetWrapper();
|
||||
tryConstructSlimWrapper = PR_TRUE;
|
||||
}
|
||||
else if(!IS_WRAPPER_CLASS(STOBJ_GET_CLASS(flat)))
|
||||
{
|
||||
JSObject* global = JS_GetGlobalForObject(ccx, flat);
|
||||
JSObject* global = JS_GetGlobalForObject(cx, flat);
|
||||
if(global == xpcscope->GetGlobalJSObject())
|
||||
{
|
||||
*d = OBJECT_TO_JSVAL(flat);
|
||||
|
@ -1152,12 +1142,47 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
|
|||
flat = nsnull;
|
||||
}
|
||||
|
||||
AutoMarkingNativeInterfacePtr iface(ccx, Interface);
|
||||
if(!iface && iid)
|
||||
if(tryConstructSlimWrapper)
|
||||
{
|
||||
iface = XPCNativeInterface::GetNewOrUsed(ccx, iid);
|
||||
if(!iface)
|
||||
XPCCallContext &ccx = lccx.GetXPCCallContext();
|
||||
if(!ccx.IsValid())
|
||||
return JS_FALSE;
|
||||
|
||||
jsval slim;
|
||||
if(ConstructSlimWrapper(ccx, src, cache, xpcscope, &slim))
|
||||
{
|
||||
*d = slim;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
// Even if ConstructSlimWrapper returns JS_FALSE it might have created a
|
||||
// wrapper (while calling the PreCreate hook). In that case we need to
|
||||
// fall through because we either have a slim wrapper that needs to be
|
||||
// morphed or we have an XPCWrappedNative.
|
||||
flat = cache->GetWrapper();
|
||||
}
|
||||
|
||||
AutoMarkingNativeInterfacePtr iface;
|
||||
if(iid)
|
||||
{
|
||||
XPCCallContext &ccx = lccx.GetXPCCallContext();
|
||||
if(!ccx.IsValid())
|
||||
return JS_FALSE;
|
||||
|
||||
iface.Init(ccx);
|
||||
|
||||
if(Interface)
|
||||
iface = *Interface;
|
||||
|
||||
if(!iface)
|
||||
{
|
||||
iface = XPCNativeInterface::GetNewOrUsed(ccx, iid);
|
||||
if(!iface)
|
||||
return JS_FALSE;
|
||||
|
||||
if(Interface)
|
||||
*Interface = iface;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
@ -1165,6 +1190,10 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
|
|||
nsRefPtr<XPCWrappedNative> strongWrapper;
|
||||
if(!flat)
|
||||
{
|
||||
XPCCallContext &ccx = lccx.GetXPCCallContext();
|
||||
if(!ccx.IsValid())
|
||||
return JS_FALSE;
|
||||
|
||||
rv = XPCWrappedNative::GetNewOrUsed(ccx, src, xpcscope, iface,
|
||||
cache, isGlobal,
|
||||
getter_AddRefs(strongWrapper));
|
||||
|
@ -1180,8 +1209,12 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
|
|||
// rooted in that case).
|
||||
if(dest)
|
||||
strongWrapper = wrapper;
|
||||
// If iface is not null we know lccx.GetXPCCallContext() returns
|
||||
// a valid XPCCallContext because we checked when calling Init on
|
||||
// iface.
|
||||
if(iface)
|
||||
wrapper->FindTearOff(ccx, iface, JS_FALSE, &rv);
|
||||
wrapper->FindTearOff(lccx.GetXPCCallContext(), iface, JS_FALSE,
|
||||
&rv);
|
||||
else
|
||||
rv = NS_OK;
|
||||
}
|
||||
|
@ -1189,6 +1222,11 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
|
|||
{
|
||||
NS_ASSERTION(IS_SLIM_WRAPPER(flat),
|
||||
"What kind of wrapper is this?");
|
||||
|
||||
XPCCallContext &ccx = lccx.GetXPCCallContext();
|
||||
if(!ccx.IsValid())
|
||||
return JS_FALSE;
|
||||
|
||||
SLIM_LOG(("***** morphing from XPCConvert::NativeInterface2JSObject"
|
||||
"(%p)\n",
|
||||
static_cast<nsISupports*>(xpc_GetJSPrivate(flat))));
|
||||
|
@ -1202,6 +1240,10 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
|
|||
*pErr = rv;
|
||||
if(NS_SUCCEEDED(rv) && wrapper)
|
||||
{
|
||||
XPCCallContext &ccx = lccx.GetXPCCallContext();
|
||||
if(!ccx.IsValid())
|
||||
return JS_FALSE;
|
||||
|
||||
uint32 flags = 0;
|
||||
flat = wrapper->GetFlatJSObject();
|
||||
jsval v = OBJECT_TO_JSVAL(flat);
|
||||
|
@ -1886,7 +1928,7 @@ XPC_JSArgumentFormatter(JSContext *cx, const char *format,
|
|||
|
||||
// static
|
||||
JSBool
|
||||
XPCConvert::NativeArray2JS(XPCCallContext& ccx,
|
||||
XPCConvert::NativeArray2JS(XPCLazyCallContext& lccx,
|
||||
jsval* d, const void** s,
|
||||
const nsXPTType& type, const nsID* iid,
|
||||
JSUint32 count, JSObject* scope,
|
||||
|
@ -1895,6 +1937,10 @@ XPCConvert::NativeArray2JS(XPCCallContext& ccx,
|
|||
NS_PRECONDITION(s, "bad param");
|
||||
NS_PRECONDITION(d, "bad param");
|
||||
|
||||
XPCCallContext& ccx = lccx.GetXPCCallContext();
|
||||
if(!ccx.IsValid())
|
||||
return JS_FALSE;
|
||||
|
||||
JSContext* cx = ccx.GetJSContext();
|
||||
|
||||
// XXX add support for putting chars in a string rather than an array
|
||||
|
@ -2128,7 +2174,7 @@ failure:
|
|||
|
||||
// static
|
||||
JSBool
|
||||
XPCConvert::NativeStringWithSize2JS(XPCCallContext& ccx,
|
||||
XPCConvert::NativeStringWithSize2JS(JSContext* cx,
|
||||
jsval* d, const void* s,
|
||||
const nsXPTType& type,
|
||||
JSUint32 count,
|
||||
|
@ -2137,8 +2183,6 @@ XPCConvert::NativeStringWithSize2JS(XPCCallContext& ccx,
|
|||
NS_PRECONDITION(s, "bad param");
|
||||
NS_PRECONDITION(d, "bad param");
|
||||
|
||||
JSContext* cx = ccx.GetJSContext();
|
||||
|
||||
if(pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
|
||||
|
||||
|
|
|
@ -120,7 +120,6 @@ static JSDHashOperator
|
|||
NativeInterfaceSweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
|
||||
uint32 number, void *arg)
|
||||
{
|
||||
CX_AND_XPCRT_Data* data = (CX_AND_XPCRT_Data*) arg;
|
||||
XPCNativeInterface* iface = ((IID2NativeInterfaceMap::Entry*)hdr)->value;
|
||||
if(iface->IsMarked())
|
||||
{
|
||||
|
@ -133,7 +132,7 @@ NativeInterfaceSweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
|
|||
JS_GetStringBytes(JSVAL_TO_STRING(iface->GetName())));
|
||||
#endif
|
||||
|
||||
XPCNativeInterface::DestroyInstance(data->cx, data->rt, iface);
|
||||
XPCNativeInterface::DestroyInstance(iface);
|
||||
return JS_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
|
@ -645,10 +644,8 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
|||
self->mNativeSetMap->
|
||||
Enumerate(NativeSetSweeper, nsnull);
|
||||
|
||||
CX_AND_XPCRT_Data data = {cx, self};
|
||||
|
||||
self->mIID2NativeInterfaceMap->
|
||||
Enumerate(NativeInterfaceSweeper, &data);
|
||||
Enumerate(NativeInterfaceSweeper, nsnull);
|
||||
|
||||
#ifdef DEBUG
|
||||
XPCWrappedNativeScope::ASSERT_NoInterfaceSetsAreMarked();
|
||||
|
|
|
@ -134,7 +134,10 @@ LogSlimWrapperWillMorph(JSContext *cx, JSObject *obj, const char *propname,
|
|||
{
|
||||
if(obj && IS_SLIM_WRAPPER(obj))
|
||||
{
|
||||
printf("***** morphing from %s", functionName);
|
||||
XPCNativeScriptableInfo *si =
|
||||
GetSlimWrapperProto(obj)->GetScriptableInfo();
|
||||
printf("***** morphing %s from %s", si->GetJSClass()->name,
|
||||
functionName);
|
||||
if(propname)
|
||||
printf(" for %s", propname);
|
||||
printf(" (%p, %p)\n", obj,
|
||||
|
@ -146,8 +149,15 @@ LogSlimWrapperWillMorph(JSContext *cx, JSObject *obj, const char *propname,
|
|||
void
|
||||
LogSlimWrapperNotCreated(JSContext *cx, nsISupports *obj, const char *reason)
|
||||
{
|
||||
printf("***** refusing to create slim wrapper, reason: %s (%p)\n",
|
||||
reason, obj);
|
||||
char* className = nsnull;
|
||||
nsCOMPtr<nsIClassInfo> ci = do_QueryInterface(obj);
|
||||
if(ci)
|
||||
ci->GetClassDescription(&className);
|
||||
printf("***** refusing to create slim wrapper%s%s, reason: %s (%p)\n",
|
||||
className ? " for " : "", className ? className : "", reason, obj);
|
||||
if(className)
|
||||
PR_Free(className);
|
||||
AutoJSRequestWithNoCallContext autoRequest(cx);
|
||||
xpc_DumpJSStack(cx, JS_FALSE, JS_FALSE, JS_FALSE);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1084,6 +1084,25 @@ private:
|
|||
XPCCallContext(const XPCCallContext& r); // not implemented
|
||||
XPCCallContext& operator= (const XPCCallContext& r); // not implemented
|
||||
|
||||
friend class XPCLazyCallContext;
|
||||
XPCCallContext(XPCContext::LangType callerLanguage,
|
||||
JSContext* cx,
|
||||
JSBool callBeginRequest,
|
||||
JSObject* obj,
|
||||
JSObject* currentJSObject,
|
||||
XPCWrappedNative* wn,
|
||||
XPCWrappedNativeTearOff* tearoff);
|
||||
|
||||
void Init(XPCContext::LangType callerLanguage,
|
||||
JSBool callBeginRequest,
|
||||
JSObject* obj,
|
||||
JSObject* funobj,
|
||||
JSBool getWrappedNative,
|
||||
jsval name,
|
||||
uintN argc,
|
||||
jsval *argv,
|
||||
jsval *rval);
|
||||
|
||||
private:
|
||||
// posible values for mState
|
||||
enum State {
|
||||
|
@ -1176,6 +1195,113 @@ private:
|
|||
char mStringWrapperData[sizeof(StringWrapperEntry) * XPCCCX_STRING_CACHE_SIZE];
|
||||
};
|
||||
|
||||
class XPCLazyCallContext
|
||||
{
|
||||
public:
|
||||
XPCLazyCallContext(XPCCallContext& ccx)
|
||||
: mCallBeginRequest(DONT_CALL_BEGINREQUEST),
|
||||
mCcx(&ccx),
|
||||
mCcxToDestroy(nsnull)
|
||||
|
||||
{
|
||||
}
|
||||
XPCLazyCallContext(XPCContext::LangType callerLanguage, JSContext* cx,
|
||||
JSObject* obj = nsnull,
|
||||
JSObject* currentJSObject = nsnull,
|
||||
XPCWrappedNative* wrapper = nsnull,
|
||||
XPCWrappedNativeTearOff* tearoff = nsnull)
|
||||
: mCallBeginRequest(callerLanguage == NATIVE_CALLER ?
|
||||
CALL_BEGINREQUEST : DONT_CALL_BEGINREQUEST),
|
||||
mCcx(nsnull),
|
||||
mCcxToDestroy(nsnull),
|
||||
mCx(cx),
|
||||
mCallerLanguage(callerLanguage),
|
||||
mObj(obj),
|
||||
mCurrentJSObject(currentJSObject),
|
||||
mWrapper(wrapper),
|
||||
mTearOff(tearoff)
|
||||
{
|
||||
NS_ASSERTION(cx, "Need a JS context!");
|
||||
NS_ASSERTION(callerLanguage == NATIVE_CALLER ||
|
||||
callerLanguage == JS_CALLER,
|
||||
"Can't deal with unknown caller language!");
|
||||
#ifdef DEBUG
|
||||
AssertContextIsTopOfStack(cx);
|
||||
#endif
|
||||
}
|
||||
~XPCLazyCallContext()
|
||||
{
|
||||
if(mCcxToDestroy)
|
||||
mCcxToDestroy->~XPCCallContext();
|
||||
else if(mCallBeginRequest == CALLED_BEGINREQUEST)
|
||||
JS_EndRequest(mCx);
|
||||
}
|
||||
void SetWrapper(JSObject* currentJSObject,
|
||||
XPCWrappedNative* wrapper,
|
||||
XPCWrappedNativeTearOff* tearoff)
|
||||
{
|
||||
mCurrentJSObject = currentJSObject;
|
||||
mWrapper = wrapper;
|
||||
mTearOff = tearoff;
|
||||
}
|
||||
|
||||
JSContext *GetJSContext()
|
||||
{
|
||||
if(mCcx)
|
||||
return mCcx->GetJSContext();
|
||||
|
||||
if(mCallBeginRequest == CALL_BEGINREQUEST) {
|
||||
JS_BeginRequest(mCx);
|
||||
mCallBeginRequest = CALLED_BEGINREQUEST;
|
||||
}
|
||||
|
||||
return mCx;
|
||||
}
|
||||
JSObject *GetCurrentJSObject() const
|
||||
{
|
||||
return mCurrentJSObject;
|
||||
}
|
||||
XPCCallContext &GetXPCCallContext()
|
||||
{
|
||||
if(!mCcx)
|
||||
{
|
||||
mCcxToDestroy = mCcx =
|
||||
new (mData) XPCCallContext(mCallerLanguage, mCx,
|
||||
mCallBeginRequest == CALL_BEGINREQUEST,
|
||||
mObj,
|
||||
mCurrentJSObject, mWrapper,
|
||||
mTearOff);
|
||||
if(!mCcx->IsValid())
|
||||
{
|
||||
NS_ERROR("This is not supposed to fail!");
|
||||
}
|
||||
}
|
||||
|
||||
return *mCcx;
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef DEBUG
|
||||
static void AssertContextIsTopOfStack(JSContext* cx);
|
||||
#endif
|
||||
|
||||
enum {
|
||||
DONT_CALL_BEGINREQUEST,
|
||||
CALL_BEGINREQUEST,
|
||||
CALLED_BEGINREQUEST
|
||||
} mCallBeginRequest;
|
||||
|
||||
XPCCallContext *mCcx;
|
||||
XPCCallContext *mCcxToDestroy;
|
||||
JSContext *mCx;
|
||||
XPCContext::LangType mCallerLanguage;
|
||||
JSObject *mObj;
|
||||
JSObject *mCurrentJSObject;
|
||||
XPCWrappedNative *mWrapper;
|
||||
XPCWrappedNativeTearOff *mTearOff;
|
||||
char mData[sizeof(XPCCallContext)];
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
****************************************************************************
|
||||
*
|
||||
|
@ -1524,8 +1650,7 @@ public:
|
|||
inline void TraceJS(JSTracer* trc) {}
|
||||
inline void AutoTrace(JSTracer* trc) {}
|
||||
|
||||
static void DestroyInstance(JSContext* cx, XPCJSRuntime* rt,
|
||||
XPCNativeInterface* inst);
|
||||
static void DestroyInstance(XPCNativeInterface* inst);
|
||||
|
||||
protected:
|
||||
static XPCNativeInterface* NewInstance(XPCCallContext& ccx,
|
||||
|
@ -2078,7 +2203,6 @@ extern JSBool XPC_SWN_Equality(JSContext *cx, JSObject *obj, jsval v,
|
|||
|
||||
extern JSBool ConstructSlimWrapper(XPCCallContext &ccx, nsISupports *p,
|
||||
nsWrapperCache *cache,
|
||||
XPCNativeInterface *iface,
|
||||
XPCWrappedNativeScope* xpcScope,
|
||||
jsval *rval);
|
||||
extern JSBool MorphSlimWrapper(JSContext *cx, JSObject *obj);
|
||||
|
@ -2837,7 +2961,15 @@ public:
|
|||
*/
|
||||
static JSBool NativeData2JS(XPCCallContext& ccx, jsval* d, const void* s,
|
||||
const nsXPTType& type, const nsID* iid,
|
||||
JSObject* scope, nsresult* pErr);
|
||||
JSObject* scope, nsresult* pErr)
|
||||
{
|
||||
XPCLazyCallContext lccx(ccx);
|
||||
return NativeData2JS(lccx, d, s, type, iid, scope, pErr);
|
||||
}
|
||||
static JSBool NativeData2JS(XPCLazyCallContext& lccx, jsval* d,
|
||||
const void* s, const nsXPTType& type,
|
||||
const nsID* iid, JSObject* scope,
|
||||
nsresult* pErr);
|
||||
|
||||
static JSBool JSData2Native(XPCCallContext& ccx, void* d, jsval s,
|
||||
const nsXPTType& type,
|
||||
|
@ -2850,11 +2982,15 @@ public:
|
|||
* @param ccx the context for the whole procedure
|
||||
* @param dest [out] the resulting JSObject
|
||||
* @param src the native object we're working with
|
||||
* @param iid the interface of src that we want
|
||||
* @param iid the interface of src that we want (may be null)
|
||||
* @param Interface the interface of src that we want
|
||||
* @param cache the wrapper cache for src (may be null, in which case src
|
||||
* will be QI'ed to get the cache)
|
||||
* @param scope the default scope to put on the new JSObject's __parent__
|
||||
* chain
|
||||
* @param allowNativeWrapper if true, this method may wrap the resulting
|
||||
* JSObject in an XPCNativeWrapper and return that, as needed.
|
||||
* @param isGlobal
|
||||
* @param pErr [out] relevant error code, if any.
|
||||
*/
|
||||
static JSBool NativeInterface2JSObject(XPCCallContext& ccx,
|
||||
|
@ -2862,7 +2998,24 @@ public:
|
|||
nsIXPConnectJSObjectHolder** dest,
|
||||
nsISupports* src,
|
||||
const nsID* iid,
|
||||
XPCNativeInterface* Interface,
|
||||
XPCNativeInterface** Interface,
|
||||
nsWrapperCache *cache,
|
||||
JSObject* scope,
|
||||
PRBool allowNativeWrapper,
|
||||
PRBool isGlobal,
|
||||
nsresult* pErr)
|
||||
{
|
||||
XPCLazyCallContext lccx(ccx);
|
||||
return NativeInterface2JSObject(lccx, d, dest, src, iid, Interface,
|
||||
cache, scope, allowNativeWrapper,
|
||||
isGlobal, pErr);
|
||||
}
|
||||
static JSBool NativeInterface2JSObject(XPCLazyCallContext& lccx,
|
||||
jsval* d,
|
||||
nsIXPConnectJSObjectHolder** dest,
|
||||
nsISupports* src,
|
||||
const nsID* iid,
|
||||
XPCNativeInterface** Interface,
|
||||
nsWrapperCache *cache,
|
||||
JSObject* scope,
|
||||
PRBool allowNativeWrapper,
|
||||
|
@ -2893,7 +3046,7 @@ public:
|
|||
* chain
|
||||
* @param pErr [out] relevant error code, if any.
|
||||
*/
|
||||
static JSBool NativeArray2JS(XPCCallContext& ccx,
|
||||
static JSBool NativeArray2JS(XPCLazyCallContext& ccx,
|
||||
jsval* d, const void** s,
|
||||
const nsXPTType& type, const nsID* iid,
|
||||
JSUint32 count, JSObject* scope,
|
||||
|
@ -2905,7 +3058,7 @@ public:
|
|||
JSBool useAllocator, const nsID* iid,
|
||||
uintN* pErr);
|
||||
|
||||
static JSBool NativeStringWithSize2JS(XPCCallContext& ccx,
|
||||
static JSBool NativeStringWithSize2JS(JSContext* cx,
|
||||
jsval* d, const void* s,
|
||||
const nsXPTType& type,
|
||||
JSUint32 count,
|
||||
|
@ -3830,9 +3983,16 @@ class AutoMarkingPtr
|
|||
public:
|
||||
AutoMarkingPtr(XPCCallContext& ccx)
|
||||
: mNext(nsnull), mTLS(ccx.GetThreadData()) {Link();}
|
||||
AutoMarkingPtr()
|
||||
: mNext(nsnull), mTLS(nsnull) {}
|
||||
|
||||
virtual ~AutoMarkingPtr() {Unlink();}
|
||||
|
||||
|
||||
void Init(XPCCallContext& ccx)
|
||||
{NS_ASSERTION(!mTLS, "Already init'ed!");
|
||||
mTLS = ccx.GetThreadData();
|
||||
Link();}
|
||||
|
||||
void Link()
|
||||
{if(!mTLS) return;
|
||||
AutoMarkingPtr** list = mTLS->GetAutoRootsAdr();
|
||||
|
@ -3865,6 +4025,8 @@ protected:
|
|||
class class_ : public AutoMarkingPtr \
|
||||
{ \
|
||||
public: \
|
||||
class_ () \
|
||||
: AutoMarkingPtr(), mPtr(nsnull) {} \
|
||||
class_ (XPCCallContext& ccx, type_ * ptr = nsnull) \
|
||||
: AutoMarkingPtr(ccx), mPtr(ptr) {} \
|
||||
virtual ~ class_ () {} \
|
||||
|
@ -3885,7 +4047,8 @@ public: \
|
|||
type_ * operator->() const {return mPtr;} \
|
||||
\
|
||||
class_ & operator =(type_ * p) \
|
||||
{mPtr = p; return *this;} \
|
||||
{NS_ASSERTION(mTLS, "Hasn't been init'ed!"); \
|
||||
mPtr = p; return *this;} \
|
||||
\
|
||||
protected: \
|
||||
type_ * mPtr; \
|
||||
|
@ -4019,7 +4182,7 @@ public:
|
|||
* @param pErr [out] relevant error code, if any.
|
||||
* @param pJSVal [out] the resulting jsval.
|
||||
*/
|
||||
static JSBool VariantDataToJS(XPCCallContext& ccx,
|
||||
static JSBool VariantDataToJS(XPCLazyCallContext& lccx,
|
||||
nsIVariant* variant,
|
||||
JSObject* scope, nsresult* pErr,
|
||||
jsval* pJSVal);
|
||||
|
|
|
@ -839,93 +839,42 @@ getNativeFromWrapper(XPCWrappedNative *wrapper,
|
|||
JSBool
|
||||
xpc_qsUnwrapThisImpl(JSContext *cx,
|
||||
JSObject *obj,
|
||||
JSObject *callee,
|
||||
const nsIID &iid,
|
||||
void **ppThis,
|
||||
nsISupports **pThisRef,
|
||||
jsval *vp)
|
||||
jsval *vp,
|
||||
XPCLazyCallContext *lccx)
|
||||
{
|
||||
// From XPCWrappedNative::GetWrappedNativeOfJSObject.
|
||||
//
|
||||
// Usually IS_WRAPPER_CLASS is true the first time through the while loop,
|
||||
// and the QueryInterface then succeeds.
|
||||
|
||||
NS_ASSERTION(obj, "this == null");
|
||||
|
||||
JSObject *cur = obj;
|
||||
while(cur)
|
||||
XPCWrappedNativeTearOff *tearoff;
|
||||
XPCWrappedNative *wrapper =
|
||||
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj, callee, &cur,
|
||||
&tearoff);
|
||||
if(wrapper)
|
||||
{
|
||||
JSClass *clazz;
|
||||
|
||||
clazz = STOBJ_GET_CLASS(cur);
|
||||
if(IS_SLIM_WRAPPER_CLASS(clazz))
|
||||
{
|
||||
nsISupports *native =
|
||||
static_cast<nsISupports*>(xpc_GetJSPrivate(cur));
|
||||
if(NS_SUCCEEDED(getNative(native, GetOffsetsFromSlimWrapper(cur),
|
||||
cur, iid, ppThis, pThisRef, vp)))
|
||||
return JS_TRUE;
|
||||
*pThisRef = nsnull;
|
||||
return xpc_qsThrow(cx, NS_ERROR_XPC_BAD_OP_ON_WN_PROTO);
|
||||
}
|
||||
|
||||
XPCWrappedNative *wrapper;
|
||||
nsresult rv;
|
||||
|
||||
if(IS_WRAPPER_CLASS(clazz))
|
||||
{
|
||||
wrapper = (XPCWrappedNative*) xpc_GetJSPrivate(cur);
|
||||
NS_ASSERTION(wrapper, "XPCWN wrapping nothing");
|
||||
}
|
||||
else if(clazz == &XPC_WN_Tearoff_JSClass)
|
||||
{
|
||||
wrapper = (XPCWrappedNative*) xpc_GetJSPrivate(STOBJ_GET_PARENT(cur));
|
||||
NS_ASSERTION(wrapper, "XPCWN wrapping nothing");
|
||||
}
|
||||
else
|
||||
{
|
||||
JSObject *unsafeObj = XPCWrapper::Unwrap(cx, cur);
|
||||
if(unsafeObj)
|
||||
{
|
||||
cur = unsafeObj;
|
||||
continue;
|
||||
}
|
||||
|
||||
// This goto is a bug, dutifully copied from
|
||||
// XPCWrappedNative::GetWrappedNativeOfJSObject.
|
||||
goto next;
|
||||
}
|
||||
|
||||
rv = getNativeFromWrapper(wrapper, iid, ppThis, pThisRef, vp);
|
||||
nsresult rv = getNativeFromWrapper(wrapper, iid, ppThis, pThisRef, vp);
|
||||
if(NS_SUCCEEDED(rv))
|
||||
{
|
||||
if(lccx)
|
||||
lccx->SetWrapper(cur, wrapper, tearoff);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
if(rv != NS_ERROR_NO_INTERFACE)
|
||||
return xpc_qsThrow(cx, rv);
|
||||
|
||||
next:
|
||||
cur = STOBJ_GET_PROTO(cur);
|
||||
}
|
||||
|
||||
// If we didn't find a wrapper using the given obj, try again with obj's
|
||||
// outer object, if it's got one.
|
||||
|
||||
JSClass *clazz = STOBJ_GET_CLASS(obj);
|
||||
|
||||
if((clazz->flags & JSCLASS_IS_EXTENDED) &&
|
||||
((JSExtendedClass*)clazz)->outerObject)
|
||||
else if(cur)
|
||||
{
|
||||
JSObject *outer = ((JSExtendedClass*)clazz)->outerObject(cx, obj);
|
||||
|
||||
// Protect against infinite recursion through XOWs.
|
||||
JSObject *unsafeObj;
|
||||
clazz = STOBJ_GET_CLASS(outer);
|
||||
if(clazz == &sXPC_XOW_JSClass.base &&
|
||||
(unsafeObj = XPCWrapper::Unwrap(cx, outer)))
|
||||
nsISupports *native = static_cast<nsISupports*>(xpc_GetJSPrivate(cur));
|
||||
if(NS_SUCCEEDED(getNative(native, GetOffsetsFromSlimWrapper(cur),
|
||||
cur, iid, ppThis, pThisRef, vp)))
|
||||
{
|
||||
outer = unsafeObj;
|
||||
}
|
||||
if(lccx)
|
||||
lccx->SetWrapper(cur, nsnull, nsnull);
|
||||
|
||||
if(outer && outer != obj)
|
||||
return xpc_qsUnwrapThisImpl(cx, outer, iid, ppThis, pThisRef, vp);
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*pThisRef = nsnull;
|
||||
|
@ -1125,34 +1074,34 @@ xpc_qsStringToJsval(JSContext *cx, const nsAString &str, jsval *rval)
|
|||
}
|
||||
|
||||
JSBool
|
||||
xpc_qsXPCOMObjectToJsval(XPCCallContext &ccx, nsISupports *p,
|
||||
nsWrapperCache *cache, XPCNativeInterface *iface,
|
||||
jsval *rval)
|
||||
xpc_qsXPCOMObjectToJsval(XPCLazyCallContext &lccx, nsISupports *p,
|
||||
nsWrapperCache *cache, const nsIID *iid,
|
||||
XPCNativeInterface **iface, jsval *rval)
|
||||
{
|
||||
// From the T_INTERFACE case in XPCConvert::NativeData2JS.
|
||||
// This is one of the slowest things quick stubs do.
|
||||
|
||||
JSObject *scope = ccx.GetCurrentJSObject();
|
||||
NS_ASSERTION(scope, "bad ccx");
|
||||
|
||||
JSContext *cx = lccx.GetJSContext();
|
||||
if(!iface)
|
||||
return xpc_qsThrow(ccx, NS_ERROR_XPC_BAD_CONVERT_NATIVE);
|
||||
return xpc_qsThrow(cx, NS_ERROR_XPC_BAD_CONVERT_NATIVE);
|
||||
|
||||
// XXX The OBJ_IS_NOT_GLOBAL here is not really right. In
|
||||
// fact, this code is depending on the fact that the
|
||||
// global object will not have been collected, and
|
||||
// therefore this NativeInterface2JSObject will not end up
|
||||
// creating a new XPCNativeScriptableShared.
|
||||
|
||||
nsresult rv;
|
||||
if(!XPCConvert::NativeInterface2JSObject(ccx, rval, nsnull, p, nsnull,
|
||||
iface, cache, scope, PR_TRUE,
|
||||
if(!XPCConvert::NativeInterface2JSObject(lccx, rval, nsnull, p,
|
||||
iid, iface, cache,
|
||||
lccx.GetCurrentJSObject(), 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
|
||||
// method really ought to be fixed to behave consistently.
|
||||
if(!JS_IsExceptionPending(ccx))
|
||||
xpc_qsThrow(ccx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
|
||||
if(!JS_IsExceptionPending(cx))
|
||||
xpc_qsThrow(cx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
@ -1167,9 +1116,8 @@ xpc_qsXPCOMObjectToJsval(XPCCallContext &ccx, nsISupports *p,
|
|||
}
|
||||
|
||||
JSBool
|
||||
xpc_qsVariantToJsval(XPCCallContext &ccx,
|
||||
xpc_qsVariantToJsval(XPCLazyCallContext &lccx,
|
||||
nsIVariant *p,
|
||||
uintN paramNum,
|
||||
jsval *rval)
|
||||
{
|
||||
// From the T_INTERFACE case in XPCConvert::NativeData2JS.
|
||||
|
@ -1177,11 +1125,11 @@ xpc_qsVariantToJsval(XPCCallContext &ccx,
|
|||
if(p)
|
||||
{
|
||||
nsresult rv;
|
||||
JSBool ok = XPCVariant::VariantDataToJS(ccx, p,
|
||||
ccx.GetCurrentJSObject(),
|
||||
JSBool ok = XPCVariant::VariantDataToJS(lccx, p,
|
||||
lccx.GetCurrentJSObject(),
|
||||
&rv, rval);
|
||||
if (!ok)
|
||||
XPCThrower::ThrowBadParam(rv, 0, ccx);
|
||||
xpc_qsThrow(lccx.GetJSContext(), rv);
|
||||
return ok;
|
||||
}
|
||||
*rval = JSVAL_NULL;
|
||||
|
|
|
@ -327,10 +327,12 @@ xpc_qsStringToJsval(JSContext *cx, const nsAString &str, jsval *rval);
|
|||
JSBool
|
||||
xpc_qsUnwrapThisImpl(JSContext *cx,
|
||||
JSObject *obj,
|
||||
JSObject *callee,
|
||||
const nsIID &iid,
|
||||
void **ppThis,
|
||||
nsISupports **ppThisRef,
|
||||
jsval *vp);
|
||||
jsval *vp,
|
||||
XPCLazyCallContext *lccx);
|
||||
|
||||
/**
|
||||
* Search @a obj and its prototype chain for an XPCOM object that implements
|
||||
|
@ -352,16 +354,20 @@ template <class T>
|
|||
inline JSBool
|
||||
xpc_qsUnwrapThis(JSContext *cx,
|
||||
JSObject *obj,
|
||||
JSObject *callee,
|
||||
T **ppThis,
|
||||
nsISupports **pThisRef,
|
||||
jsval *pThisVal)
|
||||
jsval *pThisVal,
|
||||
XPCLazyCallContext *lccx)
|
||||
{
|
||||
return xpc_qsUnwrapThisImpl(cx,
|
||||
obj,
|
||||
callee,
|
||||
NS_GET_TEMPLATE_IID(T),
|
||||
reinterpret_cast<void **>(ppThis),
|
||||
pThisRef,
|
||||
pThisVal);
|
||||
pThisVal,
|
||||
lccx);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -417,22 +423,19 @@ xpc_qsGetWrapperCache(void *p)
|
|||
|
||||
/** Convert an XPCOM pointer to jsval. Return JS_TRUE on success. */
|
||||
JSBool
|
||||
xpc_qsXPCOMObjectToJsval(XPCCallContext &ccx,
|
||||
xpc_qsXPCOMObjectToJsval(XPCLazyCallContext &lccx,
|
||||
nsISupports *p,
|
||||
nsWrapperCache *cache,
|
||||
XPCNativeInterface *iface,
|
||||
const nsIID *iid,
|
||||
XPCNativeInterface **iface,
|
||||
jsval *rval);
|
||||
|
||||
/**
|
||||
* Convert a variant to jsval. Return JS_TRUE on success.
|
||||
*
|
||||
* @a paramNum is used in error messages. XPConnect treats the return
|
||||
* value as a parameter in this regard.
|
||||
*/
|
||||
JSBool
|
||||
xpc_qsVariantToJsval(XPCCallContext &ccx,
|
||||
xpc_qsVariantToJsval(XPCLazyCallContext &ccx,
|
||||
nsIVariant *p,
|
||||
uintN paramNum,
|
||||
jsval *rval);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -450,14 +453,4 @@ xpc_qsSameResult(nsISupports *result1, nsISupports *result2)
|
|||
#define XPC_QS_ASSERT_CONTEXT_OK(cx) ((void) 0)
|
||||
#endif
|
||||
|
||||
#define XPC_QS_DEFINE_XPCNATIVEINTERFACE_GETTER(_iface, _iface_cache) \
|
||||
inline XPCNativeInterface* \
|
||||
_iface##_Interface(XPCCallContext& ccx) \
|
||||
{ \
|
||||
if(!(_iface_cache)) \
|
||||
(_iface_cache) = \
|
||||
XPCNativeInterface::GetNewOrUsed(ccx, &NS_GET_IID(_iface)); \
|
||||
return (_iface_cache); \
|
||||
}
|
||||
|
||||
#endif /* xpcquickstubs_h___ */
|
||||
|
|
|
@ -392,7 +392,7 @@ JSBool XPCVariant::InitializeData(XPCCallContext& ccx)
|
|||
|
||||
// static
|
||||
JSBool
|
||||
XPCVariant::VariantDataToJS(XPCCallContext& ccx,
|
||||
XPCVariant::VariantDataToJS(XPCLazyCallContext& lccx,
|
||||
nsIVariant* variant,
|
||||
JSObject* scope, nsresult* pErr,
|
||||
jsval* pJSVal)
|
||||
|
@ -447,6 +447,7 @@ XPCVariant::VariantDataToJS(XPCCallContext& ccx,
|
|||
xpctvar.flags = 0;
|
||||
JSBool success;
|
||||
|
||||
JSContext* cx = lccx.GetJSContext();
|
||||
switch(type)
|
||||
{
|
||||
case nsIDataType::VTYPE_INT8:
|
||||
|
@ -463,7 +464,7 @@ XPCVariant::VariantDataToJS(XPCCallContext& ccx,
|
|||
// Easy. Handle inline.
|
||||
if(NS_FAILED(variant->GetAsDouble(&xpctvar.val.d)))
|
||||
return JS_FALSE;
|
||||
return JS_NewNumberValue(ccx, xpctvar.val.d, pJSVal);
|
||||
return JS_NewNumberValue(cx, xpctvar.val.d, pJSVal);
|
||||
}
|
||||
case nsIDataType::VTYPE_BOOL:
|
||||
{
|
||||
|
@ -626,7 +627,7 @@ XPCVariant::VariantDataToJS(XPCCallContext& ccx,
|
|||
}
|
||||
|
||||
success =
|
||||
XPCConvert::NativeArray2JS(ccx, pJSVal,
|
||||
XPCConvert::NativeArray2JS(lccx, pJSVal,
|
||||
(const void**)&du.u.array.mArrayValue,
|
||||
conversionType, pid,
|
||||
du.u.array.mArrayCount,
|
||||
|
@ -638,7 +639,7 @@ VARIANT_DONE:
|
|||
}
|
||||
case nsIDataType::VTYPE_EMPTY_ARRAY:
|
||||
{
|
||||
JSObject* array = JS_NewArrayObject(ccx, 0, nsnull);
|
||||
JSObject* array = JS_NewArrayObject(cx, 0, nsnull);
|
||||
if(!array)
|
||||
return JS_FALSE;
|
||||
*pJSVal = OBJECT_TO_JSVAL(array);
|
||||
|
@ -660,14 +661,14 @@ VARIANT_DONE:
|
|||
if(xpctvar.type.TagPart() == TD_PSTRING_SIZE_IS ||
|
||||
xpctvar.type.TagPart() == TD_PWSTRING_SIZE_IS)
|
||||
{
|
||||
success = XPCConvert::NativeStringWithSize2JS(ccx, pJSVal,
|
||||
success = XPCConvert::NativeStringWithSize2JS(cx, pJSVal,
|
||||
(const void*)&xpctvar.val,
|
||||
xpctvar.type,
|
||||
size, pErr);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = XPCConvert::NativeData2JS(ccx, pJSVal,
|
||||
success = XPCConvert::NativeData2JS(lccx, pJSVal,
|
||||
(const void*)&xpctvar.val,
|
||||
xpctvar.type,
|
||||
&iid, scope, pErr);
|
||||
|
|
|
@ -1548,8 +1548,9 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex,
|
|||
|
||||
if(isArray)
|
||||
{
|
||||
|
||||
if(!XPCConvert::NativeArray2JS(ccx, &val, (const void**)&pv->val,
|
||||
XPCLazyCallContext lccx(ccx);
|
||||
if(!XPCConvert::NativeArray2JS(lccx, &val,
|
||||
(const void**)&pv->val,
|
||||
datum_type, ¶m_iid,
|
||||
array_count, obj, nsnull))
|
||||
goto pre_call_clean_up;
|
||||
|
|
|
@ -2769,7 +2769,8 @@ XPCWrappedNative::CallMethod(XPCCallContext& ccx,
|
|||
|
||||
if(isArray)
|
||||
{
|
||||
if(!XPCConvert::NativeArray2JS(ccx, &v, (const void**)&dp->val,
|
||||
XPCLazyCallContext lccx(ccx);
|
||||
if(!XPCConvert::NativeArray2JS(lccx, &v, (const void**)&dp->val,
|
||||
datum_type, ¶m_iid,
|
||||
array_count, ccx.GetCurrentJSObject(),
|
||||
&err))
|
||||
|
@ -3758,8 +3759,7 @@ static PRUint32 sSlimWrappers;
|
|||
|
||||
JSBool
|
||||
ConstructSlimWrapper(XPCCallContext &ccx, nsISupports *p, nsWrapperCache *cache,
|
||||
XPCNativeInterface *iface, XPCWrappedNativeScope* xpcScope,
|
||||
jsval *rval)
|
||||
XPCWrappedNativeScope* xpcScope, jsval *rval)
|
||||
{
|
||||
nsCOMPtr<nsISupports> identityObj = do_QueryInterface(p);
|
||||
|
||||
|
|
|
@ -280,12 +280,12 @@ XPCNativeInterface::GetNewOrUsed(XPCCallContext& ccx, const nsIID* iid)
|
|||
if(!iface2)
|
||||
{
|
||||
NS_ERROR("failed to add our interface!");
|
||||
DestroyInstance(ccx, rt, iface);
|
||||
DestroyInstance(iface);
|
||||
iface = nsnull;
|
||||
}
|
||||
else if(iface2 != iface)
|
||||
{
|
||||
DestroyInstance(ccx, rt, iface);
|
||||
DestroyInstance(iface);
|
||||
iface = iface2;
|
||||
}
|
||||
}
|
||||
|
@ -327,12 +327,12 @@ XPCNativeInterface::GetNewOrUsed(XPCCallContext& ccx, nsIInterfaceInfo* info)
|
|||
if(!iface2)
|
||||
{
|
||||
NS_ERROR("failed to add our interface!");
|
||||
DestroyInstance(ccx, rt, iface);
|
||||
DestroyInstance(iface);
|
||||
iface = nsnull;
|
||||
}
|
||||
else if(iface2 != iface)
|
||||
{
|
||||
DestroyInstance(ccx, rt, iface);
|
||||
DestroyInstance(iface);
|
||||
iface = iface2;
|
||||
}
|
||||
}
|
||||
|
@ -535,8 +535,7 @@ XPCNativeInterface::NewInstance(XPCCallContext& ccx,
|
|||
|
||||
// static
|
||||
void
|
||||
XPCNativeInterface::DestroyInstance(JSContext* cx, XPCJSRuntime* rt,
|
||||
XPCNativeInterface* inst)
|
||||
XPCNativeInterface::DestroyInstance(XPCNativeInterface* inst)
|
||||
{
|
||||
inst->~XPCNativeInterface();
|
||||
delete [] (char*) inst;
|
||||
|
|
|
@ -1131,6 +1131,10 @@ XPC_WN_Helper_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
|
|||
if(!si->GetFlags().WantNewResolve())
|
||||
return retval;
|
||||
|
||||
NS_ASSERTION(si->GetFlags().AllowPropModsToPrototype() &&
|
||||
!si->GetFlags().AllowPropModsDuringResolve(),
|
||||
"We don't support these flags for slim wrappers!");
|
||||
|
||||
rv = si->GetCallback()->NewResolve(nsnull, cx, obj, idval, flags,
|
||||
&obj2FromScriptable, &retval);
|
||||
if(NS_FAILED(rv))
|
||||
|
|
Загрузка…
Ссылка в новой задаче