js/xpconnect/src/nsXPConnect.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     7 /* High level class and public functions implementation. */
     9 #include "mozilla/Assertions.h"
    10 #include "mozilla/Base64.h"
    11 #include "mozilla/Likely.h"
    13 #include "xpcprivate.h"
    14 #include "XPCWrapper.h"
    15 #include "jsfriendapi.h"
    16 #include "js/OldDebugAPI.h"
    17 #include "nsJSEnvironment.h"
    18 #include "nsThreadUtils.h"
    19 #include "nsDOMJSUtils.h"
    21 #include "WrapperFactory.h"
    22 #include "AccessCheck.h"
    24 #ifdef MOZ_JSDEBUGGER
    25 #include "jsdIDebuggerService.h"
    26 #endif
    28 #include "XPCQuickStubs.h"
    30 #include "mozilla/dom/BindingUtils.h"
    31 #include "mozilla/dom/Exceptions.h"
    32 #include "mozilla/dom/PromiseBinding.h"
    33 #include "mozilla/dom/TextDecoderBinding.h"
    34 #include "mozilla/dom/TextEncoderBinding.h"
    35 #include "mozilla/dom/DOMErrorBinding.h"
    37 #include "nsDOMMutationObserver.h"
    38 #include "nsICycleCollectorListener.h"
    39 #include "nsThread.h"
    40 #include "mozilla/XPTInterfaceInfoManager.h"
    41 #include "nsIObjectInputStream.h"
    42 #include "nsIObjectOutputStream.h"
    44 using namespace mozilla;
    45 using namespace mozilla::dom;
    46 using namespace xpc;
    47 using namespace JS;
    49 NS_IMPL_ISUPPORTS(nsXPConnect,
    50                   nsIXPConnect,
    51                   nsISupportsWeakReference,
    52                   nsIThreadObserver,
    53                   nsIJSRuntimeService)
    55 nsXPConnect* nsXPConnect::gSelf = nullptr;
    56 bool         nsXPConnect::gOnceAliveNowDead = false;
    57 uint32_t     nsXPConnect::gReportAllJSExceptions = 0;
    59 bool         xpc::gDebugMode = false;
    60 bool         xpc::gDesiredDebugMode = false;
    62 // Global cache of the default script security manager (QI'd to
    63 // nsIScriptSecurityManager)
    64 nsIScriptSecurityManager *nsXPConnect::gScriptSecurityManager = nullptr;
    66 const char XPC_CONTEXT_STACK_CONTRACTID[] = "@mozilla.org/js/xpc/ContextStack;1";
    67 const char XPC_RUNTIME_CONTRACTID[]       = "@mozilla.org/js/xpc/RuntimeService;1";
    68 const char XPC_EXCEPTION_CONTRACTID[]     = "@mozilla.org/js/xpc/Exception;1";
    69 const char XPC_CONSOLE_CONTRACTID[]       = "@mozilla.org/consoleservice;1";
    70 const char XPC_SCRIPT_ERROR_CONTRACTID[]  = "@mozilla.org/scripterror;1";
    71 const char XPC_ID_CONTRACTID[]            = "@mozilla.org/js/xpc/ID;1";
    72 const char XPC_XPCONNECT_CONTRACTID[]     = "@mozilla.org/js/xpc/XPConnect;1";
    74 /***************************************************************************/
    76 nsXPConnect::nsXPConnect()
    77     :   mRuntime(nullptr),
    78         mShuttingDown(false),
    79         mEventDepth(0)
    80 {
    81     mRuntime = XPCJSRuntime::newXPCJSRuntime(this);
    83     char* reportableEnv = PR_GetEnv("MOZ_REPORT_ALL_JS_EXCEPTIONS");
    84     if (reportableEnv && *reportableEnv)
    85         gReportAllJSExceptions = 1;
    86 }
    88 nsXPConnect::~nsXPConnect()
    89 {
    90     mRuntime->DeleteSingletonScopes();
    91     mRuntime->DestroyJSContextStack();
    93     // In order to clean up everything properly, we need to GC twice: once now,
    94     // to clean anything that can go away on its own (like the Junk Scope, which
    95     // we unrooted above), and once after forcing a bunch of shutdown in
    96     // XPConnect, to clean the stuff we forcibly disconnected. The forced
    97     // shutdown code defaults to leaking in a number of situations, so we can't
    98     // get by with only the second GC. :-(
    99     JS_GC(mRuntime->Runtime());
   101     mShuttingDown = true;
   102     XPCWrappedNativeScope::SystemIsBeingShutDown();
   103     mRuntime->SystemIsBeingShutDown();
   105     // The above causes us to clean up a bunch of XPConnect data structures,
   106     // after which point we need to GC to clean everything up. We need to do
   107     // this before deleting the XPCJSRuntime, because doing so destroys the
   108     // maps that our finalize callback depends on.
   109     JS_GC(mRuntime->Runtime());
   111     mDefaultSecurityManager = nullptr;
   112     gScriptSecurityManager = nullptr;
   114     // shutdown the logging system
   115     XPC_LOG_FINISH();
   117     delete mRuntime;
   119     gSelf = nullptr;
   120     gOnceAliveNowDead = true;
   121 }
   123 // static
   124 void
   125 nsXPConnect::InitStatics()
   126 {
   127     gSelf = new nsXPConnect();
   128     gOnceAliveNowDead = false;
   129     if (!gSelf->mRuntime) {
   130         NS_RUNTIMEABORT("Couldn't create XPCJSRuntime.");
   131     }
   133     // Initial extra ref to keep the singleton alive
   134     // balanced by explicit call to ReleaseXPConnectSingleton()
   135     NS_ADDREF(gSelf);
   137     // Set XPConnect as the main thread observer.
   138     if (NS_FAILED(nsThread::SetMainThreadObserver(gSelf))) {
   139         MOZ_CRASH();
   140     }
   141 }
   143 nsXPConnect*
   144 nsXPConnect::GetSingleton()
   145 {
   146     nsXPConnect* xpc = nsXPConnect::XPConnect();
   147     NS_IF_ADDREF(xpc);
   148     return xpc;
   149 }
   151 // static
   152 void
   153 nsXPConnect::ReleaseXPConnectSingleton()
   154 {
   155     nsXPConnect* xpc = gSelf;
   156     if (xpc) {
   157         nsThread::SetMainThreadObserver(nullptr);
   159         nsrefcnt cnt;
   160         NS_RELEASE2(xpc, cnt);
   161     }
   162 }
   164 // static
   165 XPCJSRuntime*
   166 nsXPConnect::GetRuntimeInstance()
   167 {
   168     nsXPConnect* xpc = XPConnect();
   169     return xpc->GetRuntime();
   170 }
   172 // static
   173 bool
   174 nsXPConnect::IsISupportsDescendant(nsIInterfaceInfo* info)
   175 {
   176     bool found = false;
   177     if (info)
   178         info->HasAncestor(&NS_GET_IID(nsISupports), &found);
   179     return found;
   180 }
   182 void
   183 xpc::SystemErrorReporter(JSContext *cx, const char *message, JSErrorReport *rep)
   184 {
   185     // It would be nice to assert !DescribeScriptedCaller here, to be sure
   186     // that there isn't any script running that could catch the exception. But
   187     // the JS engine invokes the error reporter directly if someone reports an
   188     // ErrorReport that it doesn't know how to turn into an exception. Arguably
   189     // it should just learn how to throw everything. But either way, if the
   190     // exception is ending here, it's not going to get propagated to a caller,
   191     // so it's up to us to make it known.
   193     nsresult rv;
   195     /* Use the console service to register the error. */
   196     nsCOMPtr<nsIConsoleService> consoleService =
   197         do_GetService(NS_CONSOLESERVICE_CONTRACTID);
   199     /*
   200      * Make an nsIScriptError, populate it with information from this
   201      * error, then log it with the console service.
   202      */
   203     nsCOMPtr<nsIScriptError> errorObject =
   204         do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
   206     if (consoleService && errorObject) {
   207         uint32_t column = rep->uctokenptr - rep->uclinebuf;
   209         const char16_t* ucmessage =
   210             static_cast<const char16_t*>(rep->ucmessage);
   211         const char16_t* uclinebuf =
   212             static_cast<const char16_t*>(rep->uclinebuf);
   214         rv = errorObject->Init(
   215               ucmessage ? nsDependentString(ucmessage) : EmptyString(),
   216               NS_ConvertASCIItoUTF16(rep->filename),
   217               uclinebuf ? nsDependentString(uclinebuf) : EmptyString(),
   218               rep->lineno, column, rep->flags,
   219               "system javascript");
   220         if (NS_SUCCEEDED(rv))
   221             consoleService->LogMessage(errorObject);
   222     }
   224     if (nsContentUtils::DOMWindowDumpEnabled()) {
   225         fprintf(stderr, "System JS : %s %s:%d - %s\n",
   226                 JSREPORT_IS_WARNING(rep->flags) ? "WARNING" : "ERROR",
   227                 rep->filename, rep->lineno,
   228                 message ? message : "<no message>");
   229     }
   231 }
   234 /***************************************************************************/
   237 nsresult
   238 nsXPConnect::GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info)
   239 {
   240   return XPTInterfaceInfoManager::GetSingleton()->GetInfoForIID(aIID, info);
   241 }
   243 nsresult
   244 nsXPConnect::GetInfoForName(const char * name, nsIInterfaceInfo** info)
   245 {
   246   nsresult rv = XPTInterfaceInfoManager::GetSingleton()->GetInfoForName(name, info);
   247   return NS_FAILED(rv) ? NS_OK : NS_ERROR_NO_INTERFACE;
   248 }
   250 NS_IMETHODIMP
   251 nsXPConnect::GarbageCollect(uint32_t reason)
   252 {
   253     GetRuntime()->Collect(reason);
   254     return NS_OK;
   255 }
   257 bool
   258 xpc_GCThingIsGrayCCThing(void *thing)
   259 {
   260     return AddToCCKind(js::GCThingTraceKind(thing)) &&
   261            xpc_IsGrayGCThing(thing);
   262 }
   264 void
   265 xpc_MarkInCCGeneration(nsISupports* aVariant, uint32_t aGeneration)
   266 {
   267     nsCOMPtr<XPCVariant> variant = do_QueryInterface(aVariant);
   268     if (variant) {
   269         variant->SetCCGeneration(aGeneration);
   270         variant->GetJSVal(); // Unmarks gray JSObject.
   271         XPCVariant* weak = variant.get();
   272         variant = nullptr;
   273         if (weak->IsPurple()) {
   274           weak->RemovePurple();
   275         }
   276     }
   277 }
   279 void
   280 xpc_TryUnmarkWrappedGrayObject(nsISupports* aWrappedJS)
   281 {
   282     nsCOMPtr<nsIXPConnectWrappedJS> wjs = do_QueryInterface(aWrappedJS);
   283     if (wjs) {
   284         // Unmarks gray JSObject.
   285         static_cast<nsXPCWrappedJS*>(wjs.get())->GetJSObject();
   286     }
   287 }
   289 /***************************************************************************/
   290 /***************************************************************************/
   291 // nsIXPConnect interface methods...
   293 template<typename T>
   294 static inline T UnexpectedFailure(T rv)
   295 {
   296     NS_ERROR("This is not supposed to fail!");
   297     return rv;
   298 }
   300 /* void initClasses (in JSContextPtr aJSContext, in JSObjectPtr aGlobalJSObj); */
   301 NS_IMETHODIMP
   302 nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj)
   303 {
   304     MOZ_ASSERT(aJSContext, "bad param");
   305     MOZ_ASSERT(aGlobalJSObj, "bad param");
   306     RootedObject globalJSObj(aJSContext, aGlobalJSObj);
   308     JSAutoCompartment ac(aJSContext, globalJSObj);
   310     XPCWrappedNativeScope* scope =
   311         XPCWrappedNativeScope::GetNewOrUsed(aJSContext, globalJSObj);
   313     if (!scope)
   314         return UnexpectedFailure(NS_ERROR_FAILURE);
   316     scope->RemoveWrappedNativeProtos();
   318     if (!XPCNativeWrapper::AttachNewConstructorObject(aJSContext, globalJSObj))
   319         return UnexpectedFailure(NS_ERROR_FAILURE);
   321     return NS_OK;
   322 }
   324 #ifdef DEBUG
   325 static void
   326 VerifyTraceXPCGlobalCalled(JSTracer *trc, void **thingp, JSGCTraceKind kind)
   327 {
   328     // We don't do anything here, we only want to verify that TraceXPCGlobal
   329     // was called.
   330 }
   332 struct VerifyTraceXPCGlobalCalledTracer : public JSTracer
   333 {
   334     bool ok;
   336     VerifyTraceXPCGlobalCalledTracer(JSRuntime *rt)
   337       : JSTracer(rt, VerifyTraceXPCGlobalCalled), ok(false)
   338     {}
   339 };
   340 #endif
   342 void
   343 xpc::TraceXPCGlobal(JSTracer *trc, JSObject *obj)
   344 {
   345 #ifdef DEBUG
   346     if (trc->callback == VerifyTraceXPCGlobalCalled) {
   347         // We don't do anything here, we only want to verify that TraceXPCGlobal
   348         // was called.
   349         reinterpret_cast<VerifyTraceXPCGlobalCalledTracer*>(trc)->ok = true;
   350         return;
   351     }
   352 #endif
   354     if (js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL)
   355         mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
   357     // We might be called from a GC during the creation of a global, before we've
   358     // been able to set up the compartment private or the XPCWrappedNativeScope,
   359     // so we need to null-check those.
   360     xpc::CompartmentPrivate* compartmentPrivate = GetCompartmentPrivate(obj);
   361     if (compartmentPrivate && compartmentPrivate->scope)
   362         compartmentPrivate->scope->TraceInside(trc);
   363 }
   365 namespace xpc {
   367 JSObject*
   368 CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal,
   369                    JS::CompartmentOptions& aOptions)
   370 {
   371     MOZ_ASSERT(NS_IsMainThread(), "using a principal off the main thread?");
   372     MOZ_ASSERT(principal);
   374     RootedObject global(cx,
   375                         JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal),
   376                                            JS::DontFireOnNewGlobalHook, aOptions));
   377     if (!global)
   378         return nullptr;
   379     JSAutoCompartment ac(cx, global);
   381     // The constructor automatically attaches the scope to the compartment private
   382     // of |global|.
   383     (void) new XPCWrappedNativeScope(cx, global);
   385 #ifdef DEBUG
   386     // Verify that the right trace hook is called. Note that this doesn't
   387     // work right for wrapped globals, since the tracing situation there is
   388     // more complicated. Manual inspection shows that they do the right thing.
   389     if (!((const js::Class*)clasp)->ext.isWrappedNative)
   390     {
   391         VerifyTraceXPCGlobalCalledTracer trc(JS_GetRuntime(cx));
   392         JS_TraceChildren(&trc, global, JSTRACE_OBJECT);
   393         MOZ_ASSERT(trc.ok, "Trace hook on global needs to call TraceXPCGlobal for XPConnect compartments.");
   394     }
   395 #endif
   397     if (clasp->flags & JSCLASS_DOM_GLOBAL) {
   398         const char* className = clasp->name;
   399         AllocateProtoAndIfaceCache(global,
   400                                    (strcmp(className, "Window") == 0 ||
   401                                     strcmp(className, "ChromeWindow") == 0)
   402                                    ? ProtoAndIfaceCache::WindowLike
   403                                    : ProtoAndIfaceCache::NonWindowLike);
   404     }
   406     return global;
   407 }
   409 bool
   410 InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal, uint32_t aFlags)
   411 {
   412     // Immediately enter the global's compartment, so that everything else we
   413     // create ends up there.
   414     JSAutoCompartment ac(aJSContext, aGlobal);
   415     if (!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) {
   416         // XPCCallContext gives us an active request needed to save/restore.
   417         if (!GetCompartmentPrivate(aGlobal)->scope->AttachComponentsObject(aJSContext) ||
   418             !XPCNativeWrapper::AttachNewConstructorObject(aJSContext, aGlobal)) {
   419             return UnexpectedFailure(false);
   420         }
   421     }
   423     if (ShouldDiscardSystemSource()) {
   424         nsIPrincipal *prin = GetObjectPrincipal(aGlobal);
   425         bool isSystem = nsContentUtils::IsSystemPrincipal(prin);
   426         if (!isSystem) {
   427             short status = prin->GetAppStatus();
   428             isSystem = status == nsIPrincipal::APP_STATUS_PRIVILEGED ||
   429                        status == nsIPrincipal::APP_STATUS_CERTIFIED;
   430         }
   431         JS::CompartmentOptionsRef(aGlobal).setDiscardSource(isSystem);
   432     }
   434     // Stuff coming through this path always ends up as a DOM global.
   435     MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL);
   437     // Init WebIDL binding constructors wanted on all XPConnect globals.
   438     //
   439     // XXX Please do not add any additional classes here without the approval of
   440     //     the XPConnect module owner.
   441     if (!PromiseBinding::GetConstructorObject(aJSContext, aGlobal) ||
   442         !TextDecoderBinding::GetConstructorObject(aJSContext, aGlobal) ||
   443         !TextEncoderBinding::GetConstructorObject(aJSContext, aGlobal) ||
   444         !DOMErrorBinding::GetConstructorObject(aJSContext, aGlobal)) {
   445         return UnexpectedFailure(false);
   446     }
   448     if (!(aFlags & nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK))
   449         JS_FireOnNewGlobalObject(aJSContext, aGlobal);
   451     return true;
   452 }
   454 } // namespace xpc
   456 NS_IMETHODIMP
   457 nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
   458                                              nsISupports *aCOMObj,
   459                                              nsIPrincipal * aPrincipal,
   460                                              uint32_t aFlags,
   461                                              JS::CompartmentOptions& aOptions,
   462                                              nsIXPConnectJSObjectHolder **_retval)
   463 {
   464     MOZ_ASSERT(aJSContext, "bad param");
   465     MOZ_ASSERT(aCOMObj, "bad param");
   466     MOZ_ASSERT(_retval, "bad param");
   468     // We pass null for the 'extra' pointer during global object creation, so
   469     // we need to have a principal.
   470     MOZ_ASSERT(aPrincipal);
   472     // Call into XPCWrappedNative to make a new global object, scope, and global
   473     // prototype.
   474     xpcObjectHelper helper(aCOMObj);
   475     MOZ_ASSERT(helper.GetScriptableFlags() & nsIXPCScriptable::IS_GLOBAL_OBJECT);
   476     nsRefPtr<XPCWrappedNative> wrappedGlobal;
   477     nsresult rv =
   478         XPCWrappedNative::WrapNewGlobal(helper, aPrincipal,
   479                                         aFlags & nsIXPConnect::INIT_JS_STANDARD_CLASSES,
   480                                         aOptions, getter_AddRefs(wrappedGlobal));
   481     NS_ENSURE_SUCCESS(rv, rv);
   483     // Grab a copy of the global and enter its compartment.
   484     RootedObject global(aJSContext, wrappedGlobal->GetFlatJSObject());
   485     MOZ_ASSERT(!js::GetObjectParent(global));
   487     if (!InitGlobalObject(aJSContext, global, aFlags))
   488         return UnexpectedFailure(NS_ERROR_FAILURE);
   490     wrappedGlobal.forget(_retval);
   491     return NS_OK;
   492 }
   494 static nsresult
   495 NativeInterface2JSObject(HandleObject aScope,
   496                          nsISupports *aCOMObj,
   497                          nsWrapperCache *aCache,
   498                          const nsIID * aIID,
   499                          bool aAllowWrapping,
   500                          MutableHandleValue aVal,
   501                          nsIXPConnectJSObjectHolder **aHolder)
   502 {
   503     AutoJSContext cx;
   504     JSAutoCompartment ac(cx, aScope);
   506     nsresult rv;
   507     xpcObjectHelper helper(aCOMObj, aCache);
   508     if (!XPCConvert::NativeInterface2JSObject(aVal, aHolder, helper, aIID,
   509                                               nullptr, aAllowWrapping, &rv))
   510         return rv;
   512     MOZ_ASSERT(aAllowWrapping || !xpc::WrapperFactory::IsXrayWrapper(&aVal.toObject()),
   513                "Shouldn't be returning a xray wrapper here");
   515     return NS_OK;
   516 }
   518 /* nsIXPConnectJSObjectHolder wrapNative (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDRef aIID); */
   519 NS_IMETHODIMP
   520 nsXPConnect::WrapNative(JSContext * aJSContext,
   521                         JSObject * aScopeArg,
   522                         nsISupports *aCOMObj,
   523                         const nsIID & aIID,
   524                         nsIXPConnectJSObjectHolder **aHolder)
   525 {
   526     MOZ_ASSERT(aHolder, "bad param");
   527     MOZ_ASSERT(aJSContext, "bad param");
   528     MOZ_ASSERT(aScopeArg, "bad param");
   529     MOZ_ASSERT(aCOMObj, "bad param");
   531     RootedObject aScope(aJSContext, aScopeArg);
   532     RootedValue v(aJSContext);
   533     return NativeInterface2JSObject(aScope, aCOMObj, nullptr, &aIID,
   534                                     true, &v, aHolder);
   535 }
   537 /* void wrapNativeToJSVal (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDPtr aIID, out jsval aVal, out nsIXPConnectJSObjectHolder aHolder); */
   538 NS_IMETHODIMP
   539 nsXPConnect::WrapNativeToJSVal(JSContext *aJSContext,
   540                                JSObject *aScopeArg,
   541                                nsISupports *aCOMObj,
   542                                nsWrapperCache *aCache,
   543                                const nsIID *aIID,
   544                                bool aAllowWrapping,
   545                                MutableHandleValue aVal)
   546 {
   547     MOZ_ASSERT(aJSContext, "bad param");
   548     MOZ_ASSERT(aScopeArg, "bad param");
   549     MOZ_ASSERT(aCOMObj, "bad param");
   551     RootedObject aScope(aJSContext, aScopeArg);
   552     return NativeInterface2JSObject(aScope, aCOMObj, aCache, aIID,
   553                                     aAllowWrapping, aVal, nullptr);
   554 }
   556 /* void wrapJS (in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */
   557 NS_IMETHODIMP
   558 nsXPConnect::WrapJS(JSContext * aJSContext,
   559                     JSObject * aJSObjArg,
   560                     const nsIID & aIID,
   561                     void * *result)
   562 {
   563     MOZ_ASSERT(aJSContext, "bad param");
   564     MOZ_ASSERT(aJSObjArg, "bad param");
   565     MOZ_ASSERT(result, "bad param");
   567     *result = nullptr;
   569     RootedObject aJSObj(aJSContext, aJSObjArg);
   570     JSAutoCompartment ac(aJSContext, aJSObj);
   572     nsresult rv = NS_ERROR_UNEXPECTED;
   573     if (!XPCConvert::JSObject2NativeInterface(result, aJSObj,
   574                                               &aIID, nullptr, &rv))
   575         return rv;
   576     return NS_OK;
   577 }
   579 NS_IMETHODIMP
   580 nsXPConnect::JSValToVariant(JSContext *cx,
   581                             HandleValue aJSVal,
   582                             nsIVariant **aResult)
   583 {
   584     NS_PRECONDITION(aResult, "bad param");
   586     nsRefPtr<XPCVariant> variant = XPCVariant::newVariant(cx, aJSVal);
   587     variant.forget(aResult);
   588     NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
   590     return NS_OK;
   591 }
   593 /* void wrapJSAggregatedToNative (in nsISupports aOuter, in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */
   594 NS_IMETHODIMP
   595 nsXPConnect::WrapJSAggregatedToNative(nsISupports *aOuter,
   596                                       JSContext *aJSContext,
   597                                       JSObject *aJSObjArg,
   598                                       const nsIID &aIID,
   599                                       void **result)
   600 {
   601     MOZ_ASSERT(aOuter, "bad param");
   602     MOZ_ASSERT(aJSContext, "bad param");
   603     MOZ_ASSERT(aJSObjArg, "bad param");
   604     MOZ_ASSERT(result, "bad param");
   606     *result = nullptr;
   608     RootedObject aJSObj(aJSContext, aJSObjArg);
   609     nsresult rv;
   610     if (!XPCConvert::JSObject2NativeInterface(result, aJSObj,
   611                                               &aIID, aOuter, &rv))
   612         return rv;
   613     return NS_OK;
   614 }
   616 /* nsIXPConnectWrappedNative getWrappedNativeOfJSObject (in JSContextPtr aJSContext, in JSObjectPtr aJSObj); */
   617 NS_IMETHODIMP
   618 nsXPConnect::GetWrappedNativeOfJSObject(JSContext * aJSContext,
   619                                         JSObject * aJSObjArg,
   620                                         nsIXPConnectWrappedNative **_retval)
   621 {
   622     MOZ_ASSERT(aJSContext, "bad param");
   623     MOZ_ASSERT(aJSObjArg, "bad param");
   624     MOZ_ASSERT(_retval, "bad param");
   626     RootedObject aJSObj(aJSContext, aJSObjArg);
   627     aJSObj = js::CheckedUnwrap(aJSObj, /* stopAtOuter = */ false);
   628     if (!aJSObj || !IS_WN_REFLECTOR(aJSObj)) {
   629         *_retval = nullptr;
   630         return NS_ERROR_FAILURE;
   631     }
   633     nsRefPtr<XPCWrappedNative> temp = XPCWrappedNative::Get(aJSObj);
   634     temp.forget(_retval);
   635     return NS_OK;
   636 }
   638 /* nsISupports getNativeOfWrapper(in JSContextPtr aJSContext, in JSObjectPtr  aJSObj); */
   639 NS_IMETHODIMP_(nsISupports*)
   640 nsXPConnect::GetNativeOfWrapper(JSContext *aJSContext,
   641                                 JSObject *aJSObj)
   642 {
   643     MOZ_ASSERT(aJSContext, "bad param");
   644     MOZ_ASSERT(aJSObj, "bad param");
   646     aJSObj = js::CheckedUnwrap(aJSObj, /* stopAtOuter = */ false);
   647     if (!aJSObj) {
   648         JS_ReportError(aJSContext, "Permission denied to get native of security wrapper");
   649         return nullptr;
   650     }
   651     if (IS_WN_REFLECTOR(aJSObj)) {
   652         if (XPCWrappedNative *wn = XPCWrappedNative::Get(aJSObj))
   653             return wn->Native();
   654         return nullptr;
   655     }
   657     nsCOMPtr<nsISupports> canonical =
   658         do_QueryInterface(mozilla::dom::UnwrapDOMObjectToISupports(aJSObj));
   659     return canonical;
   660 }
   662 /* nsIXPConnectWrappedNative getWrappedNativeOfNativeObject (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDRef aIID); */
   663 NS_IMETHODIMP
   664 nsXPConnect::GetWrappedNativeOfNativeObject(JSContext * aJSContext,
   665                                             JSObject * aScopeArg,
   666                                             nsISupports *aCOMObj,
   667                                             const nsIID & aIID,
   668                                             nsIXPConnectWrappedNative **_retval)
   669 {
   670     MOZ_ASSERT(aJSContext, "bad param");
   671     MOZ_ASSERT(aScopeArg, "bad param");
   672     MOZ_ASSERT(aCOMObj, "bad param");
   673     MOZ_ASSERT(_retval, "bad param");
   675     *_retval = nullptr;
   677     RootedObject aScope(aJSContext, aScopeArg);
   679     XPCWrappedNativeScope* scope = GetObjectScope(aScope);
   680     if (!scope)
   681         return UnexpectedFailure(NS_ERROR_FAILURE);
   683     AutoMarkingNativeInterfacePtr iface(aJSContext);
   684     iface = XPCNativeInterface::GetNewOrUsed(&aIID);
   685     if (!iface)
   686         return NS_ERROR_FAILURE;
   688     XPCWrappedNative* wrapper;
   690     nsresult rv = XPCWrappedNative::GetUsedOnly(aCOMObj, scope, iface, &wrapper);
   691     if (NS_FAILED(rv))
   692         return NS_ERROR_FAILURE;
   693     *_retval = static_cast<nsIXPConnectWrappedNative*>(wrapper);
   694     return NS_OK;
   695 }
   697 /* void reparentWrappedNativeIfFound (in JSContextPtr aJSContext,
   698  *                                    in JSObjectPtr aScope,
   699  *                                    in JSObjectPtr aNewParent,
   700  *                                    in nsISupports aCOMObj); */
   701 NS_IMETHODIMP
   702 nsXPConnect::ReparentWrappedNativeIfFound(JSContext * aJSContext,
   703                                           JSObject * aScopeArg,
   704                                           JSObject * aNewParentArg,
   705                                           nsISupports *aCOMObj)
   706 {
   707     RootedObject aScope(aJSContext, aScopeArg);
   708     RootedObject aNewParent(aJSContext, aNewParentArg);
   710     XPCWrappedNativeScope* scope = GetObjectScope(aScope);
   711     XPCWrappedNativeScope* scope2 = GetObjectScope(aNewParent);
   712     if (!scope || !scope2)
   713         return UnexpectedFailure(NS_ERROR_FAILURE);
   715     RootedObject newParent(aJSContext, aNewParent);
   716     return XPCWrappedNative::
   717         ReparentWrapperIfFound(scope, scope2, newParent, aCOMObj);
   718 }
   720 static PLDHashOperator
   721 MoveableWrapperFinder(PLDHashTable *table, PLDHashEntryHdr *hdr,
   722                       uint32_t number, void *arg)
   723 {
   724     nsTArray<nsRefPtr<XPCWrappedNative> > *array =
   725         static_cast<nsTArray<nsRefPtr<XPCWrappedNative> > *>(arg);
   726     XPCWrappedNative *wn = ((Native2WrappedNativeMap::Entry*)hdr)->value;
   728     // If a wrapper is expired, then there are no references to it from JS, so
   729     // we don't have to move it.
   730     if (!wn->IsWrapperExpired())
   731         array->AppendElement(wn);
   732     return PL_DHASH_NEXT;
   733 }
   735 /* void rescueOrphansInScope(in JSContextPtr aJSContext, in JSObjectPtr  aScope); */
   736 NS_IMETHODIMP
   737 nsXPConnect::RescueOrphansInScope(JSContext *aJSContext, JSObject *aScopeArg)
   738 {
   739     RootedObject aScope(aJSContext, aScopeArg);
   741     XPCWrappedNativeScope *scope = GetObjectScope(aScope);
   742     if (!scope)
   743         return UnexpectedFailure(NS_ERROR_FAILURE);
   745     // First, look through the old scope and find all of the wrappers that we
   746     // might need to rescue.
   747     nsTArray<nsRefPtr<XPCWrappedNative> > wrappersToMove;
   749     Native2WrappedNativeMap *map = scope->GetWrappedNativeMap();
   750     wrappersToMove.SetCapacity(map->Count());
   751     map->Enumerate(MoveableWrapperFinder, &wrappersToMove);
   753     // Now that we have the wrappers, reparent them to the new scope.
   754     for (uint32_t i = 0, stop = wrappersToMove.Length(); i < stop; ++i) {
   755         nsresult rv = wrappersToMove[i]->RescueOrphans();
   756         NS_ENSURE_SUCCESS(rv, rv);
   757     }
   759     return NS_OK;
   760 }
   762 /* void setDefaultSecurityManager (in nsIXPCSecurityManager aManager); */
   763 NS_IMETHODIMP
   764 nsXPConnect::SetDefaultSecurityManager(nsIXPCSecurityManager *aManager)
   765 {
   766     mDefaultSecurityManager = aManager;
   768     nsCOMPtr<nsIScriptSecurityManager> ssm =
   769         do_QueryInterface(mDefaultSecurityManager);
   771     // Remember the result of the above QI for fast access to the
   772     // script securityt manager.
   773     gScriptSecurityManager = ssm;
   775     return NS_OK;
   776 }
   778 /* nsIStackFrame createStackFrameLocation (in uint32_t aLanguage, in string aFilename, in string aFunctionName, in int32_t aLineNumber, in nsIStackFrame aCaller); */
   779 NS_IMETHODIMP
   780 nsXPConnect::CreateStackFrameLocation(uint32_t aLanguage,
   781                                       const char *aFilename,
   782                                       const char *aFunctionName,
   783                                       int32_t aLineNumber,
   784                                       nsIStackFrame *aCaller,
   785                                       nsIStackFrame **_retval)
   786 {
   787     MOZ_ASSERT(_retval, "bad param");
   789     nsCOMPtr<nsIStackFrame> stackFrame =
   790         exceptions::CreateStackFrameLocation(aLanguage,
   791                                              aFilename,
   792                                              aFunctionName,
   793                                              aLineNumber,
   794                                              aCaller);
   795     stackFrame.forget(_retval);
   796     return NS_OK;
   797 }
   799 /* readonly attribute nsIStackFrame CurrentJSStack; */
   800 NS_IMETHODIMP
   801 nsXPConnect::GetCurrentJSStack(nsIStackFrame * *aCurrentJSStack)
   802 {
   803     MOZ_ASSERT(aCurrentJSStack, "bad param");
   805     nsCOMPtr<nsIStackFrame> currentStack = dom::GetCurrentJSStack();
   806     currentStack.forget(aCurrentJSStack);
   808     return NS_OK;
   809 }
   811 /* readonly attribute nsIXPCNativeCallContext CurrentNativeCallContext; */
   812 NS_IMETHODIMP
   813 nsXPConnect::GetCurrentNativeCallContext(nsAXPCNativeCallContext * *aCurrentNativeCallContext)
   814 {
   815     MOZ_ASSERT(aCurrentNativeCallContext, "bad param");
   817     *aCurrentNativeCallContext = XPCJSRuntime::Get()->GetCallContext();
   818     return NS_OK;
   819 }
   821 /* void setFunctionThisTranslator (in nsIIDRef aIID, in nsIXPCFunctionThisTranslator aTranslator); */
   822 NS_IMETHODIMP
   823 nsXPConnect::SetFunctionThisTranslator(const nsIID & aIID,
   824                                        nsIXPCFunctionThisTranslator *aTranslator)
   825 {
   826     XPCJSRuntime* rt = GetRuntime();
   827     IID2ThisTranslatorMap* map = rt->GetThisTranslatorMap();
   828     map->Add(aIID, aTranslator);
   829     return NS_OK;
   830 }
   832 NS_IMETHODIMP
   833 nsXPConnect::CreateSandbox(JSContext *cx, nsIPrincipal *principal,
   834                            nsIXPConnectJSObjectHolder **_retval)
   835 {
   836     *_retval = nullptr;
   838     RootedValue rval(cx);
   839     SandboxOptions options;
   840     nsresult rv = CreateSandboxObject(cx, &rval, principal, options);
   841     MOZ_ASSERT(NS_FAILED(rv) || !JSVAL_IS_PRIMITIVE(rval),
   842                "Bad return value from xpc_CreateSandboxObject()!");
   844     if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(rval)) {
   845         *_retval = XPCJSObjectHolder::newHolder(JSVAL_TO_OBJECT(rval));
   846         NS_ENSURE_TRUE(*_retval, NS_ERROR_OUT_OF_MEMORY);
   848         NS_ADDREF(*_retval);
   849     }
   851     return rv;
   852 }
   854 NS_IMETHODIMP
   855 nsXPConnect::EvalInSandboxObject(const nsAString& source, const char *filename,
   856                                  JSContext *cx, JSObject *sandboxArg,
   857                                  bool returnStringOnly, MutableHandleValue rval)
   858 {
   859     if (!sandboxArg)
   860         return NS_ERROR_INVALID_ARG;
   862     RootedObject sandbox(cx, sandboxArg);
   863     nsCString filenameStr;
   864     if (filename) {
   865         filenameStr.Assign(filename);
   866     } else {
   867         filenameStr = NS_LITERAL_CSTRING("x-bogus://XPConnect/Sandbox");
   868     }
   869     return EvalInSandbox(cx, sandbox, source, filenameStr, 1,
   870                          JSVERSION_DEFAULT, returnStringOnly, rval);
   871 }
   873 /* nsIXPConnectJSObjectHolder getWrappedNativePrototype (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsIClassInfo aClassInfo); */
   874 NS_IMETHODIMP
   875 nsXPConnect::GetWrappedNativePrototype(JSContext * aJSContext,
   876                                        JSObject * aScopeArg,
   877                                        nsIClassInfo *aClassInfo,
   878                                        nsIXPConnectJSObjectHolder **_retval)
   879 {
   880     RootedObject aScope(aJSContext, aScopeArg);
   881     JSAutoCompartment ac(aJSContext, aScope);
   883     XPCWrappedNativeScope* scope = GetObjectScope(aScope);
   884     if (!scope)
   885         return UnexpectedFailure(NS_ERROR_FAILURE);
   887     XPCNativeScriptableCreateInfo sciProto;
   888     XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, sciProto);
   890     AutoMarkingWrappedNativeProtoPtr proto(aJSContext);
   891     proto = XPCWrappedNativeProto::GetNewOrUsed(scope, aClassInfo, &sciProto);
   892     if (!proto)
   893         return UnexpectedFailure(NS_ERROR_FAILURE);
   895     nsIXPConnectJSObjectHolder* holder;
   896     *_retval = holder = XPCJSObjectHolder::newHolder(proto->GetJSProtoObject());
   897     if (!holder)
   898         return UnexpectedFailure(NS_ERROR_FAILURE);
   900     NS_ADDREF(holder);
   901     return NS_OK;
   902 }
   904 /* void debugDump (in short depth); */
   905 NS_IMETHODIMP
   906 nsXPConnect::DebugDump(int16_t depth)
   907 {
   908 #ifdef DEBUG
   909     depth-- ;
   910     XPC_LOG_ALWAYS(("nsXPConnect @ %x with mRefCnt = %d", this, mRefCnt.get()));
   911     XPC_LOG_INDENT();
   912         XPC_LOG_ALWAYS(("gSelf @ %x", gSelf));
   913         XPC_LOG_ALWAYS(("gOnceAliveNowDead is %d", (int)gOnceAliveNowDead));
   914         XPC_LOG_ALWAYS(("mDefaultSecurityManager @ %x", mDefaultSecurityManager.get()));
   915         if (mRuntime) {
   916             if (depth)
   917                 mRuntime->DebugDump(depth);
   918             else
   919                 XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", mRuntime));
   920         } else
   921             XPC_LOG_ALWAYS(("mRuntime is null"));
   922         XPCWrappedNativeScope::DebugDumpAllScopes(depth);
   923     XPC_LOG_OUTDENT();
   924 #endif
   925     return NS_OK;
   926 }
   928 /* void debugDumpObject (in nsISupports aCOMObj, in short depth); */
   929 NS_IMETHODIMP
   930 nsXPConnect::DebugDumpObject(nsISupports *p, int16_t depth)
   931 {
   932 #ifdef DEBUG
   933     if (!depth)
   934         return NS_OK;
   935     if (!p) {
   936         XPC_LOG_ALWAYS(("*** Cound not dump object with NULL address"));
   937         return NS_OK;
   938     }
   940     nsIXPConnect* xpc;
   941     nsIXPCWrappedJSClass* wjsc;
   942     nsIXPConnectWrappedNative* wn;
   943     nsIXPConnectWrappedJS* wjs;
   945     if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnect),
   946                                        (void**)&xpc))) {
   947         XPC_LOG_ALWAYS(("Dumping a nsIXPConnect..."));
   948         xpc->DebugDump(depth);
   949         NS_RELEASE(xpc);
   950     } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPCWrappedJSClass),
   951                                               (void**)&wjsc))) {
   952         XPC_LOG_ALWAYS(("Dumping a nsIXPCWrappedJSClass..."));
   953         wjsc->DebugDump(depth);
   954         NS_RELEASE(wjsc);
   955     } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedNative),
   956                                               (void**)&wn))) {
   957         XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedNative..."));
   958         wn->DebugDump(depth);
   959         NS_RELEASE(wn);
   960     } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedJS),
   961                                               (void**)&wjs))) {
   962         XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedJS..."));
   963         wjs->DebugDump(depth);
   964         NS_RELEASE(wjs);
   965     } else
   966         XPC_LOG_ALWAYS(("*** Could not dump the nsISupports @ %x", p));
   967 #endif
   968     return NS_OK;
   969 }
   971 /* void debugDumpJSStack (in bool showArgs, in bool showLocals, in bool showThisProps); */
   972 NS_IMETHODIMP
   973 nsXPConnect::DebugDumpJSStack(bool showArgs,
   974                               bool showLocals,
   975                               bool showThisProps)
   976 {
   977     JSContext* cx = GetCurrentJSContext();
   978     if (!cx)
   979         printf("there is no JSContext on the nsIThreadJSContextStack!\n");
   980     else
   981         xpc_DumpJSStack(cx, showArgs, showLocals, showThisProps);
   983     return NS_OK;
   984 }
   986 char*
   987 nsXPConnect::DebugPrintJSStack(bool showArgs,
   988                                bool showLocals,
   989                                bool showThisProps)
   990 {
   991     JSContext* cx = GetCurrentJSContext();
   992     if (!cx)
   993         printf("there is no JSContext on the nsIThreadJSContextStack!\n");
   994     else
   995         return xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps);
   997     return nullptr;
   998 }
  1000 /* void debugDumpEvalInJSStackFrame (in uint32_t aFrameNumber, in string aSourceText); */
  1001 NS_IMETHODIMP
  1002 nsXPConnect::DebugDumpEvalInJSStackFrame(uint32_t aFrameNumber, const char *aSourceText)
  1004     JSContext* cx = GetCurrentJSContext();
  1005     if (!cx)
  1006         printf("there is no JSContext on the nsIThreadJSContextStack!\n");
  1007     else
  1008         xpc_DumpEvalInJSStackFrame(cx, aFrameNumber, aSourceText);
  1010     return NS_OK;
  1013 /* jsval variantToJS (in JSContextPtr ctx, in JSObjectPtr scope, in nsIVariant value); */
  1014 NS_IMETHODIMP
  1015 nsXPConnect::VariantToJS(JSContext* ctx, JSObject* scopeArg, nsIVariant* value,
  1016                          MutableHandleValue _retval)
  1018     NS_PRECONDITION(ctx, "bad param");
  1019     NS_PRECONDITION(scopeArg, "bad param");
  1020     NS_PRECONDITION(value, "bad param");
  1022     RootedObject scope(ctx, scopeArg);
  1023     MOZ_ASSERT(js::IsObjectInContextCompartment(scope, ctx));
  1025     nsresult rv = NS_OK;
  1026     if (!XPCVariant::VariantDataToJS(value, &rv, _retval)) {
  1027         if (NS_FAILED(rv))
  1028             return rv;
  1030         return NS_ERROR_FAILURE;
  1032     return NS_OK;
  1035 /* nsIVariant JSToVariant (in JSContextPtr ctx, in jsval value); */
  1036 NS_IMETHODIMP
  1037 nsXPConnect::JSToVariant(JSContext* ctx, HandleValue value, nsIVariant** _retval)
  1039     NS_PRECONDITION(ctx, "bad param");
  1040     NS_PRECONDITION(_retval, "bad param");
  1042     nsRefPtr<XPCVariant> variant = XPCVariant::newVariant(ctx, value);
  1043     variant.forget(_retval);
  1044     if (!(*_retval))
  1045         return NS_ERROR_FAILURE;
  1047     return NS_OK;
  1050 NS_IMETHODIMP
  1051 nsXPConnect::OnProcessNextEvent(nsIThreadInternal *aThread, bool aMayWait,
  1052                                 uint32_t aRecursionDepth)
  1054     // Record this event.
  1055     mEventDepth++;
  1057     // Push a null JSContext so that we don't see any script during
  1058     // event processing.
  1059     MOZ_ASSERT(NS_IsMainThread());
  1060     bool ok = PushJSContextNoScriptContext(nullptr);
  1061     NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
  1062     return NS_OK;
  1065 NS_IMETHODIMP
  1066 nsXPConnect::AfterProcessNextEvent(nsIThreadInternal *aThread,
  1067                                    uint32_t aRecursionDepth,
  1068                                    bool aEventWasProcessed)
  1070     // Watch out for unpaired events during observer registration.
  1071     if (MOZ_UNLIKELY(mEventDepth == 0))
  1072         return NS_OK;
  1073     mEventDepth--;
  1075     // Now that we're back to the event loop, reset the slow script checkpoint.
  1076     mRuntime->OnAfterProcessNextEvent();
  1078     // Call cycle collector occasionally.
  1079     MOZ_ASSERT(NS_IsMainThread());
  1080     nsJSContext::MaybePokeCC();
  1081     nsDOMMutationObserver::HandleMutations();
  1083     PopJSContextNoScriptContext();
  1085     // If the cx stack is empty, that means we're at the an un-nested event
  1086     // loop. This is a good time to make changes to debug mode.
  1087     if (XPCJSRuntime::Get()->GetJSContextStack()->Count() == 0) {
  1088         MOZ_ASSERT(mEventDepth == 0);
  1089         CheckForDebugMode(XPCJSRuntime::Get()->Runtime());
  1091     return NS_OK;
  1094 NS_IMETHODIMP
  1095 nsXPConnect::OnDispatchedEvent(nsIThreadInternal* aThread)
  1097     NS_NOTREACHED("Why tell us?");
  1098     return NS_ERROR_UNEXPECTED;
  1101 NS_IMETHODIMP
  1102 nsXPConnect::SetReportAllJSExceptions(bool newval)
  1104     // Ignore if the environment variable was set.
  1105     if (gReportAllJSExceptions != 1)
  1106         gReportAllJSExceptions = newval ? 2 : 0;
  1108     return NS_OK;
  1111 /* attribute JSRuntime runtime; */
  1112 NS_IMETHODIMP
  1113 nsXPConnect::GetRuntime(JSRuntime **runtime)
  1115     if (!runtime)
  1116         return NS_ERROR_NULL_POINTER;
  1118     JSRuntime *rt = GetRuntime()->Runtime();
  1119     JS_AbortIfWrongThread(rt);
  1120     *runtime = rt;
  1121     return NS_OK;
  1124 /* [noscript, notxpcom] void registerGCCallback(in xpcGCCallback func); */
  1125 NS_IMETHODIMP_(void)
  1126 nsXPConnect::RegisterGCCallback(xpcGCCallback func)
  1128     mRuntime->AddGCCallback(func);
  1131 /* [noscript, notxpcom] void unregisterGCCallback(in xpcGCCallback func); */
  1132 NS_IMETHODIMP_(void)
  1133 nsXPConnect::UnregisterGCCallback(xpcGCCallback func)
  1135     mRuntime->RemoveGCCallback(func);
  1138 /* [noscript, notxpcom] void registerContextCallback(in xpcContextCallback func); */
  1139 NS_IMETHODIMP_(void)
  1140 nsXPConnect::RegisterContextCallback(xpcContextCallback func)
  1142     mRuntime->AddContextCallback(func);
  1145 /* [noscript, notxpcom] void unregisterContextCallback(in xpcContextCallback func); */
  1146 NS_IMETHODIMP_(void)
  1147 nsXPConnect::UnregisterContextCallback(xpcContextCallback func)
  1149     mRuntime->RemoveContextCallback(func);
  1152 #ifdef MOZ_JSDEBUGGER
  1153 void
  1154 nsXPConnect::CheckForDebugMode(JSRuntime *rt)
  1156     if (gDebugMode == gDesiredDebugMode) {
  1157         return;
  1160     // This can happen if a Worker is running, but we don't have the ability to
  1161     // debug workers right now, so just return.
  1162     if (!NS_IsMainThread())
  1163         MOZ_CRASH();
  1165     AutoSafeJSContext cx;
  1166     JS_SetRuntimeDebugMode(rt, gDesiredDebugMode);
  1168     nsresult rv;
  1169     const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
  1170     nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
  1171     if (NS_FAILED(rv)) {
  1172         goto fail;
  1175     if (!JS_SetDebugModeForAllCompartments(cx, gDesiredDebugMode))
  1176         goto fail;
  1178     if (gDesiredDebugMode) {
  1179         rv = jsds->ActivateDebugger(rt);
  1182     gDebugMode = gDesiredDebugMode;
  1183     return;
  1185 fail:
  1186     if (jsds)
  1187         jsds->DeactivateDebugger();
  1189     /*
  1190      * If an attempt to turn debug mode on fails, cancel the request. It's
  1191      * always safe to turn debug mode off, since DeactivateDebugger prevents
  1192      * debugger callbacks from having any effect.
  1193      */
  1194     if (gDesiredDebugMode)
  1195         JS_SetRuntimeDebugMode(rt, false);
  1196     gDesiredDebugMode = gDebugMode = false;
  1198 #else //MOZ_JSDEBUGGER not defined
  1199 void
  1200 nsXPConnect::CheckForDebugMode(JSRuntime *rt)
  1202     gDesiredDebugMode = gDebugMode = false;
  1204 #endif //#ifdef MOZ_JSDEBUGGER
  1207 void
  1208 xpc_ActivateDebugMode()
  1210     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
  1211     nsXPConnect::XPConnect()->SetDebugModeWhenPossible(true, true);
  1212     nsXPConnect::CheckForDebugMode(rt->Runtime());
  1215 /* virtual */
  1216 JSContext*
  1217 nsXPConnect::GetCurrentJSContext()
  1219     return GetRuntime()->GetJSContextStack()->Peek();
  1222 /* virtual */
  1223 JSContext*
  1224 nsXPConnect::InitSafeJSContext()
  1226     return GetRuntime()->GetJSContextStack()->InitSafeJSContext();
  1229 /* virtual */
  1230 JSContext*
  1231 nsXPConnect::GetSafeJSContext()
  1233     return GetRuntime()->GetJSContextStack()->GetSafeJSContext();
  1236 namespace xpc {
  1238 bool
  1239 PushJSContextNoScriptContext(JSContext *aCx)
  1241     MOZ_ASSERT_IF(aCx, !GetScriptContextFromJSContext(aCx));
  1242     return XPCJSRuntime::Get()->GetJSContextStack()->Push(aCx);
  1245 void
  1246 PopJSContextNoScriptContext()
  1248     XPCJSRuntime::Get()->GetJSContextStack()->Pop();
  1251 } // namespace xpc
  1253 nsIPrincipal*
  1254 nsXPConnect::GetPrincipal(JSObject* obj, bool allowShortCircuit) const
  1256     MOZ_ASSERT(IS_WN_REFLECTOR(obj), "What kind of wrapper is this?");
  1258     XPCWrappedNative *xpcWrapper = XPCWrappedNative::Get(obj);
  1259     if (xpcWrapper) {
  1260         if (allowShortCircuit) {
  1261             nsIPrincipal *result = xpcWrapper->GetObjectPrincipal();
  1262             if (result) {
  1263                 return result;
  1267         // If not, check if it points to an nsIScriptObjectPrincipal
  1268         nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
  1269             do_QueryInterface(xpcWrapper->Native());
  1270         if (objPrin) {
  1271             nsIPrincipal *result = objPrin->GetPrincipal();
  1272             if (result) {
  1273                 return result;
  1278     return nullptr;
  1281 NS_IMETHODIMP
  1282 nsXPConnect::HoldObject(JSContext *aJSContext, JSObject *aObjectArg,
  1283                         nsIXPConnectJSObjectHolder **aHolder)
  1285     RootedObject aObject(aJSContext, aObjectArg);
  1286     XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(aObject);
  1287     if (!objHolder)
  1288         return NS_ERROR_OUT_OF_MEMORY;
  1290     NS_ADDREF(*aHolder = objHolder);
  1291     return NS_OK;
  1294 namespace xpc {
  1296 bool
  1297 Base64Encode(JSContext *cx, HandleValue val, MutableHandleValue out)
  1299     MOZ_ASSERT(cx);
  1301     JS::RootedValue root(cx, val);
  1302     xpc_qsACString encodedString(cx, root, &root, false,
  1303                                  xpc_qsACString::eStringify,
  1304                                  xpc_qsACString::eStringify);
  1305     if (!encodedString.IsValid())
  1306         return false;
  1308     nsAutoCString result;
  1309     if (NS_FAILED(mozilla::Base64Encode(encodedString, result))) {
  1310         JS_ReportError(cx, "Failed to encode base64 data!");
  1311         return false;
  1314     JSString *str = JS_NewStringCopyN(cx, result.get(), result.Length());
  1315     if (!str)
  1316         return false;
  1318     out.setString(str);
  1319     return true;
  1322 bool
  1323 Base64Decode(JSContext *cx, HandleValue val, MutableHandleValue out)
  1325     MOZ_ASSERT(cx);
  1327     JS::RootedValue root(cx, val);
  1328     xpc_qsACString encodedString(cx, root, &root, false,
  1329                                  xpc_qsACString::eStringify,
  1330                                  xpc_qsACString::eStringify);
  1331     if (!encodedString.IsValid())
  1332         return false;
  1334     nsAutoCString result;
  1335     if (NS_FAILED(mozilla::Base64Decode(encodedString, result))) {
  1336         JS_ReportError(cx, "Failed to decode base64 string!");
  1337         return false;
  1340     JSString *str = JS_NewStringCopyN(cx, result.get(), result.Length());
  1341     if (!str)
  1342         return false;
  1344     out.setString(str);
  1345     return true;
  1348 void
  1349 SetLocationForGlobal(JSObject *global, const nsACString& location)
  1351     MOZ_ASSERT(global);
  1352     EnsureCompartmentPrivate(global)->SetLocation(location);
  1355 void
  1356 SetLocationForGlobal(JSObject *global, nsIURI *locationURI)
  1358     MOZ_ASSERT(global);
  1359     EnsureCompartmentPrivate(global)->SetLocationURI(locationURI);
  1362 } // namespace xpc
  1364 NS_IMETHODIMP
  1365 nsXPConnect::SetDebugModeWhenPossible(bool mode, bool allowSyncDisable)
  1367     gDesiredDebugMode = mode;
  1368     if (!mode && allowSyncDisable)
  1369         CheckForDebugMode(mRuntime->Runtime());
  1370     return NS_OK;
  1373 NS_IMETHODIMP
  1374 nsXPConnect::NotifyDidPaint()
  1376     JS::NotifyDidPaint(GetRuntime()->Runtime());
  1377     return NS_OK;
  1380 // Note - We used to have HAS_PRINCIPALS_FLAG = 1 here, so reusing that flag
  1381 // will require bumping the XDR version number.
  1382 static const uint8_t HAS_ORIGIN_PRINCIPALS_FLAG        = 2;
  1384 static nsresult
  1385 WriteScriptOrFunction(nsIObjectOutputStream *stream, JSContext *cx,
  1386                       JSScript *scriptArg, HandleObject functionObj)
  1388     // Exactly one of script or functionObj must be given
  1389     MOZ_ASSERT(!scriptArg != !functionObj);
  1391     RootedScript script(cx, scriptArg);
  1392     if (!script) {
  1393         RootedFunction fun(cx, JS_GetObjectFunction(functionObj));
  1394         script.set(JS_GetFunctionScript(cx, fun));
  1397     nsIPrincipal *principal =
  1398         nsJSPrincipals::get(JS_GetScriptPrincipals(script));
  1399     nsIPrincipal *originPrincipal =
  1400         nsJSPrincipals::get(JS_GetScriptOriginPrincipals(script));
  1402     uint8_t flags = 0;
  1404     // Optimize for the common case when originPrincipals == principals. As
  1405     // originPrincipals is set to principals when the former is null we can
  1406     // simply skip the originPrincipals when they are the same as principals.
  1407     if (originPrincipal && originPrincipal != principal)
  1408         flags |= HAS_ORIGIN_PRINCIPALS_FLAG;
  1410     nsresult rv = stream->Write8(flags);
  1411     if (NS_FAILED(rv))
  1412         return rv;
  1414     if (flags & HAS_ORIGIN_PRINCIPALS_FLAG) {
  1415         rv = stream->WriteObject(originPrincipal, true);
  1416         if (NS_FAILED(rv))
  1417             return rv;
  1420     uint32_t size;
  1421     void* data;
  1423         if (functionObj)
  1424             data = JS_EncodeInterpretedFunction(cx, functionObj, &size);
  1425         else
  1426             data = JS_EncodeScript(cx, script, &size);
  1429     if (!data)
  1430         return NS_ERROR_OUT_OF_MEMORY;
  1431     MOZ_ASSERT(size);
  1432     rv = stream->Write32(size);
  1433     if (NS_SUCCEEDED(rv))
  1434         rv = stream->WriteBytes(static_cast<char *>(data), size);
  1435     js_free(data);
  1437     return rv;
  1440 static nsresult
  1441 ReadScriptOrFunction(nsIObjectInputStream *stream, JSContext *cx,
  1442                      JSScript **scriptp, JSObject **functionObjp)
  1444     // Exactly one of script or functionObj must be given
  1445     MOZ_ASSERT(!scriptp != !functionObjp);
  1447     uint8_t flags;
  1448     nsresult rv = stream->Read8(&flags);
  1449     if (NS_FAILED(rv))
  1450         return rv;
  1452     nsJSPrincipals* originPrincipal = nullptr;
  1453     nsCOMPtr<nsIPrincipal> readOriginPrincipal;
  1454     if (flags & HAS_ORIGIN_PRINCIPALS_FLAG) {
  1455         nsCOMPtr<nsISupports> supports;
  1456         rv = stream->ReadObject(true, getter_AddRefs(supports));
  1457         if (NS_FAILED(rv))
  1458             return rv;
  1459         readOriginPrincipal = do_QueryInterface(supports);
  1460         originPrincipal = nsJSPrincipals::get(readOriginPrincipal);
  1463     uint32_t size;
  1464     rv = stream->Read32(&size);
  1465     if (NS_FAILED(rv))
  1466         return rv;
  1468     char* data;
  1469     rv = stream->ReadBytes(size, &data);
  1470     if (NS_FAILED(rv))
  1471         return rv;
  1474         if (scriptp) {
  1475             JSScript *script = JS_DecodeScript(cx, data, size, originPrincipal);
  1476             if (!script)
  1477                 rv = NS_ERROR_OUT_OF_MEMORY;
  1478             else
  1479                 *scriptp = script;
  1480         } else {
  1481             JSObject *funobj = JS_DecodeInterpretedFunction(cx, data, size,
  1482                                                             originPrincipal);
  1483             if (!funobj)
  1484                 rv = NS_ERROR_OUT_OF_MEMORY;
  1485             else
  1486                 *functionObjp = funobj;
  1490     nsMemory::Free(data);
  1491     return rv;
  1494 NS_IMETHODIMP
  1495 nsXPConnect::WriteScript(nsIObjectOutputStream *stream, JSContext *cx, JSScript *script)
  1497     return WriteScriptOrFunction(stream, cx, script, NullPtr());
  1500 NS_IMETHODIMP
  1501 nsXPConnect::ReadScript(nsIObjectInputStream *stream, JSContext *cx, JSScript **scriptp)
  1503     return ReadScriptOrFunction(stream, cx, scriptp, nullptr);
  1506 NS_IMETHODIMP
  1507 nsXPConnect::WriteFunction(nsIObjectOutputStream *stream, JSContext *cx, JSObject *functionObjArg)
  1509     RootedObject functionObj(cx, functionObjArg);
  1510     return WriteScriptOrFunction(stream, cx, nullptr, functionObj);
  1513 NS_IMETHODIMP
  1514 nsXPConnect::ReadFunction(nsIObjectInputStream *stream, JSContext *cx, JSObject **functionObjp)
  1516     return ReadScriptOrFunction(stream, cx, nullptr, functionObjp);
  1519 NS_IMETHODIMP
  1520 nsXPConnect::MarkErrorUnreported(JSContext *cx)
  1522     XPCContext *xpcc = XPCContext::GetXPCContext(cx);
  1523     xpcc->MarkErrorUnreported();
  1524     return NS_OK;
  1527 /* These are here to be callable from a debugger */
  1528 extern "C" {
  1529 JS_EXPORT_API(void) DumpJSStack()
  1531     nsresult rv;
  1532     nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
  1533     if (NS_SUCCEEDED(rv) && xpc)
  1534         xpc->DebugDumpJSStack(true, true, false);
  1535     else
  1536         printf("failed to get XPConnect service!\n");
  1539 JS_EXPORT_API(char*) PrintJSStack()
  1541     nsresult rv;
  1542     nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
  1543     return (NS_SUCCEEDED(rv) && xpc) ?
  1544         xpc->DebugPrintJSStack(true, true, false) :
  1545         nullptr;
  1548 JS_EXPORT_API(void) DumpJSEval(uint32_t frameno, const char* text)
  1550     nsresult rv;
  1551     nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
  1552     if (NS_SUCCEEDED(rv) && xpc)
  1553         xpc->DebugDumpEvalInJSStackFrame(frameno, text);
  1554     else
  1555         printf("failed to get XPConnect service!\n");
  1558 JS_EXPORT_API(void) DumpCompleteHeap()
  1560     nsCOMPtr<nsICycleCollectorListener> listener =
  1561       do_CreateInstance("@mozilla.org/cycle-collector-logger;1");
  1562     if (!listener) {
  1563       NS_WARNING("Failed to create CC logger");
  1564       return;
  1567     nsCOMPtr<nsICycleCollectorListener> alltracesListener;
  1568     listener->AllTraces(getter_AddRefs(alltracesListener));
  1569     if (!alltracesListener) {
  1570       NS_WARNING("Failed to get all traces logger");
  1571       return;
  1574     nsJSContext::CycleCollectNow(alltracesListener);
  1577 } // extern "C"
  1579 namespace xpc {
  1581 bool
  1582 Atob(JSContext *cx, unsigned argc, Value *vp)
  1584     CallArgs args = CallArgsFromVp(argc, vp);
  1585     if (!args.length())
  1586         return true;
  1588     return xpc::Base64Decode(cx, args[0], args.rval());
  1591 bool
  1592 Btoa(JSContext *cx, unsigned argc, Value *vp)
  1594     CallArgs args = CallArgsFromVp(argc, vp);
  1595     if (!args.length())
  1596         return true;
  1598     return xpc::Base64Encode(cx, args[0], args.rval());
  1601 bool
  1602 IsXrayWrapper(JSObject *obj)
  1604     return WrapperFactory::IsXrayWrapper(obj);
  1607 } // namespace xpc
  1609 namespace mozilla {
  1610 namespace dom {
  1612 bool
  1613 IsChromeOrXBL(JSContext* cx, JSObject* /* unused */)
  1615     MOZ_ASSERT(NS_IsMainThread());
  1616     JSCompartment* c = js::GetContextCompartment(cx);
  1618     // For remote XUL, we run XBL in the XUL scope. Given that we care about
  1619     // compat and not security for remote XUL, we just always claim to be XBL.
  1620     //
  1621     // Note that, for performance, we don't check AllowXULXBLForPrincipal here,
  1622     // and instead rely on the fact that AllowXBLScope() only returns false in
  1623     // remote XUL situations.
  1624     return AccessCheck::isChrome(c) || IsXBLScope(c) || !AllowXBLScope(c);
  1627 } // namespace dom
  1628 } // namespace mozilla

mercurial