danger::AutoCxPusher::AutoCxPusher(JSContext* cx, bool allowNull) { MOZ_ASSERT_IF(!allowNull, cx); // Hold a strong ref to the nsIScriptContext, if any. This ensures that we // only destroy the mContext of an nsJSContext when it is not on the cx stack // (and therefore not in use). See nsJSContext::DestroyJSContext(). if (cx) mScx = GetScriptContextFromJSContext(cx); XPCJSContextStack *stack = XPCJSRuntime::Get()->GetJSContextStack(); if (!stack->Push(cx)) { MOZ_CRASH(); } mStackDepthAfterPush = stack->Count(); #ifdef DEBUG mPushedContext = cx; mCompartmentDepthOnEntry = cx ? js::GetEnterCompartmentDepth(cx) : 0; #endif // Enter a request and a compartment for the duration that the cx is on the // stack if non-null. if (cx) { mAutoRequest.emplace(cx); } }
AutoCxPusher::AutoCxPusher(JSContext* cx, bool allowNull) { MOZ_ASSERT_IF(!allowNull, cx); // Hold a strong ref to the nsIScriptContext, if any. This ensures that we // only destroy the mContext of an nsJSContext when it is not on the cx stack // (and therefore not in use). See nsJSContext::DestroyJSContext(). if (cx) mScx = GetScriptContextFromJSContext(cx); XPCJSContextStack *stack = XPCJSRuntime::Get()->GetJSContextStack(); if (!stack->Push(cx)) { MOZ_CRASH(); } mStackDepthAfterPush = stack->Count(); #ifdef DEBUG mPushedContext = cx; mCompartmentDepthOnEntry = cx ? js::GetEnterCompartmentDepth(cx) : 0; #endif // Enter a request and a compartment for the duration that the cx is on the // stack if non-null. if (cx) { mAutoRequest.construct(cx); // DOM JSContexts don't store their default compartment object on the cx. JSObject *compartmentObject = mScx ? mScx->GetWindowProxy() : js::DefaultObjectForContextOrNull(cx); if (compartmentObject) mAutoCompartment.construct(cx, compartmentObject); } }
AutoCxPusher::AutoCxPusher(JSContext* cx, bool allowNull) : mScriptIsRunning(false) { MOZ_ASSERT_IF(!allowNull, cx); // Hold a strong ref to the nsIScriptContext, if any. This ensures that we // only destroy the mContext of an nsJSContext when it is not on the cx stack // (and therefore not in use). See nsJSContext::DestroyJSContext(). if (cx) mScx = GetScriptContextFromJSContext(cx); // NB: The GetDynamicScriptContext is historical and might not be sane. XPCJSContextStack *stack = XPCJSRuntime::Get()->GetJSContextStack(); if (cx && nsJSUtils::GetDynamicScriptContext(cx) && stack->HasJSContext(cx)) { // If the context is on the stack, that means that a script // is running at the moment in the context. mScriptIsRunning = true; } if (!stack->Push(cx)) { MOZ_CRASH(); } #ifdef DEBUG mPushedContext = cx; mCompartmentDepthOnEntry = cx ? js::GetEnterCompartmentDepth(cx) : 0; #endif // Enter a request and a compartment for the duration that the cx is on the // stack if non-null. // // NB: We call UnmarkGrayContext so that this can obsolete the need for the // old XPCAutoRequest as well. if (cx) { mAutoRequest.construct(cx); if (js::DefaultObjectForContextOrNull(cx)) mAutoCompartment.construct(cx, js::DefaultObjectForContextOrNull(cx)); xpc_UnmarkGrayContext(cx); } }
void XPCCallContext::Init(XPCContext::LangType callerLanguage, JSBool callBeginRequest, JSObject* obj, JSObject* funobj, WrapperInitOptions wrapperInitOptions, jsid name, uintN argc, jsval *argv, jsval *rval) { if (!mXPC) return; mThreadData = XPCPerThreadData::GetData(mJSContext); if (!mThreadData) return; XPCJSContextStack* stack = mThreadData->GetJSContextStack(); JSContext* topJSContext; if (!stack || NS_FAILED(stack->Peek(&topJSContext))) { // If we don't have a stack we're probably in shutdown. NS_ASSERTION(!stack, "Bad, Peek failed!"); mJSContext = nsnull; return; } 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 if (NS_FAILED(stack->GetSafeJSContext(&mJSContext)) || !mJSContext) return; } if (topJSContext != mJSContext) { if (NS_FAILED(stack->Push(mJSContext))) { NS_ERROR("bad!"); return; } mContextPopRequired = true; } // Get into the request as early as we can to avoid problems with scanning // callcontexts on other threads from within the gc callbacks. NS_ASSERTION(!callBeginRequest || mCallerLanguage == NATIVE_CALLER, "Don't call JS_BeginRequest unless the caller is native."); if (callBeginRequest) JS_BeginRequest(mJSContext); mXPCContext = XPCContext::GetXPCContext(mJSContext); mPrevCallerLanguage = mXPCContext->SetCallingLangType(mCallerLanguage); // hook into call context chain for our thread mPrevCallContext = mThreadData->SetCallContext(this); // We only need to addref xpconnect once so only do it if this is the first // context in the chain. if (!mPrevCallContext) NS_ADDREF(mXPC); mState = HAVE_CONTEXT; if (!obj) return; mScopeForNewJSObjects = obj; mState = HAVE_SCOPE; mMethodIndex = 0xDEAD; mState = HAVE_OBJECT; mTearOff = nsnull; if (wrapperInitOptions == INIT_SHOULD_LOOKUP_WRAPPER) { mWrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(mJSContext, obj, funobj, &mFlattenedJSObject, &mTearOff); if (mWrapper) { DEBUG_CheckWrapperThreadSafety(mWrapper); mFlattenedJSObject = mWrapper->GetFlatJSObject(); if (mTearOff) mScriptableInfo = nsnull; else mScriptableInfo = mWrapper->GetScriptableInfo(); } else { NS_ABORT_IF_FALSE(!mFlattenedJSObject || IS_SLIM_WRAPPER(mFlattenedJSObject), "should have a slim wrapper"); } } if (!JSID_IS_VOID(name)) SetName(name); if (argc != NO_ARGS) SetArgsAndResultPtr(argc, argv, rval); CHECK_STATE(HAVE_OBJECT); }
XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage, JSContext* cx /* = nsnull */, JSObject* obj /* = nsnull */, JSObject* funobj /* = nsnull */, jsval name /* = 0 */, uintN argc /* = NO_ARGS */, jsval *argv /* = nsnull */, jsval *rval /* = nsnull */) : mState(INIT_FAILED), mXPC(nsXPConnect::GetXPConnect()), mThreadData(nsnull), mXPCContext(nsnull), mJSContext(cx), mContextPopRequired(JS_FALSE), mDestroyJSContextInDestructor(JS_FALSE), mCallerLanguage(callerLanguage), mCallee(nsnull) { // Mark our internal string wrappers as not used. Make sure we do // this before any early returns, as the destructor will assert // based on this. StringWrapperEntry *se = reinterpret_cast<StringWrapperEntry*>(&mStringWrapperData); PRUint32 i; for(i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i) { se[i].mInUse = PR_FALSE; } if(!mXPC) return; mThreadData = XPCPerThreadData::GetData(mJSContext); if(!mThreadData) return; XPCJSContextStack* stack = mThreadData->GetJSContextStack(); JSContext* topJSContext; if(!stack || NS_FAILED(stack->Peek(&topJSContext))) { // If we don't have a stack we're probably in shutdown. NS_ASSERTION(!stack, "Bad, Peek failed!"); mJSContext = nsnull; return; } 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 if(NS_FAILED(stack->GetSafeJSContext(&mJSContext)) || !mJSContext) return; } // 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) JS_BeginRequest(mJSContext); if(topJSContext != mJSContext) { if(NS_FAILED(stack->Push(mJSContext))) { NS_ERROR("bad!"); return; } mContextPopRequired = JS_TRUE; } mXPCContext = XPCContext::GetXPCContext(mJSContext); mPrevCallerLanguage = mXPCContext->SetCallingLangType(mCallerLanguage); // hook into call context chain for our thread mPrevCallContext = mThreadData->SetCallContext(this); // We only need to addref xpconnect once so only do it if this is the first // context in the chain. if(!mPrevCallContext) NS_ADDREF(mXPC); mState = HAVE_CONTEXT; if(!obj) return; mMethodIndex = 0xDEAD; mOperandJSObject = obj; mState = HAVE_OBJECT; mTearOff = nsnull; mWrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(mJSContext, obj, funobj, &mCurrentJSObject, &mTearOff); if(!mWrapper) return; DEBUG_CheckWrapperThreadSafety(mWrapper); mFlattenedJSObject = mWrapper->GetFlatJSObject(); if(mTearOff) mScriptableInfo = nsnull; else mScriptableInfo = mWrapper->GetScriptableInfo(); if(name) SetName(name); if(argc != NO_ARGS) SetArgsAndResultPtr(argc, argv, rval); CHECK_STATE(HAVE_OBJECT); }
void XPCCallContext::Init(XPCContext::LangType callerLanguage, JSBool callBeginRequest, HandleObject obj, HandleObject funobj, WrapperInitOptions wrapperInitOptions, HandleId name, unsigned argc, jsval *argv, jsval *rval) { NS_ASSERTION(mJSContext, "No JSContext supplied to XPCCallContext"); if (!mXPC) return; XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack(); JSContext *topJSContext = stack->Peek(); if (topJSContext != mJSContext) { if (!stack->Push(mJSContext)) { NS_ERROR("bad!"); return; } mContextPopRequired = true; } // Get into the request as early as we can to avoid problems with scanning // callcontexts on other threads from within the gc callbacks. NS_ASSERTION(!callBeginRequest || mCallerLanguage == NATIVE_CALLER, "Don't call JS_BeginRequest unless the caller is native."); if (callBeginRequest) JS_BeginRequest(mJSContext); mXPCContext = XPCContext::GetXPCContext(mJSContext); mPrevCallerLanguage = mXPCContext->SetCallingLangType(mCallerLanguage); // hook into call context chain. mPrevCallContext = XPCJSRuntime::Get()->SetCallContext(this); // We only need to addref xpconnect once so only do it if this is the first // context in the chain. if (!mPrevCallContext) NS_ADDREF(mXPC); mState = HAVE_CONTEXT; if (!obj) return; mScopeForNewJSObjects = obj; mState = HAVE_SCOPE; mMethodIndex = 0xDEAD; mState = HAVE_OBJECT; mTearOff = nullptr; if (wrapperInitOptions == INIT_SHOULD_LOOKUP_WRAPPER) { // If the object is a security wrapper, GetWrappedNativeOfJSObject can't // handle it. Do special handling here to make cross-origin Xrays work. JSObject *unwrapped = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); if (!unwrapped) { mWrapper = UnwrapThisIfAllowed(obj, funobj, argc); if (!mWrapper) { JS_ReportError(mJSContext, "Permission denied to call method on |this|"); mState = INIT_FAILED; return; } } else { js::Class *clasp = js::GetObjectClass(unwrapped); if (IS_WRAPPER_CLASS(clasp)) { if (IS_SLIM_WRAPPER_OBJECT(unwrapped)) mFlattenedJSObject = unwrapped; else mWrapper = XPCWrappedNative::Get(unwrapped); } else if (IS_TEAROFF_CLASS(clasp)) { mTearOff = (XPCWrappedNativeTearOff*)js::GetObjectPrivate(unwrapped); mWrapper = XPCWrappedNative::Get(js::GetObjectParent(unwrapped)); } } if (mWrapper) { mFlattenedJSObject = mWrapper->GetFlatJSObject(); if (mTearOff) mScriptableInfo = nullptr; else mScriptableInfo = mWrapper->GetScriptableInfo(); } else { NS_ABORT_IF_FALSE(!mFlattenedJSObject || IS_SLIM_WRAPPER(mFlattenedJSObject), "should have a slim wrapper"); } } if (!JSID_IS_VOID(name)) SetName(name); if (argc != NO_ARGS) SetArgsAndResultPtr(argc, argv, rval); CHECK_STATE(HAVE_OBJECT); }
XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage, JSContext* cx /* = GetDefaultJSContext() */, HandleObject obj /* = nullptr */, HandleObject funobj /* = nullptr */, HandleId name /* = JSID_VOID */, unsigned argc /* = NO_ARGS */, jsval *argv /* = nullptr */, jsval *rval /* = nullptr */) : mAr(cx), mState(INIT_FAILED), mXPC(nsXPConnect::XPConnect()), mXPCContext(nullptr), mJSContext(cx), mContextPopRequired(false), mCallerLanguage(callerLanguage), mFlattenedJSObject(cx), mWrapper(nullptr), mTearOff(nullptr), mName(cx) { MOZ_ASSERT(cx); NS_ASSERTION(mJSContext, "No JSContext supplied to XPCCallContext"); if (!mXPC) return; XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack(); JSContext *topJSContext = stack->Peek(); if (topJSContext != mJSContext) { if (!stack->Push(mJSContext)) { NS_ERROR("bad!"); return; } mContextPopRequired = true; } mXPCContext = XPCContext::GetXPCContext(mJSContext); mPrevCallerLanguage = mXPCContext->SetCallingLangType(mCallerLanguage); // hook into call context chain. mPrevCallContext = XPCJSRuntime::Get()->SetCallContext(this); // We only need to addref xpconnect once so only do it if this is the first // context in the chain. if (!mPrevCallContext) NS_ADDREF(mXPC); mState = HAVE_CONTEXT; if (!obj) return; mMethodIndex = 0xDEAD; mState = HAVE_OBJECT; mTearOff = nullptr; // If the object is a security wrapper, GetWrappedNativeOfJSObject can't // handle it. Do special handling here to make cross-origin Xrays work. JSObject *unwrapped = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); if (!unwrapped) { mWrapper = UnwrapThisIfAllowed(obj, funobj, argc); if (!mWrapper) { JS_ReportError(mJSContext, "Permission denied to call method on |this|"); mState = INIT_FAILED; return; } } else { js::Class *clasp = js::GetObjectClass(unwrapped); if (IS_WN_CLASS(clasp)) { mWrapper = XPCWrappedNative::Get(unwrapped); } else if (IS_TEAROFF_CLASS(clasp)) { mTearOff = (XPCWrappedNativeTearOff*)js::GetObjectPrivate(unwrapped); mWrapper = XPCWrappedNative::Get(js::GetObjectParent(unwrapped)); } } if (mWrapper) { mFlattenedJSObject = mWrapper->GetFlatJSObject(); if (mTearOff) mScriptableInfo = nullptr; else mScriptableInfo = mWrapper->GetScriptableInfo(); } else { NS_ABORT_IF_FALSE(!mFlattenedJSObject, "What object do we have?"); } if (!JSID_IS_VOID(name)) SetName(name); if (argc != NO_ARGS) SetArgsAndResultPtr(argc, argv, rval); CHECK_STATE(HAVE_OBJECT); }