/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * John Bandhauer (original author) * Pierre Phaneuf * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* High level class and public functions implementation. */ #include "xpcprivate.h" NS_IMPL_THREADSAFE_ISUPPORTS2(nsXPConnect,nsIXPConnect,nsISupportsWeakReference) nsXPConnect* nsXPConnect::gSelf = nsnull; JSBool nsXPConnect::gOnceAliveNowDead = JS_FALSE; PRThread* nsXPConnect::gMainThread = nsnull; const char XPC_CONTEXT_STACK_CONTRACTID[] = "@mozilla.org/js/xpc/ContextStack;1"; const char XPC_RUNTIME_CONTRACTID[] = "@mozilla.org/js/xpc/RuntimeService;1"; const char XPC_EXCEPTION_CONTRACTID[] = "@mozilla.org/js/xpc/Exception;1"; const char XPC_CONSOLE_CONTRACTID[] = "@mozilla.org/consoleservice;1"; const char XPC_SCRIPT_ERROR_CONTRACTID[] = "@mozilla.org/scripterror;1"; const char XPC_ID_CONTRACTID[] = "@mozilla.org/js/xpc/ID;1"; const char XPC_XPCONNECT_CONTRACTID[] = "@mozilla.org/js/xpc/XPConnect;1"; /***************************************************************************/ nsXPConnect::nsXPConnect() : mRuntime(nsnull), mInterfaceInfoManager(nsnull), mContextStack(nsnull), mDefaultSecurityManager(nsnull), mDefaultSecurityManagerFlags(0), mShuttingDown(JS_FALSE) { // Ignore the result. If the runtime service is not ready to rumble // then we'll set this up later as needed. CreateRuntime(); nsCOMPtr iim = dont_AddRef(XPTI_GetInterfaceInfoManager()); CallQueryInterface(iim, &mInterfaceInfoManager); nsServiceManager::GetService(XPC_CONTEXT_STACK_CONTRACTID, NS_GET_IID(nsIThreadJSContextStack), (nsISupports **)&mContextStack); #ifdef XPC_TOOLS_SUPPORT { char* filename = PR_GetEnv("MOZILLA_JS_PROFILER_OUTPUT"); if(filename && *filename) { mProfilerOutputFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); if(mProfilerOutputFile && NS_SUCCEEDED(mProfilerOutputFile->InitWithNativePath(nsDependentCString(filename)))) { mProfiler = do_GetService(XPCTOOLS_PROFILER_CONTRACTID); if(mProfiler) { if(NS_SUCCEEDED(mProfiler->Start())) { #ifdef DEBUG printf("***** profiling JavaScript. Output to: %s\n", filename); #endif } } } } } #endif } nsXPConnect::~nsXPConnect() { // XXX It would be nice if we could get away with doing a GC here and also // calling Release on the natives no longer reachable via XPConnect. As // noted all over the place, this makes bad things happen since shutdown is // an unstable time for so many modules who have not planned well for it. mShuttingDown = JS_TRUE; { // scoped callcontext XPCCallContext ccx(NATIVE_CALLER); if(ccx.IsValid()) { XPCWrappedNativeScope::SystemIsBeingShutDown(ccx); if(mRuntime) mRuntime->SystemIsBeingShutDown(&ccx); } } NS_IF_RELEASE(mInterfaceInfoManager); NS_IF_RELEASE(mContextStack); NS_IF_RELEASE(mDefaultSecurityManager); // Unfortunately calling CleanupAllThreads before the stuff above // (esp. SystemIsBeingShutDown) causes too many bad things to happen // as the Release calls propagate. See the comment in this function in // revision 1.35 of this file. // // I filed a bug on xpcom regarding the bad things that happen // if people try to create components during shutdown. // http://bugzilla.mozilla.org/show_bug.cgi?id=37058 // // Also, we just plain need the context stack for at least the current // thread to be in place. Unfortunately, this will leak stuff on the // stacks' safeJSContexts. But, this is a shutdown leak only. XPCPerThreadData::CleanupAllThreads(); // shutdown the logging system XPC_LOG_FINISH(); delete mRuntime; gSelf = nsnull; gOnceAliveNowDead = JS_TRUE; } // static nsXPConnect* nsXPConnect::GetXPConnect() { if(!gSelf) { if(gOnceAliveNowDead) return nsnull; gSelf = new nsXPConnect(); if(!gSelf) return nsnull; if(!gSelf->mInterfaceInfoManager || !gSelf->mContextStack) { // ctor failed to create an acceptable instance delete gSelf; gSelf = nsnull; } else { // Initial extra ref to keep the singleton alive // balanced by explicit call to ReleaseXPConnectSingleton() NS_ADDREF(gSelf); } } return gSelf; } // In order to enable this jsgc heap dumping you need to compile // _both_ js/src/jsgc.c and this file with 'GC_MARK_DEBUG' #defined. // Normally this is done by adding -DGC_MARK_DEBUG to the appropriate // defines lists in the makefiles. #ifdef GC_MARK_DEBUG extern "C" JS_FRIEND_DATA(FILE *) js_DumpGCHeap; #endif // static nsXPConnect* nsXPConnect::GetSingleton() { nsXPConnect* xpc = nsXPConnect::GetXPConnect(); NS_IF_ADDREF(xpc); return xpc; } // static void nsXPConnect::ReleaseXPConnectSingleton() { nsXPConnect* xpc = gSelf; if(xpc) { #ifdef XPC_TOOLS_SUPPORT if(xpc->mProfiler) { xpc->mProfiler->Stop(); xpc->mProfiler->WriteResults(xpc->mProfilerOutputFile); } #endif #ifdef GC_MARK_DEBUG // force a dump of the JavaScript gc heap if JS is still alive XPCCallContext ccx(NATIVE_CALLER); if(ccx.IsValid()) { FILE* oldFileHandle = js_DumpGCHeap; js_DumpGCHeap = stdout; JS_GC(ccx); js_DumpGCHeap = oldFileHandle; } #endif #ifdef XPC_DUMP_AT_SHUTDOWN // NOTE: to see really interesting stuff turn on the prlog stuff. // See the comment at the top of xpclog.h to see how to do that. xpc->DebugDump(7); #endif nsrefcnt cnt; NS_RELEASE2(xpc, cnt); #ifdef XPC_DUMP_AT_SHUTDOWN if(0 != cnt) printf("*** dangling reference to nsXPConnect: refcnt=%d\n", cnt); else printf("+++ XPConnect had no dangling references.\n"); #endif } } // static nsresult nsXPConnect::GetInterfaceInfoManager(nsIInterfaceInfoSuperManager** iim, nsXPConnect* xpc /*= nsnull*/) { if(!xpc && !(xpc = GetXPConnect())) return NS_ERROR_FAILURE; *iim = xpc->mInterfaceInfoManager; NS_IF_ADDREF(*iim); return NS_OK; } // static nsresult nsXPConnect::GetContextStack(nsIThreadJSContextStack** stack, nsXPConnect* xpc /*= nsnull*/) { nsIThreadJSContextStack* temp; if(!xpc && !(xpc = GetXPConnect())) return NS_ERROR_FAILURE; *stack = temp = xpc->mContextStack; NS_IF_ADDREF(temp); return NS_OK; } // static XPCJSRuntime* nsXPConnect::GetRuntime(nsXPConnect* xpc /*= nsnull*/) { if(!xpc && !(xpc = GetXPConnect())) return nsnull; return xpc->EnsureRuntime() ? xpc->mRuntime : nsnull; } // static nsIJSRuntimeService* nsXPConnect::GetJSRuntimeService(nsXPConnect* xpc /* = nsnull */) { XPCJSRuntime* rt = GetRuntime(xpc); return rt ? rt->GetJSRuntimeService() : nsnull; } // static XPCContext* nsXPConnect::GetContext(JSContext* cx, nsXPConnect* xpc /*= nsnull*/) { NS_PRECONDITION(cx,"bad param"); XPCJSRuntime* rt = GetRuntime(xpc); if(!rt) return nsnull; if(rt->GetJSRuntime() != JS_GetRuntime(cx)) { NS_WARNING("XPConnect was passed aJSContext from a foreign JSRuntime!"); return nsnull; } return rt->GetXPCContext(cx); } // static JSBool nsXPConnect::IsISupportsDescendant(nsIInterfaceInfo* info) { PRBool found = PR_FALSE; if(info) info->HasAncestor(&NS_GET_IID(nsISupports), &found); return found; } JSBool nsXPConnect::CreateRuntime() { NS_ASSERTION(!mRuntime,"CreateRuntime called but mRuntime already init'd"); nsresult rv; nsCOMPtr rtsvc = do_GetService(XPC_RUNTIME_CONTRACTID, &rv); if(NS_SUCCEEDED(rv) && rtsvc) { mRuntime = XPCJSRuntime::newXPCJSRuntime(this, rtsvc); } return nsnull != mRuntime; } // static PRThread* nsXPConnect::FindMainThread() { nsCOMPtr t; nsresult rv; rv = nsIThread::GetMainThread(getter_AddRefs(t)); NS_ASSERTION(NS_SUCCEEDED(rv) && t, "bad"); rv = t->GetPRThread(&gMainThread); NS_ASSERTION(NS_SUCCEEDED(rv) && gMainThread, "bad"); return gMainThread; } /***************************************************************************/ typedef PRBool (*InfoTester)(nsIInterfaceInfoManager* manager, const void* data, nsIInterfaceInfo** info); static PRBool IIDTester(nsIInterfaceInfoManager* manager, const void* data, nsIInterfaceInfo** info) { return NS_SUCCEEDED(manager->GetInfoForIID((const nsIID *) data, info)) && *info; } static PRBool NameTester(nsIInterfaceInfoManager* manager, const void* data, nsIInterfaceInfo** info) { return NS_SUCCEEDED(manager->GetInfoForName((const char *) data, info)) && *info; } static nsresult FindInfo(InfoTester tester, const void* data, nsIInterfaceInfoSuperManager* iism, nsIInterfaceInfo** info) { if(tester(iism, data, info)) return NS_OK; // If not found, then let's ask additional managers. PRBool yes; nsCOMPtr list; if(NS_SUCCEEDED(iism->HasAdditionalManagers(&yes)) && yes && NS_SUCCEEDED(iism->EnumerateAdditionalManagers(getter_AddRefs(list))) && list) { PRBool more; nsCOMPtr current; while(NS_SUCCEEDED(list->HasMoreElements(&more)) && more && NS_SUCCEEDED(list->GetNext(getter_AddRefs(current))) && current) { if(tester(current, data, info)) return NS_OK; } } return NS_ERROR_NO_INTERFACE; } nsresult nsXPConnect::GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info) { return FindInfo(IIDTester, aIID, mInterfaceInfoManager, info); } nsresult nsXPConnect::GetInfoForName(const char * name, nsIInterfaceInfo** info) { return FindInfo(NameTester, name, mInterfaceInfoManager, info); } /***************************************************************************/ /***************************************************************************/ // nsIXPConnect interface methods... inline nsresult UnexpectedFailure(nsresult rv) { NS_ERROR("This is not supposed to fail!"); return rv; } /* void initClasses (in JSContextPtr aJSContext, in JSObjectPtr aGlobalJSObj); */ NS_IMETHODIMP nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj) { NS_ASSERTION(aJSContext, "bad param"); NS_ASSERTION(aGlobalJSObj, "bad param"); XPCCallContext ccx(NATIVE_CALLER, aJSContext); if(!ccx.IsValid()) return UnexpectedFailure(NS_ERROR_FAILURE); if(!xpc_InitJSxIDClassObjects()) return UnexpectedFailure(NS_ERROR_FAILURE); if(!xpc_InitWrappedNativeJSOps()) return UnexpectedFailure(NS_ERROR_FAILURE); XPCWrappedNativeScope* scope = XPCWrappedNativeScope::GetNewOrUsed(ccx, aGlobalJSObj); if(!scope) return UnexpectedFailure(NS_ERROR_FAILURE); scope->RemoveWrappedNativeProtos(); if(!nsXPCComponents::AttachNewComponentsObject(ccx, scope, aGlobalJSObj)) return UnexpectedFailure(NS_ERROR_FAILURE); #ifdef XPC_IDISPATCH_SUPPORT // Initialize any properties IDispatch needs on the global object XPCIDispatchExtension::Initialize(ccx, aGlobalJSObj); #endif return NS_OK; } JS_STATIC_DLL_CALLBACK(JSBool) TempGlobalResolve(JSContext *aJSContext, JSObject *obj, jsval id) { JSBool resolved; return JS_ResolveStandardClass(aJSContext, obj, id, &resolved); } static JSClass xpcTempGlobalClass = { "xpcTempGlobalClass", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, TempGlobalResolve, JS_ConvertStub, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS }; /* nsIXPConnectJSObjectHolder initClassesWithNewWrappedGlobal (in JSContextPtr aJSContext, in nsISupports aCOMObj, in nsIIDRef aIID, in PRBool aCallJS_InitStandardClasses); */ NS_IMETHODIMP nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext, nsISupports *aCOMObj, const nsIID & aIID, PRBool aCallJS_InitStandardClasses, nsIXPConnectJSObjectHolder **_retval) { NS_ASSERTION(aJSContext, "bad param"); NS_ASSERTION(aCOMObj, "bad param"); NS_ASSERTION(_retval, "bad param"); // XXX This is not pretty. We make a temporary global object and // init it with all the Components object junk just so we have a // parent with an xpc scope to use when wrapping the object that will // become the 'real' global. XPCCallContext ccx(NATIVE_CALLER, aJSContext); JSObject* tempGlobal = JS_NewObject(aJSContext, &xpcTempGlobalClass, nsnull, nsnull); if(!tempGlobal || !JS_SetParent(aJSContext, tempGlobal, nsnull) || !JS_SetPrototype(aJSContext, tempGlobal, nsnull)) return UnexpectedFailure(NS_ERROR_FAILURE); if(NS_FAILED(InitClasses(aJSContext, tempGlobal))) return UnexpectedFailure(NS_ERROR_FAILURE); nsCOMPtr holder; if(NS_FAILED(WrapNative(aJSContext, tempGlobal, aCOMObj, aIID, getter_AddRefs(holder))) || !holder) return UnexpectedFailure(NS_ERROR_FAILURE); JSObject* globalJSObj; if(NS_FAILED(holder->GetJSObject(&globalJSObj)) || !globalJSObj) return UnexpectedFailure(NS_ERROR_FAILURE); // voodoo to fixup scoping and parenting... JS_SetParent(aJSContext, globalJSObj, nsnull); JSObject* oldGlobal = JS_GetGlobalObject(aJSContext); if(!oldGlobal || oldGlobal == tempGlobal) JS_SetGlobalObject(aJSContext, globalJSObj); if(aCallJS_InitStandardClasses && !JS_InitStandardClasses(aJSContext, globalJSObj)) return UnexpectedFailure(NS_ERROR_FAILURE); XPCWrappedNative* wrapper = NS_REINTERPRET_CAST(XPCWrappedNative*, holder.get()); XPCWrappedNativeScope* scope = wrapper->GetScope(); if(!scope) return UnexpectedFailure(NS_ERROR_FAILURE); NS_ASSERTION(scope->GetGlobalJSObject() == tempGlobal, "stealing scope!"); scope->SetGlobal(ccx, globalJSObj); JSObject* protoJSObject = wrapper->HasProto() ? wrapper->GetProto()->GetJSProtoObject() : globalJSObj; if(protoJSObject) { if(protoJSObject != globalJSObj) JS_SetParent(aJSContext, protoJSObject, globalJSObj); JS_SetPrototype(aJSContext, protoJSObject, scope->GetPrototypeJSObject()); } if(!nsXPCComponents::AttachNewComponentsObject(ccx, scope, globalJSObj)) return UnexpectedFailure(NS_ERROR_FAILURE); NS_ADDREF(*_retval = holder); return NS_OK; } /* nsIXPConnectJSObjectHolder wrapNative (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDRef aIID); */ NS_IMETHODIMP nsXPConnect::WrapNative(JSContext * aJSContext, JSObject * aScope, nsISupports *aCOMObj, const nsIID & aIID, nsIXPConnectJSObjectHolder **_retval) { NS_ASSERTION(aJSContext, "bad param"); NS_ASSERTION(aScope, "bad param"); NS_ASSERTION(aCOMObj, "bad param"); NS_ASSERTION(_retval, "bad param"); *_retval = nsnull; XPCCallContext ccx(NATIVE_CALLER, aJSContext); if(!ccx.IsValid()) return UnexpectedFailure(NS_ERROR_FAILURE); nsresult rv; if(!XPCConvert::NativeInterface2JSObject(ccx, _retval, aCOMObj, &aIID, aScope, &rv)) return rv; return NS_OK; } /* void wrapJS (in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */ NS_IMETHODIMP nsXPConnect::WrapJS(JSContext * aJSContext, JSObject * aJSObj, const nsIID & aIID, void * *result) { NS_ASSERTION(aJSContext, "bad param"); NS_ASSERTION(aJSObj, "bad param"); NS_ASSERTION(result, "bad param"); *result = nsnull; XPCCallContext ccx(NATIVE_CALLER, aJSContext); if(!ccx.IsValid()) return UnexpectedFailure(NS_ERROR_FAILURE); nsresult rv; if(!XPCConvert::JSObject2NativeInterface(ccx, result, aJSObj, &aIID, nsnull, &rv)) return rv; return NS_OK; } /* void wrapJSAggregatedToNative (in nsISupports aOuter, in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */ NS_IMETHODIMP nsXPConnect::WrapJSAggregatedToNative(nsISupports *aOuter, JSContext * aJSContext, JSObject * aJSObj, const nsIID & aIID, void * *result) { NS_ASSERTION(aOuter, "bad param"); NS_ASSERTION(aJSContext, "bad param"); NS_ASSERTION(aJSObj, "bad param"); NS_ASSERTION(result, "bad param"); *result = nsnull; XPCCallContext ccx(NATIVE_CALLER, aJSContext); if(!ccx.IsValid()) return UnexpectedFailure(NS_ERROR_FAILURE); nsresult rv; if(!XPCConvert::JSObject2NativeInterface(ccx, result, aJSObj, &aIID, aOuter, &rv)) return rv; return NS_OK; } /* nsIXPConnectWrappedNative getWrappedNativeOfJSObject (in JSContextPtr aJSContext, in JSObjectPtr aJSObj); */ NS_IMETHODIMP nsXPConnect::GetWrappedNativeOfJSObject(JSContext * aJSContext, JSObject * aJSObj, nsIXPConnectWrappedNative **_retval) { NS_ASSERTION(aJSContext, "bad param"); NS_ASSERTION(aJSObj, "bad param"); NS_ASSERTION(_retval, "bad param"); XPCCallContext ccx(NATIVE_CALLER, aJSContext); if(!ccx.IsValid()) return UnexpectedFailure(NS_ERROR_FAILURE); nsIXPConnectWrappedNative* wrapper = XPCWrappedNative::GetWrappedNativeOfJSObject(aJSContext, aJSObj); if(wrapper) { NS_ADDREF(wrapper); *_retval = wrapper; return NS_OK; } // else... *_retval = nsnull; return NS_ERROR_FAILURE; } /* nsIXPConnectWrappedNative getWrappedNativeOfNativeObject (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDRef aIID); */ NS_IMETHODIMP nsXPConnect::GetWrappedNativeOfNativeObject(JSContext * aJSContext, JSObject * aScope, nsISupports *aCOMObj, const nsIID & aIID, nsIXPConnectWrappedNative **_retval) { NS_ASSERTION(aJSContext, "bad param"); NS_ASSERTION(aScope, "bad param"); NS_ASSERTION(aCOMObj, "bad param"); NS_ASSERTION(_retval, "bad param"); *_retval = nsnull; XPCCallContext ccx(NATIVE_CALLER, aJSContext); if(!ccx.IsValid()) return UnexpectedFailure(NS_ERROR_FAILURE); XPCWrappedNativeScope* scope = XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope); if(!scope) return UnexpectedFailure(NS_ERROR_FAILURE); AutoMarkingNativeInterfacePtr iface(ccx); iface = XPCNativeInterface::GetNewOrUsed(ccx, &aIID); if(!iface) return NS_ERROR_FAILURE; XPCWrappedNative* wrapper; nsresult rv = XPCWrappedNative::GetUsedOnly(ccx, aCOMObj, scope, iface, &wrapper); if(NS_FAILED(rv)) return NS_ERROR_FAILURE; *_retval = NS_STATIC_CAST(nsIXPConnectWrappedNative*, wrapper); return NS_OK; } /* nsIXPConnectJSObjectHolder reparentWrappedNativeIfFound (in JSContextPtr aJSContext, in JSObjectPtr aScope, in JSObjectPtr aNewParent, in nsISupports aCOMObj); */ NS_IMETHODIMP nsXPConnect::ReparentWrappedNativeIfFound(JSContext * aJSContext, JSObject * aScope, JSObject * aNewParent, nsISupports *aCOMObj, nsIXPConnectJSObjectHolder **_retval) { XPCCallContext ccx(NATIVE_CALLER, aJSContext); if(!ccx.IsValid()) return UnexpectedFailure(NS_ERROR_FAILURE); XPCWrappedNativeScope* scope = XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope); if(!scope) return UnexpectedFailure(NS_ERROR_FAILURE); XPCWrappedNativeScope* scope2 = XPCWrappedNativeScope::FindInJSObjectScope(ccx, aNewParent); if(!scope2) return UnexpectedFailure(NS_ERROR_FAILURE); return XPCWrappedNative:: ReparentWrapperIfFound(ccx, scope, scope2, aNewParent, aCOMObj, (XPCWrappedNative**) _retval); } /* void setSecurityManagerForJSContext (in JSContextPtr aJSContext, in nsIXPCSecurityManager aManager, in PRUint16 flags); */ NS_IMETHODIMP nsXPConnect::SetSecurityManagerForJSContext(JSContext * aJSContext, nsIXPCSecurityManager *aManager, PRUint16 flags) { NS_ASSERTION(aJSContext, "bad param"); XPCCallContext ccx(NATIVE_CALLER, aJSContext); if(!ccx.IsValid()) return UnexpectedFailure(NS_ERROR_FAILURE); XPCContext* xpcc = ccx.GetXPCContext(); NS_IF_ADDREF(aManager); nsIXPCSecurityManager* oldManager = xpcc->GetSecurityManager(); NS_IF_RELEASE(oldManager); xpcc->SetSecurityManager(aManager); xpcc->SetSecurityManagerFlags(flags); return NS_OK; } /* void getSecurityManagerForJSContext (in JSContextPtr aJSContext, out nsIXPCSecurityManager aManager, out PRUint16 flags); */ NS_IMETHODIMP nsXPConnect::GetSecurityManagerForJSContext(JSContext * aJSContext, nsIXPCSecurityManager **aManager, PRUint16 *flags) { NS_ASSERTION(aJSContext, "bad param"); NS_ASSERTION(aManager, "bad param"); NS_ASSERTION(flags, "bad param"); XPCCallContext ccx(NATIVE_CALLER, aJSContext); if(!ccx.IsValid()) return UnexpectedFailure(NS_ERROR_FAILURE); XPCContext* xpcc = ccx.GetXPCContext(); nsIXPCSecurityManager* manager = xpcc->GetSecurityManager(); NS_IF_ADDREF(manager); *aManager = manager; *flags = xpcc->GetSecurityManagerFlags(); return NS_OK; } /* void setDefaultSecurityManager (in nsIXPCSecurityManager aManager, in PRUint16 flags); */ NS_IMETHODIMP nsXPConnect::SetDefaultSecurityManager(nsIXPCSecurityManager *aManager, PRUint16 flags) { NS_IF_ADDREF(aManager); NS_IF_RELEASE(mDefaultSecurityManager); mDefaultSecurityManager = aManager; mDefaultSecurityManagerFlags = flags; return NS_OK; } /* void getDefaultSecurityManager (out nsIXPCSecurityManager aManager, out PRUint16 flags); */ NS_IMETHODIMP nsXPConnect::GetDefaultSecurityManager(nsIXPCSecurityManager **aManager, PRUint16 *flags) { NS_ASSERTION(aManager, "bad param"); NS_ASSERTION(flags, "bad param"); NS_IF_ADDREF(mDefaultSecurityManager); *aManager = mDefaultSecurityManager; *flags = mDefaultSecurityManagerFlags; return NS_OK; } /* nsIStackFrame createStackFrameLocation (in PRUint32 aLanguage, in string aFilename, in string aFunctionName, in PRInt32 aLineNumber, in nsIStackFrame aCaller); */ NS_IMETHODIMP nsXPConnect::CreateStackFrameLocation(PRUint32 aLanguage, const char *aFilename, const char *aFunctionName, PRInt32 aLineNumber, nsIStackFrame *aCaller, nsIStackFrame **_retval) { NS_ASSERTION(_retval, "bad param"); return XPCJSStack::CreateStackFrameLocation(aLanguage, aFilename, aFunctionName, aLineNumber, aCaller, _retval); } /* readonly attribute nsIStackFrame CurrentJSStack; */ NS_IMETHODIMP nsXPConnect::GetCurrentJSStack(nsIStackFrame * *aCurrentJSStack) { NS_ASSERTION(aCurrentJSStack, "bad param"); *aCurrentJSStack = nsnull; JSContext* cx; // is there a current context available? if(mContextStack && NS_SUCCEEDED(mContextStack->Peek(&cx)) && cx) { nsCOMPtr stack; XPCJSStack::CreateStack(cx, getter_AddRefs(stack)); if(stack) { // peel off native frames... PRUint32 language; nsCOMPtr caller; while(stack && NS_SUCCEEDED(stack->GetLanguage(&language)) && language != nsIProgrammingLanguage::JAVASCRIPT && NS_SUCCEEDED(stack->GetCaller(getter_AddRefs(caller))) && caller) { stack = caller; } NS_IF_ADDREF(*aCurrentJSStack = stack); } } return NS_OK; } /* readonly attribute nsIXPCNativeCallContext CurrentNativeCallContext; */ NS_IMETHODIMP nsXPConnect::GetCurrentNativeCallContext(nsIXPCNativeCallContext * *aCurrentNativeCallContext) { NS_ASSERTION(aCurrentNativeCallContext, "bad param"); XPCPerThreadData* data = XPCPerThreadData::GetData(); if(data) { nsIXPCNativeCallContext* temp = data->GetCallContext(); NS_IF_ADDREF(temp); *aCurrentNativeCallContext = temp; return NS_OK; } //else... *aCurrentNativeCallContext = nsnull; return UnexpectedFailure(NS_ERROR_FAILURE); } /* attribute nsIException PendingException; */ NS_IMETHODIMP nsXPConnect::GetPendingException(nsIException * *aPendingException) { NS_ASSERTION(aPendingException, "bad param"); XPCPerThreadData* data = XPCPerThreadData::GetData(); if(!data) { *aPendingException = nsnull; return UnexpectedFailure(NS_ERROR_FAILURE); } return data->GetException(aPendingException); } NS_IMETHODIMP nsXPConnect::SetPendingException(nsIException * aPendingException) { XPCPerThreadData* data = XPCPerThreadData::GetData(); if(!data) return UnexpectedFailure(NS_ERROR_FAILURE); data->SetException(aPendingException); return NS_OK; } /* void syncJSContexts (); */ NS_IMETHODIMP nsXPConnect::SyncJSContexts(void) { XPCJSRuntime* rt = GetRuntime(this); if(rt) rt->SyncXPCContextList(); return NS_OK; } /* nsIXPCFunctionThisTranslator setFunctionThisTranslator (in nsIIDRef aIID, in nsIXPCFunctionThisTranslator aTranslator); */ NS_IMETHODIMP nsXPConnect::SetFunctionThisTranslator(const nsIID & aIID, nsIXPCFunctionThisTranslator *aTranslator, nsIXPCFunctionThisTranslator **_retval) { XPCJSRuntime* rt = GetRuntime(this); if(!rt) return NS_ERROR_UNEXPECTED; nsIXPCFunctionThisTranslator* old; IID2ThisTranslatorMap* map = rt->GetThisTranslatorMap(); { XPCAutoLock lock(rt->GetMapLock()); // scoped lock if(_retval) { old = map->Find(aIID); NS_IF_ADDREF(old); *_retval = old; } map->Add(aIID, aTranslator); } return NS_OK; } /* nsIXPCFunctionThisTranslator getFunctionThisTranslator (in nsIIDRef aIID); */ NS_IMETHODIMP nsXPConnect::GetFunctionThisTranslator(const nsIID & aIID, nsIXPCFunctionThisTranslator **_retval) { XPCJSRuntime* rt = GetRuntime(this); if(!rt) return NS_ERROR_UNEXPECTED; nsIXPCFunctionThisTranslator* old; IID2ThisTranslatorMap* map = rt->GetThisTranslatorMap(); { XPCAutoLock lock(rt->GetMapLock()); // scoped lock old = map->Find(aIID); NS_IF_ADDREF(old); *_retval = old; } return NS_OK; } /* void setSafeJSContextForCurrentThread (in JSContextPtr cx); */ NS_IMETHODIMP nsXPConnect::SetSafeJSContextForCurrentThread(JSContext * cx) { XPCCallContext ccx(NATIVE_CALLER); if(!ccx.IsValid()) return UnexpectedFailure(NS_ERROR_FAILURE); return ccx.GetThreadData()->GetJSContextStack()->SetSafeJSContext(cx); } /* void clearAllWrappedNativeSecurityPolicies (); */ NS_IMETHODIMP nsXPConnect::ClearAllWrappedNativeSecurityPolicies() { XPCCallContext ccx(NATIVE_CALLER); if(!ccx.IsValid()) return UnexpectedFailure(NS_ERROR_FAILURE); return XPCWrappedNativeScope::ClearAllWrappedNativeSecurityPolicies(ccx); } /* nsIXPConnectJSObjectHolder getWrappedNativePrototype (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsIClassInfo aClassInfo); */ NS_IMETHODIMP nsXPConnect::GetWrappedNativePrototype(JSContext * aJSContext, JSObject * aScope, nsIClassInfo *aClassInfo, nsIXPConnectJSObjectHolder **_retval) { XPCCallContext ccx(NATIVE_CALLER, aJSContext); if(!ccx.IsValid()) return UnexpectedFailure(NS_ERROR_FAILURE); XPCWrappedNativeScope* scope = XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope); if(!scope) return UnexpectedFailure(NS_ERROR_FAILURE); XPCNativeScriptableCreateInfo sciProto; XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, &sciProto); AutoMarkingWrappedNativeProtoPtr proto(ccx); proto = XPCWrappedNativeProto::GetNewOrUsed(ccx, scope, aClassInfo, &sciProto, JS_FALSE); if(!proto) return UnexpectedFailure(NS_ERROR_FAILURE); nsIXPConnectJSObjectHolder* holder; *_retval = holder = XPCJSObjectHolder::newHolder(ccx, proto->GetJSProtoObject()); if(!holder) return UnexpectedFailure(NS_ERROR_FAILURE); NS_ADDREF(holder); return NS_OK; } /* attribute PRBool collectGarbageOnMainThreadOnly; */ NS_IMETHODIMP nsXPConnect::GetCollectGarbageOnMainThreadOnly(PRBool *aCollectGarbageOnMainThreadOnly) { XPCJSRuntime* rt = GetRuntime(); if(!rt) return UnexpectedFailure(NS_ERROR_FAILURE); *aCollectGarbageOnMainThreadOnly = rt->GetMainThreadOnlyGC(); return NS_OK; } NS_IMETHODIMP nsXPConnect::SetCollectGarbageOnMainThreadOnly(PRBool aCollectGarbageOnMainThreadOnly) { XPCJSRuntime* rt = GetRuntime(); if(!rt) return UnexpectedFailure(NS_ERROR_FAILURE); rt->SetMainThreadOnlyGC(aCollectGarbageOnMainThreadOnly); return NS_OK; } /* attribute PRBool deferReleasesUntilAfterGarbageCollection; */ NS_IMETHODIMP nsXPConnect::GetDeferReleasesUntilAfterGarbageCollection(PRBool *aDeferReleasesUntilAfterGarbageCollection) { XPCJSRuntime* rt = GetRuntime(); if(!rt) return UnexpectedFailure(NS_ERROR_FAILURE); *aDeferReleasesUntilAfterGarbageCollection = rt->GetDeferReleases(); return NS_OK; } NS_IMETHODIMP nsXPConnect::SetDeferReleasesUntilAfterGarbageCollection(PRBool aDeferReleasesUntilAfterGarbageCollection) { XPCJSRuntime* rt = GetRuntime(); if(!rt) return UnexpectedFailure(NS_ERROR_FAILURE); rt->SetDeferReleases(aDeferReleasesUntilAfterGarbageCollection); return NS_OK; } /* void releaseJSContext (in JSContextPtr aJSContext, in PRBool noGC); */ NS_IMETHODIMP nsXPConnect::ReleaseJSContext(JSContext * aJSContext, PRBool noGC) { NS_ASSERTION(aJSContext, "bad param"); XPCPerThreadData* tls = XPCPerThreadData::GetData(); if(tls) { XPCCallContext* ccx = nsnull; for(XPCCallContext* cur = tls->GetCallContext(); cur; cur = cur->GetPrevCallContext()) { if(cur->GetJSContext() == aJSContext) { ccx = cur; // Keep looping to find the deepest matching call context. } } if(ccx) { #ifdef DEBUG_xpc_hacker printf("!xpc - deferring destruction of JSContext @ %0x\n", aJSContext); #endif ccx->SetDestroyJSContextInDestructor(JS_TRUE); JS_ClearNewbornRoots(aJSContext); return NS_OK; } // else continue on and synchronously destroy the JSContext ... NS_ASSERTION(!tls->GetJSContextStack() || !tls->GetJSContextStack()-> DEBUG_StackHasJSContext(aJSContext), "JSContext still in threadjscontextstack!"); } if(noGC) JS_DestroyContextNoGC(aJSContext); else JS_DestroyContext(aJSContext); SyncJSContexts(); return NS_OK; } /* void debugDump (in short depth); */ NS_IMETHODIMP nsXPConnect::DebugDump(PRInt16 depth) { #ifdef DEBUG depth-- ; XPC_LOG_ALWAYS(("nsXPConnect @ %x with mRefCnt = %d", this, mRefCnt.get())); XPC_LOG_INDENT(); XPC_LOG_ALWAYS(("gSelf @ %x", gSelf)); XPC_LOG_ALWAYS(("gOnceAliveNowDead is %d", (int)gOnceAliveNowDead)); XPC_LOG_ALWAYS(("mDefaultSecurityManager @ %x", mDefaultSecurityManager)); XPC_LOG_ALWAYS(("mDefaultSecurityManagerFlags of %x", mDefaultSecurityManagerFlags)); XPC_LOG_ALWAYS(("mInterfaceInfoManager @ %x", mInterfaceInfoManager)); XPC_LOG_ALWAYS(("mContextStack @ %x", mContextStack)); if(mRuntime) { if(depth) mRuntime->DebugDump(depth); else XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", mRuntime)); } else XPC_LOG_ALWAYS(("mRuntime is null")); XPCWrappedNativeScope::DebugDumpAllScopes(depth); XPC_LOG_OUTDENT(); #endif return NS_OK; } /* void debugDumpObject (in nsISupports aCOMObj, in short depth); */ NS_IMETHODIMP nsXPConnect::DebugDumpObject(nsISupports *p, PRInt16 depth) { #ifdef DEBUG if(!depth) return NS_OK; if(!p) { XPC_LOG_ALWAYS(("*** Cound not dump object with NULL address")); return NS_OK; } nsIXPConnect* xpc; nsIXPCWrappedJSClass* wjsc; nsIXPConnectWrappedNative* wn; nsIXPConnectWrappedJS* wjs; if(NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnect), (void**)&xpc))) { XPC_LOG_ALWAYS(("Dumping a nsIXPConnect...")); xpc->DebugDump(depth); NS_RELEASE(xpc); } else if(NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPCWrappedJSClass), (void**)&wjsc))) { XPC_LOG_ALWAYS(("Dumping a nsIXPCWrappedJSClass...")); wjsc->DebugDump(depth); NS_RELEASE(wjsc); } else if(NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedNative), (void**)&wn))) { XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedNative...")); wn->DebugDump(depth); NS_RELEASE(wn); } else if(NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedJS), (void**)&wjs))) { XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedJS...")); wjs->DebugDump(depth); NS_RELEASE(wjs); } else XPC_LOG_ALWAYS(("*** Could not dump the nsISupports @ %x", p)); #endif return NS_OK; } /* void debugDumpJSStack (in PRBool showArgs, in PRBool showLocals, in PRBool showThisProps); */ NS_IMETHODIMP nsXPConnect::DebugDumpJSStack(PRBool showArgs, PRBool showLocals, PRBool showThisProps) { #ifdef DEBUG JSContext* cx; nsresult rv; nsCOMPtr stack = do_GetService(XPC_CONTEXT_STACK_CONTRACTID, &rv); if(NS_FAILED(rv) || !stack) printf("failed to get nsIThreadJSContextStack service!\n"); else if(NS_FAILED(stack->Peek(&cx))) printf("failed to peek into nsIThreadJSContextStack service!\n"); else if(!cx) printf("there is no JSContext on the nsIThreadJSContextStack!\n"); else xpc_DumpJSStack(cx, showArgs, showLocals, showThisProps); #endif return NS_OK; } /* void debugDumpEvalInJSStackFrame (in PRUint32 aFrameNumber, in string aSourceText); */ NS_IMETHODIMP nsXPConnect::DebugDumpEvalInJSStackFrame(PRUint32 aFrameNumber, const char *aSourceText) { #ifdef DEBUG JSContext* cx; nsresult rv; nsCOMPtr stack = do_GetService(XPC_CONTEXT_STACK_CONTRACTID, &rv); if(NS_FAILED(rv) || !stack) printf("failed to get nsIThreadJSContextStack service!\n"); else if(NS_FAILED(stack->Peek(&cx))) printf("failed to peek into nsIThreadJSContextStack service!\n"); else if(!cx) printf("there is no JSContext on the nsIThreadJSContextStack!\n"); else xpc_DumpEvalInJSStackFrame(cx, aFrameNumber, aSourceText); #endif return NS_OK; } #ifdef DEBUG /* These are here to be callable from a debugger */ JS_BEGIN_EXTERN_C void DumpJSStack() { nsresult rv; nsCOMPtr xpc(do_GetService(nsIXPConnect::GetCID(), &rv)); if(NS_SUCCEEDED(rv) && xpc) xpc->DebugDumpJSStack(PR_TRUE, PR_TRUE, PR_FALSE); else printf("failed to get XPConnect service!\n"); } void DumpJSEval(PRUint32 frameno, const char* text) { nsresult rv; nsCOMPtr xpc(do_GetService(nsIXPConnect::GetCID(), &rv)); if(NS_SUCCEEDED(rv) && xpc) xpc->DebugDumpEvalInJSStackFrame(frameno, text); else printf("failed to get XPConnect service!\n"); } void DumpJSObject(JSObject* obj) { xpc_DumpJSObject(obj); } JS_END_EXTERN_C #endif