Bug 863767 - GC: Rooting for XPCCallContext r=bholley

This commit is contained in:
Jon Coppeard 2013-04-20 09:52:56 +01:00
parent 6b41db971f
commit 7b2f5e54d8
6 changed files with 90 additions and 82 deletions

View File

@ -13,15 +13,16 @@
using namespace mozilla;
using namespace xpc;
using namespace JS;
XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
JSContext* cx /* = nullptr */,
JSObject* obj /* = nullptr */,
JSObject* funobj /* = nullptr */,
jsid name /* = JSID_VOID */,
unsigned argc /* = NO_ARGS */,
jsval *argv /* = nullptr */,
jsval *rval /* = nullptr */)
JSContext* cx /* = GetDefaultJSContext() */,
HandleObject obj /* = nullptr */,
HandleObject funobj /* = nullptr */,
HandleId name /* = JSID_VOID */,
unsigned argc /* = NO_ARGS */,
jsval *argv /* = nullptr */,
jsval *rval /* = nullptr */)
: mState(INIT_FAILED),
mXPC(nsXPConnect::GetXPConnect()),
mXPCContext(nullptr),
@ -29,12 +30,13 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
mContextPopRequired(false),
mDestroyJSContextInDestructor(false),
mCallerLanguage(callerLanguage),
mScopeForNewJSObjects(xpc_GetSafeJSContext()),
mFlattenedJSObject(xpc_GetSafeJSContext()),
mScopeForNewJSObjects(cx),
mFlattenedJSObject(cx),
mWrapper(nullptr),
mTearOff(nullptr),
mName(xpc_GetSafeJSContext())
mName(cx)
{
MOZ_ASSERT(cx);
Init(callerLanguage, callerLanguage == NATIVE_CALLER, obj, funobj,
INIT_SHOULD_LOOKUP_WRAPPER, name, argc, argv, rval);
}
@ -42,8 +44,8 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
JSContext* cx,
JSBool callBeginRequest,
JSObject* obj,
JSObject* flattenedJSObject,
HandleObject obj,
HandleObject flattenedJSObject,
XPCWrappedNative* wrapper,
XPCWrappedNativeTearOff* tearOff)
: mState(INIT_FAILED),
@ -53,61 +55,58 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
mContextPopRequired(false),
mDestroyJSContextInDestructor(false),
mCallerLanguage(callerLanguage),
mScopeForNewJSObjects(xpc_GetSafeJSContext()),
mFlattenedJSObject(xpc_GetSafeJSContext(), flattenedJSObject),
mScopeForNewJSObjects(cx),
mFlattenedJSObject(cx, flattenedJSObject),
mWrapper(wrapper),
mTearOff(tearOff),
mName(xpc_GetSafeJSContext())
mName(cx)
{
Init(callerLanguage, callBeginRequest, obj, nullptr,
WRAPPER_PASSED_TO_CONSTRUCTOR, JSID_VOID, NO_ARGS,
MOZ_ASSERT(cx);
Init(callerLanguage, callBeginRequest, obj, NullPtr(),
WRAPPER_PASSED_TO_CONSTRUCTOR, JSID_VOIDHANDLE, NO_ARGS,
nullptr, nullptr);
}
#define IS_TEAROFF_CLASS(clazz) ((clazz) == &XPC_WN_Tearoff_JSClass)
// static
JSContext *
XPCCallContext::GetDefaultJSContext()
{
// This is slightly questionable. If called without an explicit
// JSContext (generally a call to a wrappedJS) we will use the JSContext
// on the top of the JSContext stack - if there is one - *before*
// falling back on the safe JSContext.
// This is good AND bad because it makes calls from JS -> native -> JS
// have JS stack 'continuity' for purposes of stack traces etc.
// Note: this *is* what the pre-XPCCallContext xpconnect did too.
XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack();
JSContext *topJSContext = stack->Peek();
return topJSContext ? topJSContext : stack->GetSafeJSContext();
}
void
XPCCallContext::Init(XPCContext::LangType callerLanguage,
JSBool callBeginRequest,
JSObject* obj,
JSObject* funobj,
HandleObject obj,
HandleObject funobj,
WrapperInitOptions wrapperInitOptions,
jsid name,
HandleId name,
unsigned argc,
jsval *argv,
jsval *rval)
{
NS_ASSERTION(mJSContext, "No JSContext supplied to XPCCallContext");
if (!mXPC)
return;
XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack();
if (!stack) {
// If we don't have a stack we're probably in shutdown.
mJSContext = nullptr;
return;
}
JSContext *topJSContext = stack->Peek();
if (!mJSContext) {
// This is slightly questionable. If called without an explicit
// JSContext (generally a call to a wrappedJS) we will use the JSContext
// on the top of the JSContext stack - if there is one - *before*
// falling back on the safe JSContext.
// This is good AND bad because it makes calls from JS -> native -> JS
// have JS stack 'continuity' for purposes of stack traces etc.
// Note: this *is* what the pre-XPCCallContext xpconnect did too.
if (topJSContext) {
mJSContext = topJSContext;
} else {
mJSContext = stack->GetSafeJSContext();
if (!mJSContext)
return;
}
}
if (topJSContext != mJSContext) {
if (!stack->Push(mJSContext)) {
NS_ERROR("bad!");
@ -204,7 +203,7 @@ XPCCallContext::SetName(jsid name)
if (mTearOff) {
mSet = nullptr;
mInterface = mTearOff->GetInterface();
mMember = mInterface->FindMember(name);
mMember = mInterface->FindMember(mName);
mStaticMemberIsLocal = true;
if (mMember && !mMember->IsConstant())
mMethodIndex = mMember->GetIndex();
@ -212,7 +211,7 @@ XPCCallContext::SetName(jsid name)
mSet = mWrapper ? mWrapper->GetSet() : nullptr;
if (mSet &&
mSet->FindMember(name, &mMember, &mInterface,
mSet->FindMember(mName, &mMember, &mInterface,
mWrapper->HasProto() ?
mWrapper->GetProto()->GetSet() :
nullptr,
@ -459,9 +458,8 @@ XPCLazyCallContext::AssertContextIsTopOfStack(JSContext* cx)
#endif
XPCWrappedNative*
XPCCallContext::UnwrapThisIfAllowed(JSObject *object, JSObject *fun, unsigned argc)
XPCCallContext::UnwrapThisIfAllowed(HandleObject obj, HandleObject fun, unsigned argc)
{
JS::Rooted<JSObject *> obj(mJSContext, object);
// We should only get here for objects that aren't safe to unwrap.
MOZ_ASSERT(!js::CheckedUnwrap(obj));
MOZ_ASSERT(js::IsObjectInContextCompartment(obj, mJSContext));
@ -482,7 +480,7 @@ XPCCallContext::UnwrapThisIfAllowed(JSObject *object, JSObject *fun, unsigned ar
// First, get the XPCWN out of the underlying object. We should have a wrapper
// here, potentially an outer window proxy, and then an XPCWN.
MOZ_ASSERT(js::IsWrapper(obj));
JSObject *unwrapped = js::UncheckedUnwrap(obj, /* stopAtOuter = */ false);
RootedObject unwrapped(mJSContext, js::UncheckedUnwrap(obj, /* stopAtOuter = */ false));
MOZ_ASSERT(unwrapped == JS_ObjectToInnerObject(mJSContext, js::Wrapper::wrappedObject(obj)));
// Make sure we have an XPCWN, and grab it.

View File

@ -837,9 +837,8 @@ nsJSCID::Construct(nsIXPConnectWrappedNative *wrapper,
return NS_ERROR_FAILURE;
// 'push' a call context and call on it
XPCCallContext ccx(JS_CALLER, cx, obj, nullptr,
rt->GetStringID(XPCJSRuntime::IDX_CREATE_INSTANCE),
argc, argv, vp);
RootedId name(cx, rt->GetStringID(XPCJSRuntime::IDX_CREATE_INSTANCE));
XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), name, argc, argv, vp);
*_retval = XPCWrappedNative::CallMethod(ccx);
return NS_OK;

View File

@ -625,6 +625,8 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
}
JSContext *context = GetContextFromObject(self->GetJSObject());
if (!context)
context = XPCCallContext::GetDefaultJSContext();
XPCCallContext ccx(NATIVE_CALLER, context);
if (!ccx.IsValid()) {
*aInstancePtr = nullptr;
@ -1142,6 +1144,8 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
// convert natives to JSObjects, but we do NOT plan to pass those JSObjects
// to our real callee.
JSContext *context = GetContextFromObject(wrapper->GetJSObject());
if (!context)
context = XPCCallContext::GetDefaultJSContext();
XPCCallContext ccx(NATIVE_CALLER, context);
if (!ccx.IsValid())
return retval;

View File

@ -77,7 +77,7 @@ ToStringGuts(XPCCallContext& ccx)
static JSBool
XPC_WN_Shared_ToString(JSContext *cx, unsigned argc, jsval *vp)
{
JSObject *obj = JS_THIS_OBJECT(cx, vp);
RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
if (!obj)
return false;
@ -93,7 +93,7 @@ XPC_WN_Shared_ToString(JSContext *cx, unsigned argc, jsval *vp)
# define FMT_STR(str)
# define PARAM_ADDR(w)
#endif
char *sz = JS_smprintf("[object %s" FMT_ADDR FMT_STR(" (native") FMT_ADDR FMT_STR(")") "]", si->GetJSClass()->name PARAM_ADDR(obj) PARAM_ADDR(xpc_GetJSPrivate(obj)));
char *sz = JS_smprintf("[object %s" FMT_ADDR FMT_STR(" (native") FMT_ADDR FMT_STR(")") "]", si->GetJSClass()->name PARAM_ADDR(obj.get()) PARAM_ADDR(xpc_GetJSPrivate(obj)));
if (!sz)
return false;
@ -473,7 +473,7 @@ DefinePropertyIfFound(XPCCallContext& ccx,
static JSBool
XPC_WN_OnlyIWrite_AddPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp)
{
XPCCallContext ccx(JS_CALLER, cx, obj, nullptr, id);
XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), id);
XPCWrappedNative* wrapper = ccx.GetWrapper();
THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
@ -701,7 +701,7 @@ static JSBool
XPC_WN_NoHelper_Resolve(JSContext *cx, JSHandleObject obj, JSHandleId id)
{
MORPH_SLIM_WRAPPER(cx, obj);
XPCCallContext ccx(JS_CALLER, cx, obj, nullptr, id);
XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), id);
XPCWrappedNative* wrapper = ccx.GetWrapper();
THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
@ -962,7 +962,7 @@ XPC_WN_Helper_Call(JSContext *cx, unsigned argc, jsval *vp)
// N.B. we want obj to be the callee, not JS_THIS(cx, vp)
RootedObject obj(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
XPCCallContext ccx(JS_CALLER, cx, obj, nullptr, JSID_VOID,
XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), JSID_VOIDHANDLE,
argc, JS_ARGV(cx, vp), vp);
if (!ccx.IsValid())
return false;
@ -982,7 +982,7 @@ XPC_WN_Helper_Construct(JSContext *cx, unsigned argc, jsval *vp)
if (!obj)
return false;
XPCCallContext ccx(JS_CALLER, cx, obj, nullptr, JSID_VOID,
XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), JSID_VOIDHANDLE,
argc, JS_ARGV(cx, vp), vp);
if (!ccx.IsValid())
return false;
@ -1472,7 +1472,8 @@ XPC_WN_CallMethod(JSContext *cx, unsigned argc, jsval *vp)
return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
obj = FixUpThisIfBroken(obj, funobj);
XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOID, argc, JS_ARGV(cx, vp), vp);
XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, argc,
JS_ARGV(cx, vp), vp);
XPCWrappedNative* wrapper = ccx.GetWrapper();
THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
@ -1511,7 +1512,8 @@ XPC_WN_GetterSetter(JSContext *cx, unsigned argc, jsval *vp)
obj = FixUpThisIfBroken(obj, funobj);
XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOID, argc, JS_ARGV(cx, vp), vp);
XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, argc,
JS_ARGV(cx, vp), vp);
XPCWrappedNative* wrapper = ccx.GetWrapper();
THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);

View File

@ -1139,14 +1139,16 @@ public:
enum {NO_ARGS = (unsigned) -1};
static JSContext* GetDefaultJSContext();
XPCCallContext(XPCContext::LangType callerLanguage,
JSContext* cx = nullptr,
JSObject* obj = nullptr,
JSObject* funobj = nullptr,
jsid id = JSID_VOID,
unsigned argc = NO_ARGS,
jsval *argv = nullptr,
jsval *rval = nullptr);
JSContext* cx = GetDefaultJSContext(),
JS::HandleObject obj = JS::NullPtr(),
JS::HandleObject funobj = JS::NullPtr(),
JS::HandleId id = JS::JSID_VOIDHANDLE,
unsigned argc = NO_ARGS,
jsval *argv = nullptr,
jsval *rval = nullptr);
virtual ~XPCCallContext();
@ -1228,8 +1230,8 @@ private:
XPCCallContext(XPCContext::LangType callerLanguage,
JSContext* cx,
JSBool callBeginRequest,
JSObject* obj,
JSObject* flattenedJSObject,
JS::HandleObject obj,
JS::HandleObject flattenedJSObject,
XPCWrappedNative* wn,
XPCWrappedNativeTearOff* tearoff);
@ -1240,15 +1242,15 @@ private:
void Init(XPCContext::LangType callerLanguage,
JSBool callBeginRequest,
JSObject* obj,
JSObject* funobj,
JS::HandleObject obj,
JS::HandleObject funobj,
WrapperInitOptions wrapperInitOptions,
jsid name,
JS::HandleId name,
unsigned argc,
jsval *argv,
jsval *rval);
XPCWrappedNative* UnwrapThisIfAllowed(JSObject *obj, JSObject *fun,
XPCWrappedNative* UnwrapThisIfAllowed(JS::HandleObject obj, JS::HandleObject fun,
unsigned argc);
private:
@ -1399,12 +1401,14 @@ public:
{
if (!mCcx) {
XPCCallContext *data = mData.addr();
xpc_UnmarkGrayObject(mObj);
xpc_UnmarkGrayObject(mFlattenedJSObject);
mCcxToDestroy = mCcx =
new (data) XPCCallContext(mCallerLanguage, mCx,
mCallBeginRequest == CALL_BEGINREQUEST,
xpc_UnmarkGrayObject(mObj),
xpc_UnmarkGrayObject(mFlattenedJSObject),
mWrapper,
mObj,
mFlattenedJSObject,
mWrapper,
mTearOff);
if (!mCcx->IsValid()) {
NS_ERROR("This is not supposed to fail!");

View File

@ -756,7 +756,8 @@ XPCWrappedNativeXrayTraits::resolveNativeProperty(JSContext *cx, HandleObject wr
desc->obj = NULL;
// This will do verification and the method lookup for us.
XPCCallContext ccx(JS_CALLER, cx, getTargetObject(wrapper), nullptr, id);
RootedObject target(cx, getTargetObject(wrapper));
XPCCallContext ccx(JS_CALLER, cx, target, NullPtr(), id);
// There are no native numeric properties, so we can shortcut here. We will
// not find the property. However we want to support non shadowing dom
@ -1115,8 +1116,8 @@ XPCWrappedNativeXrayTraits::call(JSContext *cx, HandleObject wrapper,
// Run the resolve hook of the wrapped native.
XPCWrappedNative *wn = getWN(wrapper);
if (NATIVE_HAS_FLAG(wn, WantCall)) {
XPCCallContext ccx(JS_CALLER, cx, wrapper, nullptr, JSID_VOID, args.length(), args.array(),
args.rval().address());
XPCCallContext ccx(JS_CALLER, cx, wrapper, NullPtr(), JSID_VOIDHANDLE, args.length(),
args.array(), args.rval().address());
if (!ccx.IsValid())
return false;
bool ok = true;
@ -1140,8 +1141,8 @@ XPCWrappedNativeXrayTraits::construct(JSContext *cx, HandleObject wrapper,
// Run the resolve hook of the wrapped native.
XPCWrappedNative *wn = getWN(wrapper);
if (NATIVE_HAS_FLAG(wn, WantConstruct)) {
XPCCallContext ccx(JS_CALLER, cx, wrapper, nullptr, JSID_VOID, args.length(), args.array(),
args.rval().address());
XPCCallContext ccx(JS_CALLER, cx, wrapper, NullPtr(), JSID_VOIDHANDLE, args.length(),
args.array(), args.rval().address());
if (!ccx.IsValid())
return false;
bool ok = true;