1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code, released
17 : * March 31, 1998.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Netscape Communications Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 1998
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * John Bandhauer <jband@netscape.com> (original author)
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : /* Call context. */
42 :
43 : #include "mozilla/Util.h"
44 :
45 : #include "xpcprivate.h"
46 :
47 : using namespace mozilla;
48 :
49 15741753 : XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
50 : JSContext* cx /* = nsnull */,
51 : JSObject* obj /* = nsnull */,
52 : JSObject* funobj /* = nsnull */,
53 : jsid name /* = JSID_VOID */,
54 : unsigned argc /* = NO_ARGS */,
55 : jsval *argv /* = nsnull */,
56 : jsval *rval /* = nsnull */)
57 : : mState(INIT_FAILED),
58 15741753 : mXPC(nsXPConnect::GetXPConnect()),
59 : mThreadData(nsnull),
60 : mXPCContext(nsnull),
61 : mJSContext(cx),
62 : mContextPopRequired(false),
63 : mDestroyJSContextInDestructor(false),
64 31483506 : mCallerLanguage(callerLanguage)
65 : {
66 : Init(callerLanguage, callerLanguage == NATIVE_CALLER, obj, funobj,
67 15741753 : INIT_SHOULD_LOOKUP_WRAPPER, name, argc, argv, rval);
68 15741753 : }
69 :
70 132930 : XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
71 : JSContext* cx,
72 : JSBool callBeginRequest,
73 : JSObject* obj,
74 : JSObject* flattenedJSObject,
75 : XPCWrappedNative* wrapper,
76 : XPCWrappedNativeTearOff* tearOff)
77 : : mState(INIT_FAILED),
78 132930 : mXPC(nsXPConnect::GetXPConnect()),
79 : mThreadData(nsnull),
80 : mXPCContext(nsnull),
81 : mJSContext(cx),
82 : mContextPopRequired(false),
83 : mDestroyJSContextInDestructor(false),
84 : mCallerLanguage(callerLanguage),
85 : mFlattenedJSObject(flattenedJSObject),
86 : mWrapper(wrapper),
87 265860 : mTearOff(tearOff)
88 : {
89 : Init(callerLanguage, callBeginRequest, obj, nsnull,
90 : WRAPPER_PASSED_TO_CONSTRUCTOR, JSID_VOID, NO_ARGS,
91 132930 : nsnull, nsnull);
92 132930 : }
93 :
94 : void
95 15874683 : XPCCallContext::Init(XPCContext::LangType callerLanguage,
96 : JSBool callBeginRequest,
97 : JSObject* obj,
98 : JSObject* funobj,
99 : WrapperInitOptions wrapperInitOptions,
100 : jsid name,
101 : unsigned argc,
102 : jsval *argv,
103 : jsval *rval)
104 : {
105 15874683 : if (!mXPC)
106 0 : return;
107 :
108 15874683 : mThreadData = XPCPerThreadData::GetData(mJSContext);
109 :
110 15874683 : if (!mThreadData)
111 0 : return;
112 :
113 15874683 : XPCJSContextStack* stack = mThreadData->GetJSContextStack();
114 :
115 15874683 : if (!stack) {
116 : // If we don't have a stack we're probably in shutdown.
117 0 : mJSContext = nsnull;
118 0 : return;
119 : }
120 :
121 15874683 : JSContext *topJSContext = stack->Peek();
122 :
123 15874683 : if (!mJSContext) {
124 : // This is slightly questionable. If called without an explicit
125 : // JSContext (generally a call to a wrappedJS) we will use the JSContext
126 : // on the top of the JSContext stack - if there is one - *before*
127 : // falling back on the safe JSContext.
128 : // This is good AND bad because it makes calls from JS -> native -> JS
129 : // have JS stack 'continuity' for purposes of stack traces etc.
130 : // Note: this *is* what the pre-XPCCallContext xpconnect did too.
131 :
132 1851562 : if (topJSContext) {
133 1755364 : mJSContext = topJSContext;
134 : } else {
135 96198 : mJSContext = stack->GetSafeJSContext();
136 96198 : if (!mJSContext)
137 0 : return;
138 : }
139 : }
140 :
141 15874683 : if (topJSContext != mJSContext) {
142 195436 : if (!stack->Push(mJSContext)) {
143 0 : NS_ERROR("bad!");
144 0 : return;
145 : }
146 195436 : mContextPopRequired = true;
147 : }
148 :
149 : // Get into the request as early as we can to avoid problems with scanning
150 : // callcontexts on other threads from within the gc callbacks.
151 :
152 15874683 : NS_ASSERTION(!callBeginRequest || mCallerLanguage == NATIVE_CALLER,
153 : "Don't call JS_BeginRequest unless the caller is native.");
154 15874683 : if (callBeginRequest)
155 2539405 : JS_BeginRequest(mJSContext);
156 :
157 15874683 : mXPCContext = XPCContext::GetXPCContext(mJSContext);
158 15874683 : mPrevCallerLanguage = mXPCContext->SetCallingLangType(mCallerLanguage);
159 :
160 : // hook into call context chain for our thread
161 15874683 : mPrevCallContext = mThreadData->SetCallContext(this);
162 :
163 : // We only need to addref xpconnect once so only do it if this is the first
164 : // context in the chain.
165 15874683 : if (!mPrevCallContext)
166 4278171 : NS_ADDREF(mXPC);
167 :
168 15874683 : mState = HAVE_CONTEXT;
169 :
170 15874683 : if (!obj)
171 3911940 : return;
172 :
173 11962743 : mScopeForNewJSObjects = obj;
174 :
175 11962743 : mState = HAVE_SCOPE;
176 :
177 11962743 : mMethodIndex = 0xDEAD;
178 :
179 11962743 : mState = HAVE_OBJECT;
180 :
181 11962743 : mTearOff = nsnull;
182 11962743 : if (wrapperInitOptions == INIT_SHOULD_LOOKUP_WRAPPER) {
183 : mWrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(mJSContext, obj,
184 : funobj,
185 : &mFlattenedJSObject,
186 11829813 : &mTearOff);
187 11829813 : if (mWrapper) {
188 11829813 : DEBUG_CheckWrapperThreadSafety(mWrapper);
189 :
190 11829813 : mFlattenedJSObject = mWrapper->GetFlatJSObject();
191 :
192 11829813 : if (mTearOff)
193 248 : mScriptableInfo = nsnull;
194 : else
195 11829565 : mScriptableInfo = mWrapper->GetScriptableInfo();
196 : } else {
197 0 : NS_ABORT_IF_FALSE(!mFlattenedJSObject || IS_SLIM_WRAPPER(mFlattenedJSObject),
198 : "should have a slim wrapper");
199 : }
200 : }
201 :
202 11962743 : if (!JSID_IS_VOID(name))
203 3236236 : SetName(name);
204 :
205 11962743 : if (argc != NO_ARGS)
206 4420250 : SetArgsAndResultPtr(argc, argv, rval);
207 :
208 11962743 : CHECK_STATE(HAVE_OBJECT);
209 : }
210 :
211 : void
212 3285355 : XPCCallContext::SetName(jsid name)
213 : {
214 3285355 : CHECK_STATE(HAVE_OBJECT);
215 :
216 3285355 : mName = name;
217 :
218 3285355 : if (mTearOff) {
219 79 : mSet = nsnull;
220 79 : mInterface = mTearOff->GetInterface();
221 79 : mMember = mInterface->FindMember(name);
222 79 : mStaticMemberIsLocal = true;
223 79 : if (mMember && !mMember->IsConstant())
224 79 : mMethodIndex = mMember->GetIndex();
225 : } else {
226 3285276 : mSet = mWrapper ? mWrapper->GetSet() : nsnull;
227 :
228 6570552 : if (mSet &&
229 : mSet->FindMember(name, &mMember, &mInterface,
230 3285276 : mWrapper->HasProto() ?
231 246848 : mWrapper->GetProto()->GetSet() :
232 : nsnull,
233 6817400 : &mStaticMemberIsLocal)) {
234 3254076 : if (mMember && !mMember->IsConstant())
235 3241465 : mMethodIndex = mMember->GetIndex();
236 : } else {
237 31200 : mMember = nsnull;
238 31200 : mInterface = nsnull;
239 31200 : mStaticMemberIsLocal = false;
240 : }
241 : }
242 :
243 3285355 : mState = HAVE_NAME;
244 3285355 : }
245 :
246 : void
247 6731668 : XPCCallContext::SetCallInfo(XPCNativeInterface* iface, XPCNativeMember* member,
248 : JSBool isSetter)
249 : {
250 6731668 : CHECK_STATE(HAVE_CONTEXT);
251 :
252 : // We are going straight to the method info and need not do a lookup
253 : // by id.
254 :
255 : // don't be tricked if method is called with wrong 'this'
256 6731668 : if (mTearOff && mTearOff->GetInterface() != iface)
257 0 : mTearOff = nsnull;
258 :
259 6731668 : mSet = nsnull;
260 6731668 : mInterface = iface;
261 6731668 : mMember = member;
262 6731668 : mMethodIndex = mMember->GetIndex() + (isSetter ? 1 : 0);
263 6731668 : mName = mMember->GetName();
264 :
265 6731668 : if (mState < HAVE_NAME)
266 9898 : mState = HAVE_NAME;
267 6731668 : }
268 :
269 : void
270 6826808 : XPCCallContext::SetArgsAndResultPtr(unsigned argc,
271 : jsval *argv,
272 : jsval *rval)
273 : {
274 6826808 : CHECK_STATE(HAVE_OBJECT);
275 :
276 6826808 : if (mState < HAVE_NAME) {
277 6777689 : mSet = nsnull;
278 6777689 : mInterface = nsnull;
279 6777689 : mMember = nsnull;
280 6777689 : mStaticMemberIsLocal = false;
281 : }
282 :
283 6826808 : mArgc = argc;
284 6826808 : mArgv = argv;
285 6826808 : mRetVal = rval;
286 :
287 6826808 : mState = HAVE_ARGS;
288 6826808 : }
289 :
290 : nsresult
291 6752344 : XPCCallContext::CanCallNow()
292 : {
293 : nsresult rv;
294 :
295 6752344 : if (!HasInterfaceAndMember())
296 0 : return NS_ERROR_UNEXPECTED;
297 6752344 : if (mState < HAVE_ARGS)
298 0 : return NS_ERROR_UNEXPECTED;
299 :
300 6752344 : if (!mTearOff) {
301 6752254 : mTearOff = mWrapper->FindTearOff(*this, mInterface, false, &rv);
302 6752254 : if (!mTearOff || mTearOff->GetInterface() != mInterface) {
303 0 : mTearOff = nsnull;
304 0 : return NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED;
305 : }
306 : }
307 :
308 : // Refresh in case FindTearOff extended the set
309 6752344 : mSet = mWrapper->GetSet();
310 :
311 6752344 : mState = READY_TO_CALL;
312 6752344 : return NS_OK;
313 : }
314 :
315 : void
316 0 : XPCCallContext::SystemIsBeingShutDown()
317 : {
318 : // XXX This is pretty questionable since the per thread cleanup stuff
319 : // can be making this call on one thread for call contexts on another
320 : // thread.
321 0 : NS_WARNING("Shutting Down XPConnect even through there is a live XPCCallContext");
322 0 : mThreadData = nsnull;
323 0 : mXPCContext = nsnull;
324 0 : mState = SYSTEM_SHUTDOWN;
325 0 : if (mPrevCallContext)
326 0 : mPrevCallContext->SystemIsBeingShutDown();
327 0 : }
328 :
329 15876593 : XPCCallContext::~XPCCallContext()
330 : {
331 : // do cleanup...
332 :
333 15874683 : bool shouldReleaseXPC = false;
334 :
335 15874683 : if (mXPCContext) {
336 15874683 : mXPCContext->SetCallingLangType(mPrevCallerLanguage);
337 :
338 : #ifdef DEBUG
339 15874683 : XPCCallContext* old = mThreadData->SetCallContext(mPrevCallContext);
340 15874683 : NS_ASSERTION(old == this, "bad pop from per thread data");
341 : #else
342 : (void) mThreadData->SetCallContext(mPrevCallContext);
343 : #endif
344 :
345 15874683 : shouldReleaseXPC = mPrevCallContext == nsnull;
346 : }
347 :
348 : // NB: Needs to happen before the context stack pop.
349 15874683 : if (mJSContext && mCallerLanguage == NATIVE_CALLER)
350 2642414 : JS_EndRequest(mJSContext);
351 :
352 15874683 : if (mContextPopRequired) {
353 195436 : XPCJSContextStack* stack = mThreadData->GetJSContextStack();
354 195436 : NS_ASSERTION(stack, "bad!");
355 195436 : if (stack) {
356 390872 : DebugOnly<JSContext*> poppedCX = stack->Pop();
357 195436 : NS_ASSERTION(poppedCX == mJSContext, "bad pop");
358 : }
359 : }
360 :
361 15874683 : if (mJSContext) {
362 15874683 : if (mDestroyJSContextInDestructor) {
363 : #ifdef DEBUG_xpc_hacker
364 : printf("!xpc - doing deferred destruction of JSContext @ %p\n",
365 : mJSContext);
366 : #endif
367 0 : NS_ASSERTION(!mThreadData->GetJSContextStack() ||
368 : !mThreadData->GetJSContextStack()->
369 : DEBUG_StackHasJSContext(mJSContext),
370 : "JSContext still in threadjscontextstack!");
371 :
372 0 : JS_DestroyContext(mJSContext);
373 : }
374 : }
375 :
376 : #ifdef DEBUG
377 47624049 : for (PRUint32 i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i) {
378 31749366 : NS_ASSERTION(!mScratchStrings[i].mInUse, "Uh, string wrapper still in use!");
379 : }
380 : #endif
381 :
382 15874683 : if (shouldReleaseXPC && mXPC)
383 4278171 : NS_RELEASE(mXPC);
384 31753186 : }
385 :
386 : XPCReadableJSStringWrapper *
387 258385 : XPCCallContext::NewStringWrapper(const PRUnichar *str, PRUint32 len)
388 : {
389 314904 : for (PRUint32 i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i) {
390 298384 : StringWrapperEntry& ent = mScratchStrings[i];
391 :
392 298384 : if (!ent.mInUse) {
393 241865 : ent.mInUse = true;
394 :
395 : // Construct the string using placement new.
396 :
397 241865 : return new (ent.mString.addr()) XPCReadableJSStringWrapper(str, len);
398 : }
399 : }
400 :
401 : // All our internal string wrappers are used, allocate a new string.
402 :
403 16520 : return new XPCReadableJSStringWrapper(str, len);
404 : }
405 :
406 : void
407 1599508 : XPCCallContext::DeleteString(nsAString *string)
408 : {
409 4338273 : for (PRUint32 i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i) {
410 2980630 : StringWrapperEntry& ent = mScratchStrings[i];
411 2980630 : if (string == ent.mString.addr()) {
412 : // One of our internal strings is no longer in use, mark
413 : // it as such and destroy the string.
414 :
415 241865 : ent.mInUse = false;
416 241865 : ent.mString.addr()->~XPCReadableJSStringWrapper();
417 :
418 241865 : return;
419 : }
420 : }
421 :
422 : // We're done with a string that's not one of our internal
423 : // strings, delete it.
424 1357643 : delete string;
425 : }
426 :
427 : /* readonly attribute nsISupports Callee; */
428 : NS_IMETHODIMP
429 0 : XPCCallContext::GetCallee(nsISupports * *aCallee)
430 : {
431 0 : nsISupports* temp = mWrapper ? mWrapper->GetIdentityObject() : nsnull;
432 0 : NS_IF_ADDREF(temp);
433 0 : *aCallee = temp;
434 0 : return NS_OK;
435 : }
436 :
437 : /* readonly attribute PRUint16 CalleeMethodIndex; */
438 : NS_IMETHODIMP
439 0 : XPCCallContext::GetCalleeMethodIndex(PRUint16 *aCalleeMethodIndex)
440 : {
441 0 : *aCalleeMethodIndex = mMethodIndex;
442 0 : return NS_OK;
443 : }
444 :
445 : /* readonly attribute nsIXPConnectWrappedNative CalleeWrapper; */
446 : NS_IMETHODIMP
447 211137 : XPCCallContext::GetCalleeWrapper(nsIXPConnectWrappedNative * *aCalleeWrapper)
448 : {
449 211137 : nsIXPConnectWrappedNative* temp = mWrapper;
450 211137 : NS_IF_ADDREF(temp);
451 211137 : *aCalleeWrapper = temp;
452 211137 : return NS_OK;
453 : }
454 :
455 : /* readonly attribute XPCNativeInterface CalleeInterface; */
456 : NS_IMETHODIMP
457 0 : XPCCallContext::GetCalleeInterface(nsIInterfaceInfo * *aCalleeInterface)
458 : {
459 0 : nsIInterfaceInfo* temp = mInterface->GetInterfaceInfo();
460 0 : NS_IF_ADDREF(temp);
461 0 : *aCalleeInterface = temp;
462 0 : return NS_OK;
463 : }
464 :
465 : /* readonly attribute nsIClassInfo CalleeClassInfo; */
466 : NS_IMETHODIMP
467 0 : XPCCallContext::GetCalleeClassInfo(nsIClassInfo * *aCalleeClassInfo)
468 : {
469 0 : nsIClassInfo* temp = mWrapper ? mWrapper->GetClassInfo() : nsnull;
470 0 : NS_IF_ADDREF(temp);
471 0 : *aCalleeClassInfo = temp;
472 0 : return NS_OK;
473 : }
474 :
475 : /* readonly attribute JSContextPtr JSContext; */
476 : NS_IMETHODIMP
477 11 : XPCCallContext::GetJSContext(JSContext * *aJSContext)
478 : {
479 11 : JS_AbortIfWrongThread(JS_GetRuntime(mJSContext));
480 11 : *aJSContext = mJSContext;
481 11 : return NS_OK;
482 : }
483 :
484 : /* readonly attribute PRUint32 Argc; */
485 : NS_IMETHODIMP
486 0 : XPCCallContext::GetArgc(PRUint32 *aArgc)
487 : {
488 0 : *aArgc = (PRUint32) mArgc;
489 0 : return NS_OK;
490 : }
491 :
492 : /* readonly attribute JSValPtr ArgvPtr; */
493 : NS_IMETHODIMP
494 0 : XPCCallContext::GetArgvPtr(jsval * *aArgvPtr)
495 : {
496 0 : *aArgvPtr = mArgv;
497 0 : return NS_OK;
498 : }
499 :
500 : NS_IMETHODIMP
501 421 : XPCCallContext::GetPreviousCallContext(nsAXPCNativeCallContext **aResult)
502 : {
503 421 : NS_ENSURE_ARG_POINTER(aResult);
504 421 : *aResult = GetPrevCallContext();
505 421 : return NS_OK;
506 : }
507 :
508 : NS_IMETHODIMP
509 397 : XPCCallContext::GetLanguage(PRUint16 *aResult)
510 : {
511 397 : NS_ENSURE_ARG_POINTER(aResult);
512 397 : *aResult = GetCallerLanguage();
513 397 : return NS_OK;
514 : }
515 :
516 : #ifdef DEBUG
517 : // static
518 : void
519 142781 : XPCLazyCallContext::AssertContextIsTopOfStack(JSContext* cx)
520 : {
521 142781 : XPCPerThreadData* tls = XPCPerThreadData::GetData(cx);
522 142781 : XPCJSContextStack* stack = tls->GetJSContextStack();
523 :
524 142781 : JSContext *topJSContext = stack->Peek();
525 142781 : NS_ASSERTION(cx == topJSContext, "wrong context on XPCJSContextStack!");
526 142781 : }
527 : #endif
|