1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
9 #include "xpcprivate.h"
10 #include "jsfriendapi.h"
11 #include "js/Object.h" // JS::GetClass, JS::GetReservedSlot
12 #include "js/Wrapper.h"
13 #include "nsContentUtils.h"
15 using namespace mozilla
;
19 static inline bool IsTearoffClass(const JSClass
* clazz
) {
20 return clazz
== &XPC_WN_Tearoff_JSClass
;
23 XPCCallContext::XPCCallContext(
24 JSContext
* cx
, HandleObject obj
/* = nullptr */,
25 HandleObject funobj
/* = nullptr */,
26 HandleId name
/* = JSID_VOID */, unsigned argc
/* = NO_ARGS */,
27 Value
* argv
/* = nullptr */, Value
* rval
/* = nullptr */)
28 : mState(INIT_FAILED
),
29 mXPC(nsXPConnect::XPConnect()),
30 mXPCJSContext(nullptr),
36 mStaticMemberIsLocal(false),
41 MOZ_ASSERT(cx
== nsContentUtils::GetCurrentJSContext());
47 mXPCJSContext
= XPCJSContext::Get();
49 // hook into call context chain.
50 mPrevCallContext
= mXPCJSContext
->SetCallContext(this);
52 mState
= HAVE_CONTEXT
;
58 mMethodIndex
= 0xDEAD;
65 js::CheckedUnwrapDynamic(obj
, cx
, /* stopAtWindowProxy = */ false);
67 JS_ReportErrorASCII(mJSContext
,
68 "Permission denied to call method on |this|");
72 const JSClass
* clasp
= JS::GetClass(unwrapped
);
73 if (clasp
->isWrappedNative()) {
74 mWrapper
= XPCWrappedNative::Get(unwrapped
);
75 } else if (IsTearoffClass(clasp
)) {
76 mTearOff
= XPCWrappedNativeTearOff::Get(unwrapped
);
77 mWrapper
= XPCWrappedNative::Get(
78 &JS::GetReservedSlot(unwrapped
, XPCWrappedNativeTearOff::FlatObjectSlot
)
81 if (mWrapper
&& !mTearOff
) {
82 mScriptable
= mWrapper
->GetScriptable();
89 if (argc
!= NO_ARGS
) {
90 SetArgsAndResultPtr(argc
, argv
, rval
);
93 CHECK_STATE(HAVE_OBJECT
);
96 void XPCCallContext::SetName(jsid name
) {
97 CHECK_STATE(HAVE_OBJECT
);
103 mInterface
= mTearOff
->GetInterface();
104 mMember
= mInterface
->FindMember(mName
);
105 mStaticMemberIsLocal
= true;
106 if (mMember
&& !mMember
->IsConstant()) {
107 mMethodIndex
= mMember
->GetIndex();
110 mSet
= mWrapper
? mWrapper
->GetSet() : nullptr;
114 mName
, &mMember
, &mInterface
,
115 mWrapper
->HasProto() ? mWrapper
->GetProto()->GetSet() : nullptr,
116 &mStaticMemberIsLocal
)) {
117 if (mMember
&& !mMember
->IsConstant()) {
118 mMethodIndex
= mMember
->GetIndex();
122 mInterface
= nullptr;
123 mStaticMemberIsLocal
= false;
130 void XPCCallContext::SetCallInfo(XPCNativeInterface
* iface
,
131 XPCNativeMember
* member
, bool isSetter
) {
132 CHECK_STATE(HAVE_CONTEXT
);
134 // We are going straight to the method info and need not do a lookup
137 // don't be tricked if method is called with wrong 'this'
138 if (mTearOff
&& mTearOff
->GetInterface() != iface
) {
145 mMethodIndex
= mMember
->GetIndex() + (isSetter
? 1 : 0);
146 mName
= mMember
->GetName();
148 if (mState
< HAVE_NAME
) {
153 void XPCCallContext::SetArgsAndResultPtr(unsigned argc
, Value
* argv
,
155 CHECK_STATE(HAVE_OBJECT
);
157 if (mState
< HAVE_NAME
) {
159 mInterface
= nullptr;
161 mStaticMemberIsLocal
= false;
171 nsresult
XPCCallContext::CanCallNow() {
174 if (!HasInterfaceAndMember()) {
175 return NS_ERROR_UNEXPECTED
;
177 if (mState
< HAVE_ARGS
) {
178 return NS_ERROR_UNEXPECTED
;
182 mTearOff
= mWrapper
->FindTearOff(mJSContext
, mInterface
, false, &rv
);
183 if (!mTearOff
|| mTearOff
->GetInterface() != mInterface
) {
185 return NS_FAILED(rv
) ? rv
: NS_ERROR_UNEXPECTED
;
189 // Refresh in case FindTearOff extended the set
190 mSet
= mWrapper
->GetSet();
192 mState
= READY_TO_CALL
;
196 void XPCCallContext::SystemIsBeingShutDown() {
197 // XXX This is pretty questionable since the per thread cleanup stuff
198 // can be making this call on one thread for call contexts on another
201 "Shutting Down XPConnect even through there is a live XPCCallContext");
202 mXPCJSContext
= nullptr;
203 mState
= SYSTEM_SHUTDOWN
;
205 mInterface
= nullptr;
207 if (mPrevCallContext
) {
208 mPrevCallContext
->SystemIsBeingShutDown();
212 XPCCallContext::~XPCCallContext() {
214 DebugOnly
<XPCCallContext
*> old
=
215 mXPCJSContext
->SetCallContext(mPrevCallContext
);
216 MOZ_ASSERT(old
== this, "bad pop from per thread data");