Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim: set ts=8 sts=4 et sw=4 tw=99: */
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/. */
6 :
7 : /* Call context. */
8 :
9 : #include "xpcprivate.h"
10 : #include "jswrapper.h"
11 : #include "jsfriendapi.h"
12 : #include "nsContentUtils.h"
13 :
14 : using namespace mozilla;
15 : using namespace xpc;
16 : using namespace JS;
17 :
18 0 : static inline bool IsTearoffClass(const js::Class* clazz)
19 : {
20 0 : return clazz == &XPC_WN_Tearoff_JSClass;
21 : }
22 :
23 49131 : XPCCallContext::XPCCallContext(JSContext* cx,
24 : HandleObject obj /* = nullptr */,
25 : HandleObject funobj /* = nullptr */,
26 : HandleId name /* = JSID_VOID */,
27 : unsigned argc /* = NO_ARGS */,
28 : Value* argv /* = nullptr */,
29 49131 : Value* rval /* = nullptr */)
30 : : mAr(cx),
31 : mState(INIT_FAILED),
32 : mXPC(nsXPConnect::XPConnect()),
33 : mXPCJSContext(nullptr),
34 : mJSContext(cx),
35 : mWrapper(nullptr),
36 : mTearOff(nullptr),
37 49131 : mName(cx)
38 : {
39 49131 : MOZ_ASSERT(cx);
40 49131 : MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
41 :
42 49131 : if (!mXPC)
43 0 : return;
44 :
45 49131 : mXPCJSContext = XPCJSContext::Get();
46 :
47 : // hook into call context chain.
48 49131 : mPrevCallContext = mXPCJSContext->SetCallContext(this);
49 :
50 49131 : mState = HAVE_CONTEXT;
51 :
52 49131 : if (!obj)
53 9555 : return;
54 :
55 39576 : mMethodIndex = 0xDEAD;
56 :
57 39576 : mState = HAVE_OBJECT;
58 :
59 39576 : mTearOff = nullptr;
60 :
61 39576 : JSObject* unwrapped = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
62 39576 : if (!unwrapped) {
63 0 : JS_ReportErrorASCII(mJSContext, "Permission denied to call method on |this|");
64 0 : mState = INIT_FAILED;
65 0 : return;
66 : }
67 39576 : const js::Class* clasp = js::GetObjectClass(unwrapped);
68 39576 : if (IS_WN_CLASS(clasp)) {
69 39576 : mWrapper = XPCWrappedNative::Get(unwrapped);
70 0 : } else if (IsTearoffClass(clasp)) {
71 0 : mTearOff = (XPCWrappedNativeTearOff*)js::GetObjectPrivate(unwrapped);
72 0 : mWrapper = XPCWrappedNative::Get(
73 : &js::GetReservedSlot(unwrapped,
74 0 : XPC_WN_TEAROFF_FLAT_OBJECT_SLOT).toObject());
75 : }
76 39576 : if (mWrapper && !mTearOff) {
77 39576 : mScriptable = mWrapper->GetScriptable();
78 : }
79 :
80 39576 : if (!JSID_IS_VOID(name))
81 3917 : SetName(name);
82 :
83 39576 : if (argc != NO_ARGS)
84 11287 : SetArgsAndResultPtr(argc, argv, rval);
85 :
86 39576 : CHECK_STATE(HAVE_OBJECT);
87 : }
88 :
89 : void
90 4769 : XPCCallContext::SetName(jsid name)
91 : {
92 4769 : CHECK_STATE(HAVE_OBJECT);
93 :
94 4769 : mName = name;
95 :
96 4769 : if (mTearOff) {
97 0 : mSet = nullptr;
98 0 : mInterface = mTearOff->GetInterface();
99 0 : mMember = mInterface->FindMember(mName);
100 0 : mStaticMemberIsLocal = true;
101 0 : if (mMember && !mMember->IsConstant())
102 0 : mMethodIndex = mMember->GetIndex();
103 : } else {
104 4769 : mSet = mWrapper ? mWrapper->GetSet() : nullptr;
105 :
106 23845 : if (mSet &&
107 26189 : mSet->FindMember(mName, &mMember, &mInterface,
108 4769 : mWrapper->HasProto() ?
109 2344 : mWrapper->GetProto()->GetSet() :
110 : nullptr,
111 4769 : &mStaticMemberIsLocal)) {
112 4635 : if (mMember && !mMember->IsConstant())
113 4529 : mMethodIndex = mMember->GetIndex();
114 : } else {
115 134 : mMember = nullptr;
116 134 : mInterface = nullptr;
117 134 : mStaticMemberIsLocal = false;
118 : }
119 : }
120 :
121 4769 : mState = HAVE_NAME;
122 4769 : }
123 :
124 : void
125 11153 : XPCCallContext::SetCallInfo(XPCNativeInterface* iface, XPCNativeMember* member,
126 : bool isSetter)
127 : {
128 11153 : CHECK_STATE(HAVE_CONTEXT);
129 :
130 : // We are going straight to the method info and need not do a lookup
131 : // by id.
132 :
133 : // don't be tricked if method is called with wrong 'this'
134 11153 : if (mTearOff && mTearOff->GetInterface() != iface)
135 0 : mTearOff = nullptr;
136 :
137 11153 : mSet = nullptr;
138 11153 : mInterface = iface;
139 11153 : mMember = member;
140 11153 : mMethodIndex = mMember->GetIndex() + (isSetter ? 1 : 0);
141 11153 : mName = mMember->GetName();
142 :
143 11153 : if (mState < HAVE_NAME)
144 0 : mState = HAVE_NAME;
145 11153 : }
146 :
147 : void
148 12139 : XPCCallContext::SetArgsAndResultPtr(unsigned argc,
149 : Value* argv,
150 : Value* rval)
151 : {
152 12139 : CHECK_STATE(HAVE_OBJECT);
153 :
154 12139 : if (mState < HAVE_NAME) {
155 11287 : mSet = nullptr;
156 11287 : mInterface = nullptr;
157 11287 : mMember = nullptr;
158 11287 : mStaticMemberIsLocal = false;
159 : }
160 :
161 12139 : mArgc = argc;
162 12139 : mArgv = argv;
163 12139 : mRetVal = rval;
164 :
165 12139 : mState = HAVE_ARGS;
166 12139 : }
167 :
168 : nsresult
169 11997 : XPCCallContext::CanCallNow()
170 : {
171 : nsresult rv;
172 :
173 11997 : if (!HasInterfaceAndMember())
174 0 : return NS_ERROR_UNEXPECTED;
175 11997 : if (mState < HAVE_ARGS)
176 0 : return NS_ERROR_UNEXPECTED;
177 :
178 11997 : if (!mTearOff) {
179 11997 : mTearOff = mWrapper->FindTearOff(mInterface, false, &rv);
180 11997 : if (!mTearOff || mTearOff->GetInterface() != mInterface) {
181 0 : mTearOff = nullptr;
182 0 : return NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED;
183 : }
184 : }
185 :
186 : // Refresh in case FindTearOff extended the set
187 11997 : mSet = mWrapper->GetSet();
188 :
189 11997 : mState = READY_TO_CALL;
190 11997 : return NS_OK;
191 : }
192 :
193 : void
194 0 : XPCCallContext::SystemIsBeingShutDown()
195 : {
196 : // XXX This is pretty questionable since the per thread cleanup stuff
197 : // can be making this call on one thread for call contexts on another
198 : // thread.
199 0 : NS_WARNING("Shutting Down XPConnect even through there is a live XPCCallContext");
200 0 : mXPCJSContext = nullptr;
201 0 : mState = SYSTEM_SHUTDOWN;
202 0 : mSet = nullptr;
203 0 : mInterface = nullptr;
204 :
205 0 : if (mPrevCallContext)
206 0 : mPrevCallContext->SystemIsBeingShutDown();
207 0 : }
208 :
209 98258 : XPCCallContext::~XPCCallContext()
210 : {
211 49129 : if (mXPCJSContext) {
212 98258 : DebugOnly<XPCCallContext*> old = mXPCJSContext->SetCallContext(mPrevCallContext);
213 49129 : MOZ_ASSERT(old == this, "bad pop from per thread data");
214 : }
215 49129 : }
216 :
217 : NS_IMETHODIMP
218 0 : XPCCallContext::GetCallee(nsISupports * *aCallee)
219 : {
220 0 : nsCOMPtr<nsISupports> rval = mWrapper ? mWrapper->GetIdentityObject() : nullptr;
221 0 : rval.forget(aCallee);
222 0 : return NS_OK;
223 : }
224 :
225 : NS_IMETHODIMP
226 0 : XPCCallContext::GetCalleeMethodIndex(uint16_t* aCalleeMethodIndex)
227 : {
228 0 : *aCalleeMethodIndex = mMethodIndex;
229 0 : return NS_OK;
230 : }
231 :
232 : NS_IMETHODIMP
233 0 : XPCCallContext::GetCalleeInterface(nsIInterfaceInfo * *aCalleeInterface)
234 : {
235 0 : nsCOMPtr<nsIInterfaceInfo> rval = mInterface->GetInterfaceInfo();
236 0 : rval.forget(aCalleeInterface);
237 0 : return NS_OK;
238 : }
239 :
240 : NS_IMETHODIMP
241 0 : XPCCallContext::GetCalleeClassInfo(nsIClassInfo * *aCalleeClassInfo)
242 : {
243 0 : nsCOMPtr<nsIClassInfo> rval = mWrapper ? mWrapper->GetClassInfo() : nullptr;
244 0 : rval.forget(aCalleeClassInfo);
245 0 : return NS_OK;
246 : }
247 :
248 : NS_IMETHODIMP
249 0 : XPCCallContext::GetJSContext(JSContext * *aJSContext)
250 : {
251 0 : JS_AbortIfWrongThread(mJSContext);
252 0 : *aJSContext = mJSContext;
253 0 : return NS_OK;
254 : }
255 :
256 : NS_IMETHODIMP
257 0 : XPCCallContext::GetArgc(uint32_t* aArgc)
258 : {
259 0 : *aArgc = (uint32_t) mArgc;
260 0 : return NS_OK;
261 : }
262 :
263 : NS_IMETHODIMP
264 0 : XPCCallContext::GetArgvPtr(Value** aArgvPtr)
265 : {
266 0 : *aArgvPtr = mArgv;
267 0 : return NS_OK;
268 : }
269 :
270 : NS_IMETHODIMP
271 0 : XPCCallContext::GetPreviousCallContext(nsAXPCNativeCallContext** aResult)
272 : {
273 0 : NS_ENSURE_ARG_POINTER(aResult);
274 0 : *aResult = GetPrevCallContext();
275 0 : return NS_OK;
276 : }
|