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);
  }
}
Beispiel #3
0
XPCCallContext::~XPCCallContext()
{
    // do cleanup...

    bool shouldReleaseXPC = false;

    if (mXPCContext) {
        mXPCContext->SetCallingLangType(mPrevCallerLanguage);

        DebugOnly<XPCCallContext*> old = XPCJSRuntime::Get()->SetCallContext(mPrevCallContext);
        NS_ASSERTION(old == this, "bad pop from per thread data");

        shouldReleaseXPC = mPrevCallContext == nullptr;
    }

    if (mContextPopRequired) {
        XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack();
        NS_ASSERTION(stack, "bad!");
        if (stack) {
            DebugOnly<JSContext*> poppedCX = stack->Pop();
            NS_ASSERTION(poppedCX == mJSContext, "bad pop");
        }
    }

    if (shouldReleaseXPC && mXPC)
        NS_RELEASE(mXPC);
}
Beispiel #4
0
// static
void
XPCLazyCallContext::AssertContextIsTopOfStack(JSContext* cx)
{
    XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack();

    JSContext *topJSContext = stack->Peek();
    NS_ASSERTION(cx == topJSContext, "wrong context on XPCJSContextStack!");
}
void
xpc_qsAssertContextOK(JSContext *cx)
{
    XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack();

    JSContext *topJSContext = stack->Peek();

    // This is what we're actually trying to assert here.
    MOZ_ASSERT(cx == topJSContext, "wrong context on XPCJSContextStack!");
}
// 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!");
}
Beispiel #7
0
// 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();
}
Beispiel #8
0
void
xpc_qsAssertContextOK(JSContext *cx)
{
    XPCPerThreadData *thread = XPCPerThreadData::GetData(cx);
    XPCJSContextStack* stack = thread->GetJSContextStack();

    JSContext* topJSContext = nsnull;
    nsresult rv = stack->Peek(&topJSContext);
    NS_ASSERTION(NS_SUCCEEDED(rv), "XPCJSContextStack::Peek failed");

    // This is what we're actually trying to assert here.
    NS_ASSERTION(cx == topJSContext, "wrong context on XPCJSContextStack!");

    NS_ASSERTION(XPCPerThreadData::IsMainThread(cx),
                 "XPConnect quick stub called on non-main thread");
}
Beispiel #9
0
XPCCallContext::~XPCCallContext()
{
    // do cleanup...

    bool shouldReleaseXPC = false;

    if (mXPCContext) {
        mXPCContext->SetCallingLangType(mPrevCallerLanguage);

        DebugOnly<XPCCallContext*> old = XPCJSRuntime::Get()->SetCallContext(mPrevCallContext);
        NS_ASSERTION(old == this, "bad pop from per thread data");

        shouldReleaseXPC = mPrevCallContext == nullptr;
    }

    // NB: Needs to happen before the context stack pop.
    if (mJSContext && mCallerLanguage == NATIVE_CALLER)
        JS_EndRequest(mJSContext);

    if (mContextPopRequired) {
        XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack();
        NS_ASSERTION(stack, "bad!");
        if (stack) {
            DebugOnly<JSContext*> poppedCX = stack->Pop();
            NS_ASSERTION(poppedCX == mJSContext, "bad pop");
        }
    }

    if (mJSContext) {
        if (mDestroyJSContextInDestructor) {
#ifdef DEBUG_xpc_hacker
            printf("!xpc - doing deferred destruction of JSContext @ %p\n",
                   mJSContext);
#endif
            NS_ASSERTION(!XPCJSRuntime::Get()->GetJSContextStack()->HasJSContext(mJSContext),
                         "JSContext still in threadjscontextstack!");

            JS_DestroyContext(mJSContext);
        }
    }

    if (shouldReleaseXPC && mXPC)
        NS_RELEASE(mXPC);
}
Beispiel #10
0
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);
  }
}
Beispiel #11
0
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);
}
Beispiel #12
0
XPCCallContext::~XPCCallContext()
{
    // do cleanup...

    bool shouldReleaseXPC = false;

    if (mXPCContext) {
        mXPCContext->SetCallingLangType(mPrevCallerLanguage);

#ifdef DEBUG
        XPCCallContext* old = mThreadData->SetCallContext(mPrevCallContext);
        NS_ASSERTION(old == this, "bad pop from per thread data");
#else
        (void) mThreadData->SetCallContext(mPrevCallContext);
#endif

        shouldReleaseXPC = mPrevCallContext == nsnull;
    }

    // NB: Needs to happen before the context stack pop.
    if (mJSContext && mCallerLanguage == NATIVE_CALLER)
        JS_EndRequest(mJSContext);

    if (mContextPopRequired) {
        XPCJSContextStack* stack = mThreadData->GetJSContextStack();
        NS_ASSERTION(stack, "bad!");
        if (stack) {
#ifdef DEBUG
            JSContext* poppedCX;
            nsresult rv = stack->Pop(&poppedCX);
            NS_ASSERTION(NS_SUCCEEDED(rv) && poppedCX == mJSContext, "bad pop");
#else
            (void) stack->Pop(nsnull);
#endif
        }
    }

    if (mJSContext) {
        if (mDestroyJSContextInDestructor) {
#ifdef DEBUG_xpc_hacker
            printf("!xpc - doing deferred destruction of JSContext @ %p\n",
                   mJSContext);
#endif
            NS_ASSERTION(!mThreadData->GetJSContextStack() ||
                         !mThreadData->GetJSContextStack()->
                         DEBUG_StackHasJSContext(mJSContext),
                         "JSContext still in threadjscontextstack!");

            JS_DestroyContext(mJSContext);
        }
    }

#ifdef DEBUG
    for (PRUint32 i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i) {
        NS_ASSERTION(!mScratchStrings[i].mInUse, "Uh, string wrapper still in use!");
    }
#endif

    if (shouldReleaseXPC && mXPC)
        NS_RELEASE(mXPC);
}
Beispiel #13
0
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);
}
Beispiel #14
0
XPCCallContext::~XPCCallContext()
{
    // do cleanup...

    PRBool shouldReleaseXPC = PR_FALSE;

    if(mXPCContext)
    {
        mXPCContext->SetCallingLangType(mPrevCallerLanguage);

#ifdef DEBUG
        XPCCallContext* old = mThreadData->SetCallContext(mPrevCallContext);
        NS_ASSERTION(old == this, "bad pop from per thread data");
#else
        (void) mThreadData->SetCallContext(mPrevCallContext);
#endif

        shouldReleaseXPC = mPrevCallContext == nsnull;
    }

    if(mContextPopRequired)
    {
        XPCJSContextStack* stack = mThreadData->GetJSContextStack();
        NS_ASSERTION(stack, "bad!");
        if(stack)
        {
#ifdef DEBUG
            JSContext* poppedCX;
            nsresult rv = stack->Pop(&poppedCX);
            NS_ASSERTION(NS_SUCCEEDED(rv) && poppedCX == mJSContext, "bad pop");
#else
            (void) stack->Pop(nsnull);
#endif
        }
    }

    if(mJSContext)
    {
        if(mCallerLanguage == NATIVE_CALLER)
            JS_EndRequest(mJSContext);
        
        if(mDestroyJSContextInDestructor)
        {
#ifdef DEBUG_xpc_hacker
            printf("!xpc - doing deferred destruction of JSContext @ %0x\n", 
                   mJSContext);
#endif
            NS_ASSERTION(!mThreadData->GetJSContextStack() || 
                         !mThreadData->GetJSContextStack()->
                            DEBUG_StackHasJSContext(mJSContext),
                         "JSContext still in threadjscontextstack!");
        
            JS_DestroyContext(mJSContext);
        }
        else
        {
            // Don't clear newborns if JS frames (compilation or execution)
            // are active!  Doing so violates ancient invariants in the JS
            // engine, and it's not necessary to fix JS component leaks.
            if(!JS_IsRunning(mJSContext))
                JS_ClearNewbornRoots(mJSContext);
        }
    }

#ifdef DEBUG
    {
        StringWrapperEntry *se =
            reinterpret_cast<StringWrapperEntry*>(&mStringWrapperData);

        PRUint32 i;
        for(i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i)
        {
            NS_ASSERTION(!se[i].mInUse, "Uh, string wrapper still in use!");
        }
    }
#endif

    if(shouldReleaseXPC && mXPC)
        NS_RELEASE(mXPC);
}
Beispiel #15
0
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);
}
Beispiel #16
0
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);
}