summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/src/nsXPConnect.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/xpconnect/src/nsXPConnect.cpp')
-rw-r--r--js/xpconnect/src/nsXPConnect.cpp1336
1 files changed, 1336 insertions, 0 deletions
diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp
new file mode 100644
index 000000000..0466175b1
--- /dev/null
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -0,0 +1,1336 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=99: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* High level class and public functions implementation. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Base64.h"
+#include "mozilla/Likely.h"
+#include "mozilla/Unused.h"
+
+#include "xpcprivate.h"
+#include "XPCWrapper.h"
+#include "jsfriendapi.h"
+#include "nsJSEnvironment.h"
+#include "nsThreadUtils.h"
+#include "nsDOMJSUtils.h"
+
+#include "WrapperFactory.h"
+#include "AccessCheck.h"
+
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/DOMException.h"
+#include "mozilla/dom/Exceptions.h"
+#include "mozilla/dom/Promise.h"
+
+#include "nsDOMMutationObserver.h"
+#include "nsICycleCollectorListener.h"
+#include "mozilla/XPTInterfaceInfoManager.h"
+#include "nsIObjectInputStream.h"
+#include "nsIObjectOutputStream.h"
+#include "nsScriptSecurityManager.h"
+#include "nsIPermissionManager.h"
+#include "nsContentUtils.h"
+#include "jsfriendapi.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+using namespace xpc;
+using namespace JS;
+
+NS_IMPL_ISUPPORTS(nsXPConnect, nsIXPConnect)
+
+nsXPConnect* nsXPConnect::gSelf = nullptr;
+bool nsXPConnect::gOnceAliveNowDead = false;
+
+// Global cache of the default script security manager (QI'd to
+// nsIScriptSecurityManager) and the system principal.
+nsIScriptSecurityManager* nsXPConnect::gScriptSecurityManager = nullptr;
+nsIPrincipal* nsXPConnect::gSystemPrincipal = nullptr;
+
+const char XPC_CONTEXT_STACK_CONTRACTID[] = "@mozilla.org/js/xpc/ContextStack;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()
+ : mContext(nullptr),
+ mShuttingDown(false)
+{
+ mContext = XPCJSContext::newXPCJSContext();
+ if (!mContext) {
+ NS_RUNTIMEABORT("Couldn't create XPCJSContext.");
+ }
+}
+
+nsXPConnect::~nsXPConnect()
+{
+ mContext->DeleteSingletonScopes();
+
+ // In order to clean up everything properly, we need to GC twice: once now,
+ // to clean anything that can go away on its own (like the Junk Scope, which
+ // we unrooted above), and once after forcing a bunch of shutdown in
+ // XPConnect, to clean the stuff we forcibly disconnected. The forced
+ // shutdown code defaults to leaking in a number of situations, so we can't
+ // get by with only the second GC. :-(
+ mContext->GarbageCollect(JS::gcreason::XPCONNECT_SHUTDOWN);
+
+ mShuttingDown = true;
+ XPCWrappedNativeScope::SystemIsBeingShutDown();
+
+ // The above causes us to clean up a bunch of XPConnect data structures,
+ // after which point we need to GC to clean everything up. We need to do
+ // this before deleting the XPCJSContext, because doing so destroys the
+ // maps that our finalize callback depends on.
+ mContext->GarbageCollect(JS::gcreason::XPCONNECT_SHUTDOWN);
+
+ NS_RELEASE(gSystemPrincipal);
+ gScriptSecurityManager = nullptr;
+
+ // shutdown the logging system
+ XPC_LOG_FINISH();
+
+ delete mContext;
+
+ gSelf = nullptr;
+ gOnceAliveNowDead = true;
+}
+
+// static
+void
+nsXPConnect::InitStatics()
+{
+ gSelf = new nsXPConnect();
+ gOnceAliveNowDead = false;
+ if (!gSelf->mContext) {
+ NS_RUNTIMEABORT("Couldn't create XPCJSContext.");
+ }
+
+ // Initial extra ref to keep the singleton alive
+ // balanced by explicit call to ReleaseXPConnectSingleton()
+ NS_ADDREF(gSelf);
+
+ // Fire up the SSM.
+ nsScriptSecurityManager::InitStatics();
+ gScriptSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager();
+ gScriptSecurityManager->GetSystemPrincipal(&gSystemPrincipal);
+ MOZ_RELEASE_ASSERT(gSystemPrincipal);
+
+ if (!JS::InitSelfHostedCode(gSelf->mContext->Context()))
+ MOZ_CRASH("InitSelfHostedCode failed");
+ if (!gSelf->mContext->JSContextInitialized(gSelf->mContext->Context()))
+ MOZ_CRASH("JSContextInitialized failed");
+
+ // Initialize our singleton scopes.
+ gSelf->mContext->InitSingletonScopes();
+}
+
+nsXPConnect*
+nsXPConnect::GetSingleton()
+{
+ nsXPConnect* xpc = nsXPConnect::XPConnect();
+ NS_IF_ADDREF(xpc);
+ return xpc;
+}
+
+// static
+void
+nsXPConnect::ReleaseXPConnectSingleton()
+{
+ nsXPConnect* xpc = gSelf;
+ if (xpc) {
+ nsrefcnt cnt;
+ NS_RELEASE2(xpc, cnt);
+ }
+}
+
+// static
+XPCJSContext*
+nsXPConnect::GetContextInstance()
+{
+ nsXPConnect* xpc = XPConnect();
+ return xpc->GetContext();
+}
+
+// static
+bool
+nsXPConnect::IsISupportsDescendant(nsIInterfaceInfo* info)
+{
+ bool found = false;
+ if (info)
+ info->HasAncestor(&NS_GET_IID(nsISupports), &found);
+ return found;
+}
+
+void
+xpc::ErrorReport::Init(JSErrorReport* aReport, const char* aToStringResult,
+ bool aIsChrome, uint64_t aWindowID)
+{
+ mCategory = aIsChrome ? NS_LITERAL_CSTRING("chrome javascript")
+ : NS_LITERAL_CSTRING("content javascript");
+ mWindowID = aWindowID;
+
+ ErrorReportToMessageString(aReport, mErrorMsg);
+ if (mErrorMsg.IsEmpty() && aToStringResult) {
+ AppendUTF8toUTF16(aToStringResult, mErrorMsg);
+ }
+
+ if (!aReport->filename) {
+ mFileName.SetIsVoid(true);
+ } else {
+ mFileName.AssignWithConversion(aReport->filename);
+ }
+
+ mSourceLine.Assign(aReport->linebuf(), aReport->linebufLength());
+ const JSErrorFormatString* efs = js::GetErrorMessage(nullptr, aReport->errorNumber);
+
+ if (efs == nullptr) {
+ mErrorMsgName.AssignASCII("");
+ } else {
+ mErrorMsgName.AssignASCII(efs->name);
+ }
+
+ mLineNumber = aReport->lineno;
+ mColumn = aReport->column;
+ mFlags = aReport->flags;
+ mIsMuted = aReport->isMuted;
+}
+
+void
+xpc::ErrorReport::Init(JSContext* aCx, mozilla::dom::Exception* aException,
+ bool aIsChrome, uint64_t aWindowID)
+{
+ mCategory = aIsChrome ? NS_LITERAL_CSTRING("chrome javascript")
+ : NS_LITERAL_CSTRING("content javascript");
+ mWindowID = aWindowID;
+
+ aException->GetErrorMessage(mErrorMsg);
+
+ aException->GetFilename(aCx, mFileName);
+ if (mFileName.IsEmpty()) {
+ mFileName.SetIsVoid(true);
+ }
+ aException->GetLineNumber(aCx, &mLineNumber);
+ aException->GetColumnNumber(&mColumn);
+
+ mFlags = JSREPORT_EXCEPTION;
+}
+
+static LazyLogModule gJSDiagnostics("JSDiagnostics");
+
+void
+xpc::ErrorReport::LogToConsole()
+{
+ LogToConsoleWithStack(nullptr);
+}
+void
+xpc::ErrorReport::LogToConsoleWithStack(JS::HandleObject aStack)
+{
+ // Log to stdout.
+ if (nsContentUtils::DOMWindowDumpEnabled()) {
+ nsAutoCString error;
+ error.AssignLiteral("JavaScript ");
+ if (JSREPORT_IS_STRICT(mFlags))
+ error.AppendLiteral("strict ");
+ if (JSREPORT_IS_WARNING(mFlags))
+ error.AppendLiteral("warning: ");
+ else
+ error.AppendLiteral("error: ");
+ error.Append(NS_LossyConvertUTF16toASCII(mFileName));
+ error.AppendLiteral(", line ");
+ error.AppendInt(mLineNumber, 10);
+ error.AppendLiteral(": ");
+ error.Append(NS_LossyConvertUTF16toASCII(mErrorMsg));
+
+ fprintf(stderr, "%s\n", error.get());
+ fflush(stderr);
+ }
+
+ MOZ_LOG(gJSDiagnostics,
+ JSREPORT_IS_WARNING(mFlags) ? LogLevel::Warning : LogLevel::Error,
+ ("file %s, line %u\n%s", NS_LossyConvertUTF16toASCII(mFileName).get(),
+ mLineNumber, NS_LossyConvertUTF16toASCII(mErrorMsg).get()));
+
+ // Log to the console. We do this last so that we can simply return if
+ // there's no console service without affecting the other reporting
+ // mechanisms.
+ nsCOMPtr<nsIConsoleService> consoleService =
+ do_GetService(NS_CONSOLESERVICE_CONTRACTID);
+
+ nsCOMPtr<nsIScriptError> errorObject;
+ if (mWindowID && aStack) {
+ // Only set stack on messages related to a document
+ // As we cache messages in the console service,
+ // we have to ensure not leaking them after the related
+ // context is destroyed and we only track document lifecycle for now.
+ errorObject = new nsScriptErrorWithStack(aStack);
+ } else {
+ errorObject = new nsScriptError();
+ }
+ errorObject->SetErrorMessageName(mErrorMsgName);
+ NS_ENSURE_TRUE_VOID(consoleService);
+
+ nsresult rv = errorObject->InitWithWindowID(mErrorMsg, mFileName, mSourceLine,
+ mLineNumber, mColumn, mFlags,
+ mCategory, mWindowID);
+ NS_ENSURE_SUCCESS_VOID(rv);
+ consoleService->LogMessage(errorObject);
+
+}
+
+/* static */
+void
+xpc::ErrorReport::ErrorReportToMessageString(JSErrorReport* aReport,
+ nsAString& aString)
+{
+ aString.Truncate();
+ if (aReport->message()) {
+ JSFlatString* name = js::GetErrorTypeName(CycleCollectedJSContext::Get()->Context(), aReport->exnType);
+ if (name) {
+ AssignJSFlatString(aString, name);
+ aString.AppendLiteral(": ");
+ }
+ aString.Append(NS_ConvertUTF8toUTF16(aReport->message().c_str()));
+ }
+}
+
+/***************************************************************************/
+
+
+nsresult
+nsXPConnect::GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info)
+{
+ return XPTInterfaceInfoManager::GetSingleton()->GetInfoForIID(aIID, info);
+}
+
+nsresult
+nsXPConnect::GetInfoForName(const char * name, nsIInterfaceInfo** info)
+{
+ nsresult rv = XPTInterfaceInfoManager::GetSingleton()->GetInfoForName(name, info);
+ return NS_FAILED(rv) ? NS_OK : NS_ERROR_NO_INTERFACE;
+}
+
+NS_IMETHODIMP
+nsXPConnect::GarbageCollect(uint32_t reason)
+{
+ GetContext()->GarbageCollect(reason);
+ return NS_OK;
+}
+
+void
+xpc_MarkInCCGeneration(nsISupports* aVariant, uint32_t aGeneration)
+{
+ nsCOMPtr<XPCVariant> variant = do_QueryInterface(aVariant);
+ if (variant) {
+ variant->SetCCGeneration(aGeneration);
+ variant->GetJSVal(); // Unmarks gray JSObject.
+ XPCVariant* weak = variant.get();
+ variant = nullptr;
+ if (weak->IsPurple()) {
+ weak->RemovePurple();
+ }
+ }
+}
+
+void
+xpc_TryUnmarkWrappedGrayObject(nsISupports* aWrappedJS)
+{
+ // QIing to nsIXPConnectWrappedJSUnmarkGray may have side effects!
+ nsCOMPtr<nsIXPConnectWrappedJSUnmarkGray> wjsug =
+ do_QueryInterface(aWrappedJS);
+ Unused << wjsug;
+ MOZ_ASSERT(!wjsug, "One should never be able to QI to "
+ "nsIXPConnectWrappedJSUnmarkGray successfully!");
+}
+
+/***************************************************************************/
+/***************************************************************************/
+// nsIXPConnect interface methods...
+
+template<typename T>
+static inline T UnexpectedFailure(T rv)
+{
+ NS_ERROR("This is not supposed to fail!");
+ return rv;
+}
+
+void
+xpc::TraceXPCGlobal(JSTracer* trc, JSObject* obj)
+{
+ if (js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL)
+ mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
+
+ // We might be called from a GC during the creation of a global, before we've
+ // been able to set up the compartment private or the XPCWrappedNativeScope,
+ // so we need to null-check those.
+ xpc::CompartmentPrivate* compartmentPrivate = xpc::CompartmentPrivate::Get(obj);
+ if (compartmentPrivate && compartmentPrivate->scope)
+ compartmentPrivate->scope->TraceInside(trc);
+}
+
+
+namespace xpc {
+
+JSObject*
+CreateGlobalObject(JSContext* cx, const JSClass* clasp, nsIPrincipal* principal,
+ JS::CompartmentOptions& aOptions)
+{
+ MOZ_ASSERT(NS_IsMainThread(), "using a principal off the main thread?");
+ MOZ_ASSERT(principal);
+
+ MOZ_RELEASE_ASSERT(principal != nsContentUtils::GetNullSubjectPrincipal(),
+ "The null subject principal is getting inherited - fix that!");
+
+ RootedObject global(cx,
+ JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal),
+ JS::DontFireOnNewGlobalHook, aOptions));
+ if (!global)
+ return nullptr;
+ JSAutoCompartment ac(cx, global);
+
+ // The constructor automatically attaches the scope to the compartment private
+ // of |global|.
+ (void) new XPCWrappedNativeScope(cx, global);
+
+ if (clasp->flags & JSCLASS_DOM_GLOBAL) {
+#ifdef DEBUG
+ // Verify that the right trace hook is called. Note that this doesn't
+ // work right for wrapped globals, since the tracing situation there is
+ // more complicated. Manual inspection shows that they do the right
+ // thing. Also note that we only check this for JSCLASS_DOM_GLOBAL
+ // classes because xpc::TraceXPCGlobal won't call
+ // TraceProtoAndIfaceCache unless that flag is set.
+ if (!((const js::Class*)clasp)->isWrappedNative())
+ {
+ VerifyTraceProtoAndIfaceCacheCalledTracer trc(cx);
+ TraceChildren(&trc, GCCellPtr(global.get()));
+ MOZ_ASSERT(trc.ok, "Trace hook on global needs to call TraceXPCGlobal for XPConnect compartments.");
+ }
+#endif
+
+ const char* className = clasp->name;
+ AllocateProtoAndIfaceCache(global,
+ (strcmp(className, "Window") == 0 ||
+ strcmp(className, "ChromeWindow") == 0)
+ ? ProtoAndIfaceCache::WindowLike
+ : ProtoAndIfaceCache::NonWindowLike);
+ }
+
+ return global;
+}
+
+void
+InitGlobalObjectOptions(JS::CompartmentOptions& aOptions,
+ nsIPrincipal* aPrincipal)
+{
+ bool shouldDiscardSystemSource = ShouldDiscardSystemSource();
+ bool extraWarningsForSystemJS = ExtraWarningsForSystemJS();
+
+ bool isSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
+
+ if (isSystem) {
+ // Make sure [SecureContext] APIs are visible:
+ aOptions.creationOptions().setSecureContext(true);
+ }
+
+ if (shouldDiscardSystemSource) {
+ bool discardSource = isSystem;
+
+ aOptions.behaviors().setDiscardSource(discardSource);
+ }
+
+ if (extraWarningsForSystemJS) {
+ if (isSystem)
+ aOptions.behaviors().extraWarningsOverride().set(true);
+ }
+}
+
+bool
+InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal, uint32_t aFlags)
+{
+ // Immediately enter the global's compartment so that everything we create
+ // ends up there.
+ JSAutoCompartment ac(aJSContext, aGlobal);
+
+ // Stuff coming through this path always ends up as a DOM global.
+ MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL);
+
+ if (!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) {
+ // XPCCallContext gives us an active request needed to save/restore.
+ if (!CompartmentPrivate::Get(aGlobal)->scope->AttachComponentsObject(aJSContext) ||
+ !XPCNativeWrapper::AttachNewConstructorObject(aJSContext, aGlobal)) {
+ return UnexpectedFailure(false);
+ }
+ }
+
+ if (!(aFlags & nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK))
+ JS_FireOnNewGlobalObject(aJSContext, aGlobal);
+
+ return true;
+}
+
+} // namespace xpc
+
+NS_IMETHODIMP
+nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
+ nsISupports* aCOMObj,
+ nsIPrincipal * aPrincipal,
+ uint32_t aFlags,
+ JS::CompartmentOptions& aOptions,
+ nsIXPConnectJSObjectHolder** _retval)
+{
+ MOZ_ASSERT(aJSContext, "bad param");
+ MOZ_ASSERT(aCOMObj, "bad param");
+ MOZ_ASSERT(_retval, "bad param");
+
+ // We pass null for the 'extra' pointer during global object creation, so
+ // we need to have a principal.
+ MOZ_ASSERT(aPrincipal);
+
+ InitGlobalObjectOptions(aOptions, aPrincipal);
+
+ // Call into XPCWrappedNative to make a new global object, scope, and global
+ // prototype.
+ xpcObjectHelper helper(aCOMObj);
+ MOZ_ASSERT(helper.GetScriptableFlags() & nsIXPCScriptable::IS_GLOBAL_OBJECT);
+ RefPtr<XPCWrappedNative> wrappedGlobal;
+ nsresult rv =
+ XPCWrappedNative::WrapNewGlobal(helper, aPrincipal,
+ aFlags & nsIXPConnect::INIT_JS_STANDARD_CLASSES,
+ aOptions, getter_AddRefs(wrappedGlobal));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Grab a copy of the global and enter its compartment.
+ RootedObject global(aJSContext, wrappedGlobal->GetFlatJSObject());
+ MOZ_ASSERT(JS_IsGlobalObject(global));
+
+ if (!InitGlobalObject(aJSContext, global, aFlags))
+ return UnexpectedFailure(NS_ERROR_FAILURE);
+
+ wrappedGlobal.forget(_retval);
+ return NS_OK;
+}
+
+static nsresult
+NativeInterface2JSObject(HandleObject aScope,
+ nsISupports* aCOMObj,
+ nsWrapperCache* aCache,
+ const nsIID * aIID,
+ bool aAllowWrapping,
+ MutableHandleValue aVal,
+ nsIXPConnectJSObjectHolder** aHolder)
+{
+ AutoJSContext cx;
+ JSAutoCompartment ac(cx, aScope);
+
+ nsresult rv;
+ xpcObjectHelper helper(aCOMObj, aCache);
+ if (!XPCConvert::NativeInterface2JSObject(aVal, aHolder, helper, aIID,
+ aAllowWrapping, &rv))
+ return rv;
+
+ MOZ_ASSERT(aAllowWrapping || !xpc::WrapperFactory::IsXrayWrapper(&aVal.toObject()),
+ "Shouldn't be returning a xray wrapper here");
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPConnect::WrapNative(JSContext * aJSContext,
+ JSObject * aScopeArg,
+ nsISupports* aCOMObj,
+ const nsIID & aIID,
+ JSObject** aRetVal)
+{
+ MOZ_ASSERT(aJSContext, "bad param");
+ MOZ_ASSERT(aScopeArg, "bad param");
+ MOZ_ASSERT(aCOMObj, "bad param");
+
+ RootedObject aScope(aJSContext, aScopeArg);
+ RootedValue v(aJSContext);
+ nsresult rv = NativeInterface2JSObject(aScope, aCOMObj, nullptr, &aIID,
+ true, &v, nullptr);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (!v.isObjectOrNull())
+ return NS_ERROR_FAILURE;
+
+ *aRetVal = v.toObjectOrNull();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPConnect::WrapNativeHolder(JSContext * aJSContext,
+ JSObject * aScopeArg,
+ nsISupports* aCOMObj,
+ const nsIID & aIID,
+ nsIXPConnectJSObjectHolder **aHolder)
+{
+ MOZ_ASSERT(aHolder, "bad param");
+ MOZ_ASSERT(aJSContext, "bad param");
+ MOZ_ASSERT(aScopeArg, "bad param");
+ MOZ_ASSERT(aCOMObj, "bad param");
+
+ RootedObject aScope(aJSContext, aScopeArg);
+ RootedValue v(aJSContext);
+ return NativeInterface2JSObject(aScope, aCOMObj, nullptr, &aIID,
+ true, &v, aHolder);
+}
+
+NS_IMETHODIMP
+nsXPConnect::WrapNativeToJSVal(JSContext* aJSContext,
+ JSObject* aScopeArg,
+ nsISupports* aCOMObj,
+ nsWrapperCache* aCache,
+ const nsIID* aIID,
+ bool aAllowWrapping,
+ MutableHandleValue aVal)
+{
+ MOZ_ASSERT(aJSContext, "bad param");
+ MOZ_ASSERT(aScopeArg, "bad param");
+ MOZ_ASSERT(aCOMObj, "bad param");
+
+ RootedObject aScope(aJSContext, aScopeArg);
+ return NativeInterface2JSObject(aScope, aCOMObj, aCache, aIID,
+ aAllowWrapping, aVal, nullptr);
+}
+
+NS_IMETHODIMP
+nsXPConnect::WrapJS(JSContext * aJSContext,
+ JSObject * aJSObjArg,
+ const nsIID & aIID,
+ void * *result)
+{
+ MOZ_ASSERT(aJSContext, "bad param");
+ MOZ_ASSERT(aJSObjArg, "bad param");
+ MOZ_ASSERT(result, "bad param");
+
+ *result = nullptr;
+
+ RootedObject aJSObj(aJSContext, aJSObjArg);
+ JSAutoCompartment ac(aJSContext, aJSObj);
+
+ nsresult rv = NS_ERROR_UNEXPECTED;
+ if (!XPCConvert::JSObject2NativeInterface(result, aJSObj,
+ &aIID, nullptr, &rv))
+ return rv;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPConnect::JSValToVariant(JSContext* cx,
+ HandleValue aJSVal,
+ nsIVariant** aResult)
+{
+ NS_PRECONDITION(aResult, "bad param");
+
+ RefPtr<XPCVariant> variant = XPCVariant::newVariant(cx, aJSVal);
+ variant.forget(aResult);
+ NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPConnect::WrapJSAggregatedToNative(nsISupports* aOuter,
+ JSContext* aJSContext,
+ JSObject* aJSObjArg,
+ const nsIID& aIID,
+ void** result)
+{
+ MOZ_ASSERT(aOuter, "bad param");
+ MOZ_ASSERT(aJSContext, "bad param");
+ MOZ_ASSERT(aJSObjArg, "bad param");
+ MOZ_ASSERT(result, "bad param");
+
+ *result = nullptr;
+
+ RootedObject aJSObj(aJSContext, aJSObjArg);
+ nsresult rv;
+ if (!XPCConvert::JSObject2NativeInterface(result, aJSObj,
+ &aIID, aOuter, &rv))
+ return rv;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPConnect::GetWrappedNativeOfJSObject(JSContext * aJSContext,
+ JSObject * aJSObjArg,
+ nsIXPConnectWrappedNative** _retval)
+{
+ MOZ_ASSERT(aJSContext, "bad param");
+ MOZ_ASSERT(aJSObjArg, "bad param");
+ MOZ_ASSERT(_retval, "bad param");
+
+ RootedObject aJSObj(aJSContext, aJSObjArg);
+ aJSObj = js::CheckedUnwrap(aJSObj, /* stopAtWindowProxy = */ false);
+ if (!aJSObj || !IS_WN_REFLECTOR(aJSObj)) {
+ *_retval = nullptr;
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<XPCWrappedNative> temp = XPCWrappedNative::Get(aJSObj);
+ temp.forget(_retval);
+ return NS_OK;
+}
+
+already_AddRefed<nsISupports>
+xpc::UnwrapReflectorToISupports(JSObject* reflector)
+{
+ // Unwrap security wrappers, if allowed.
+ reflector = js::CheckedUnwrap(reflector, /* stopAtWindowProxy = */ false);
+ if (!reflector)
+ return nullptr;
+
+ // Try XPCWrappedNatives.
+ if (IS_WN_REFLECTOR(reflector)) {
+ XPCWrappedNative* wn = XPCWrappedNative::Get(reflector);
+ if (!wn)
+ return nullptr;
+ nsCOMPtr<nsISupports> native = wn->Native();
+ return native.forget();
+ }
+
+ // Try DOM objects. This QI without taking a ref first is safe, because
+ // this if non-null our thing will definitely be a DOM object, and we know
+ // their QI to nsISupports doesn't do anything weird.
+ nsCOMPtr<nsISupports> canonical =
+ do_QueryInterface(mozilla::dom::UnwrapDOMObjectToISupports(reflector));
+ return canonical.forget();
+}
+
+NS_IMETHODIMP
+nsXPConnect::GetWrappedNativeOfNativeObject(JSContext * aJSContext,
+ JSObject * aScopeArg,
+ nsISupports* aCOMObj,
+ const nsIID & aIID,
+ nsIXPConnectWrappedNative** _retval)
+{
+ MOZ_ASSERT(aJSContext, "bad param");
+ MOZ_ASSERT(aScopeArg, "bad param");
+ MOZ_ASSERT(aCOMObj, "bad param");
+ MOZ_ASSERT(_retval, "bad param");
+
+ *_retval = nullptr;
+
+ RootedObject aScope(aJSContext, aScopeArg);
+
+ XPCWrappedNativeScope* scope = ObjectScope(aScope);
+ if (!scope)
+ return UnexpectedFailure(NS_ERROR_FAILURE);
+
+ RefPtr<XPCNativeInterface> iface =
+ XPCNativeInterface::GetNewOrUsed(&aIID);
+ if (!iface)
+ return NS_ERROR_FAILURE;
+
+ XPCWrappedNative* wrapper;
+
+ nsresult rv = XPCWrappedNative::GetUsedOnly(aCOMObj, scope, iface, &wrapper);
+ if (NS_FAILED(rv))
+ return NS_ERROR_FAILURE;
+ *_retval = static_cast<nsIXPConnectWrappedNative*>(wrapper);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPConnect::GetCurrentJSStack(nsIStackFrame * *aCurrentJSStack)
+{
+ MOZ_ASSERT(aCurrentJSStack, "bad param");
+
+ nsCOMPtr<nsIStackFrame> currentStack = dom::GetCurrentJSStack();
+ currentStack.forget(aCurrentJSStack);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPConnect::GetCurrentNativeCallContext(nsAXPCNativeCallContext * *aCurrentNativeCallContext)
+{
+ MOZ_ASSERT(aCurrentNativeCallContext, "bad param");
+
+ *aCurrentNativeCallContext = XPCJSContext::Get()->GetCallContext();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPConnect::SetFunctionThisTranslator(const nsIID & aIID,
+ nsIXPCFunctionThisTranslator* aTranslator)
+{
+ XPCJSContext* cx = GetContext();
+ IID2ThisTranslatorMap* map = cx->GetThisTranslatorMap();
+ map->Add(aIID, aTranslator);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPConnect::CreateSandbox(JSContext* cx, nsIPrincipal* principal,
+ JSObject** _retval)
+{
+ *_retval = nullptr;
+
+ RootedValue rval(cx);
+ SandboxOptions options;
+ nsresult rv = CreateSandboxObject(cx, &rval, principal, options);
+ MOZ_ASSERT(NS_FAILED(rv) || !rval.isPrimitive(),
+ "Bad return value from xpc_CreateSandboxObject()!");
+
+ if (NS_SUCCEEDED(rv) && !rval.isPrimitive()) {
+ *_retval = rval.toObjectOrNull();
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsXPConnect::EvalInSandboxObject(const nsAString& source, const char* filename,
+ JSContext* cx, JSObject* sandboxArg,
+ int32_t jsVersion,
+ MutableHandleValue rval)
+{
+#ifdef DEBUG
+ {
+ const char *version = JS_VersionToString(JSVersion(jsVersion));
+ MOZ_ASSERT(version && strcmp(version, "unknown") != 0, "Illegal JS version passed");
+ }
+#endif
+ if (!sandboxArg)
+ return NS_ERROR_INVALID_ARG;
+
+ RootedObject sandbox(cx, sandboxArg);
+ nsCString filenameStr;
+ if (filename) {
+ filenameStr.Assign(filename);
+ } else {
+ filenameStr = NS_LITERAL_CSTRING("x-bogus://XPConnect/Sandbox");
+ }
+ return EvalInSandbox(cx, sandbox, source, filenameStr, 1,
+ JSVersion(jsVersion), rval);
+}
+
+NS_IMETHODIMP
+nsXPConnect::GetWrappedNativePrototype(JSContext* aJSContext,
+ JSObject* aScopeArg,
+ nsIClassInfo* aClassInfo,
+ JSObject** aRetVal)
+{
+ RootedObject aScope(aJSContext, aScopeArg);
+ JSAutoCompartment ac(aJSContext, aScope);
+
+ XPCWrappedNativeScope* scope = ObjectScope(aScope);
+ if (!scope)
+ return UnexpectedFailure(NS_ERROR_FAILURE);
+
+ XPCNativeScriptableCreateInfo sciProto;
+ XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, sciProto);
+
+ AutoMarkingWrappedNativeProtoPtr proto(aJSContext);
+ proto = XPCWrappedNativeProto::GetNewOrUsed(scope, aClassInfo, &sciProto);
+ if (!proto)
+ return UnexpectedFailure(NS_ERROR_FAILURE);
+
+ JSObject* protoObj = proto->GetJSProtoObject();
+ if (!protoObj)
+ return UnexpectedFailure(NS_ERROR_FAILURE);
+
+ *aRetVal = protoObj;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPConnect::DebugDump(int16_t 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));
+ if (mContext) {
+ if (depth)
+ mContext->DebugDump(depth);
+ else
+ XPC_LOG_ALWAYS(("XPCJSContext @ %x", mContext));
+ } else
+ XPC_LOG_ALWAYS(("mContext is null"));
+ XPCWrappedNativeScope::DebugDumpAllScopes(depth);
+ XPC_LOG_OUTDENT();
+#endif
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPConnect::DebugDumpObject(nsISupports* p, int16_t depth)
+{
+#ifdef DEBUG
+ if (!depth)
+ return NS_OK;
+ if (!p) {
+ XPC_LOG_ALWAYS(("*** Cound not dump object with NULL address"));
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsIXPConnect> xpc;
+ nsCOMPtr<nsIXPCWrappedJSClass> wjsc;
+ nsCOMPtr<nsIXPConnectWrappedNative> wn;
+ nsCOMPtr<nsIXPConnectWrappedJS> wjs;
+
+ if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnect),
+ getter_AddRefs(xpc)))) {
+ XPC_LOG_ALWAYS(("Dumping a nsIXPConnect..."));
+ xpc->DebugDump(depth);
+ } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPCWrappedJSClass),
+ getter_AddRefs(wjsc)))) {
+ XPC_LOG_ALWAYS(("Dumping a nsIXPCWrappedJSClass..."));
+ wjsc->DebugDump(depth);
+ } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedNative),
+ getter_AddRefs(wn)))) {
+ XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedNative..."));
+ wn->DebugDump(depth);
+ } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedJS),
+ getter_AddRefs(wjs)))) {
+ XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedJS..."));
+ wjs->DebugDump(depth);
+ } else {
+ XPC_LOG_ALWAYS(("*** Could not dump the nsISupports @ %x", p));
+ }
+#endif
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPConnect::DebugDumpJSStack(bool showArgs,
+ bool showLocals,
+ bool showThisProps)
+{
+ xpc_DumpJSStack(showArgs, showLocals, showThisProps);
+
+ return NS_OK;
+}
+
+char*
+nsXPConnect::DebugPrintJSStack(bool showArgs,
+ bool showLocals,
+ bool showThisProps)
+{
+ JSContext* cx = nsContentUtils::GetCurrentJSContext();
+ if (!cx)
+ printf("there is no JSContext on the nsIThreadJSContextStack!\n");
+ else
+ return xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps);
+
+ return nullptr;
+}
+
+NS_IMETHODIMP
+nsXPConnect::VariantToJS(JSContext* ctx, JSObject* scopeArg, nsIVariant* value,
+ MutableHandleValue _retval)
+{
+ NS_PRECONDITION(ctx, "bad param");
+ NS_PRECONDITION(scopeArg, "bad param");
+ NS_PRECONDITION(value, "bad param");
+
+ RootedObject scope(ctx, scopeArg);
+ MOZ_ASSERT(js::IsObjectInContextCompartment(scope, ctx));
+
+ nsresult rv = NS_OK;
+ if (!XPCVariant::VariantDataToJS(value, &rv, _retval)) {
+ if (NS_FAILED(rv))
+ return rv;
+
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPConnect::JSToVariant(JSContext* ctx, HandleValue value, nsIVariant** _retval)
+{
+ NS_PRECONDITION(ctx, "bad param");
+ NS_PRECONDITION(_retval, "bad param");
+
+ RefPtr<XPCVariant> variant = XPCVariant::newVariant(ctx, value);
+ variant.forget(_retval);
+ if (!(*_retval))
+ return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+nsIPrincipal*
+nsXPConnect::GetPrincipal(JSObject* obj, bool allowShortCircuit) const
+{
+ MOZ_ASSERT(IS_WN_REFLECTOR(obj), "What kind of wrapper is this?");
+
+ XPCWrappedNative* xpcWrapper = XPCWrappedNative::Get(obj);
+ if (xpcWrapper) {
+ if (allowShortCircuit) {
+ nsIPrincipal* result = xpcWrapper->GetObjectPrincipal();
+ if (result) {
+ return result;
+ }
+ }
+
+ // If not, check if it points to an nsIScriptObjectPrincipal
+ nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
+ do_QueryInterface(xpcWrapper->Native());
+ if (objPrin) {
+ nsIPrincipal* result = objPrin->GetPrincipal();
+ if (result) {
+ return result;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+namespace xpc {
+
+bool
+Base64Encode(JSContext* cx, HandleValue val, MutableHandleValue out)
+{
+ MOZ_ASSERT(cx);
+
+ nsAutoCString encodedString;
+ if (!ConvertJSValueToByteString(cx, val, false, encodedString)) {
+ return false;
+ }
+
+ nsAutoCString result;
+ if (NS_FAILED(mozilla::Base64Encode(encodedString, result))) {
+ JS_ReportErrorASCII(cx, "Failed to encode base64 data!");
+ return false;
+ }
+
+ JSString* str = JS_NewStringCopyN(cx, result.get(), result.Length());
+ if (!str)
+ return false;
+
+ out.setString(str);
+ return true;
+}
+
+bool
+Base64Decode(JSContext* cx, HandleValue val, MutableHandleValue out)
+{
+ MOZ_ASSERT(cx);
+
+ nsAutoCString encodedString;
+ if (!ConvertJSValueToByteString(cx, val, false, encodedString)) {
+ return false;
+ }
+
+ nsAutoCString result;
+ if (NS_FAILED(mozilla::Base64Decode(encodedString, result))) {
+ JS_ReportErrorASCII(cx, "Failed to decode base64 string!");
+ return false;
+ }
+
+ JSString* str = JS_NewStringCopyN(cx, result.get(), result.Length());
+ if (!str)
+ return false;
+
+ out.setString(str);
+ return true;
+}
+
+void
+SetLocationForGlobal(JSObject* global, const nsACString& location)
+{
+ MOZ_ASSERT(global);
+ CompartmentPrivate::Get(global)->SetLocation(location);
+}
+
+void
+SetLocationForGlobal(JSObject* global, nsIURI* locationURI)
+{
+ MOZ_ASSERT(global);
+ CompartmentPrivate::Get(global)->SetLocationURI(locationURI);
+}
+
+} // namespace xpc
+
+NS_IMETHODIMP
+nsXPConnect::NotifyDidPaint()
+{
+ JS::NotifyDidPaint(GetContext()->Context());
+ return NS_OK;
+}
+
+static nsresult
+WriteScriptOrFunction(nsIObjectOutputStream* stream, JSContext* cx,
+ JSScript* scriptArg, HandleObject functionObj)
+{
+ // Exactly one of script or functionObj must be given
+ MOZ_ASSERT(!scriptArg != !functionObj);
+
+ RootedScript script(cx, scriptArg);
+ if (!script) {
+ RootedFunction fun(cx, JS_GetObjectFunction(functionObj));
+ script.set(JS_GetFunctionScript(cx, fun));
+ }
+
+ uint8_t flags = 0; // We don't have flags anymore.
+ nsresult rv = stream->Write8(flags);
+ if (NS_FAILED(rv))
+ return rv;
+
+
+ TranscodeBuffer buffer;
+ TranscodeResult code;
+ {
+ if (functionObj)
+ code = EncodeInterpretedFunction(cx, buffer, functionObj);
+ else
+ code = EncodeScript(cx, buffer, script);
+ }
+
+ if (code != TranscodeResult_Ok) {
+ if ((code & TranscodeResult_Failure) != 0)
+ return NS_ERROR_FAILURE;
+ MOZ_ASSERT((code & TranscodeResult_Throw) != 0);
+ JS_ClearPendingException(cx);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ size_t size = buffer.length();
+ if (size > UINT32_MAX)
+ return NS_ERROR_FAILURE;
+ rv = stream->Write32(size);
+ if (NS_SUCCEEDED(rv))
+ rv = stream->WriteBytes(reinterpret_cast<char*>(buffer.begin()), size);
+
+ return rv;
+}
+
+static nsresult
+ReadScriptOrFunction(nsIObjectInputStream* stream, JSContext* cx,
+ JSScript** scriptp, JSObject** functionObjp)
+{
+ // Exactly one of script or functionObj must be given
+ MOZ_ASSERT(!scriptp != !functionObjp);
+
+ uint8_t flags;
+ nsresult rv = stream->Read8(&flags);
+ if (NS_FAILED(rv))
+ return rv;
+
+ // We don't serialize mutedError-ness of scripts, which is fine as long as
+ // we only serialize system and XUL-y things. We can detect this by checking
+ // where the caller wants us to deserialize.
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome() ||
+ CurrentGlobalOrNull(cx) == xpc::CompilationScope());
+
+ uint32_t size;
+ rv = stream->Read32(&size);
+ if (NS_FAILED(rv))
+ return rv;
+
+ char* data;
+ rv = stream->ReadBytes(size, &data);
+ if (NS_FAILED(rv))
+ return rv;
+
+ TranscodeBuffer buffer;
+ buffer.replaceRawBuffer(reinterpret_cast<uint8_t*>(data), size);
+
+ {
+ TranscodeResult code;
+ if (scriptp) {
+ Rooted<JSScript*> script(cx);
+ code = DecodeScript(cx, buffer, &script);
+ if (code == TranscodeResult_Ok)
+ *scriptp = script.get();
+ } else {
+ Rooted<JSFunction*> funobj(cx);
+ code = DecodeInterpretedFunction(cx, buffer, &funobj);
+ if (code == TranscodeResult_Ok)
+ *functionObjp = JS_GetFunctionObject(funobj.get());
+ }
+
+ if (code != TranscodeResult_Ok) {
+ if ((code & TranscodeResult_Failure) != 0)
+ return NS_ERROR_FAILURE;
+ MOZ_ASSERT((code & TranscodeResult_Throw) != 0);
+ JS_ClearPendingException(cx);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsXPConnect::WriteScript(nsIObjectOutputStream* stream, JSContext* cx, JSScript* script)
+{
+ return WriteScriptOrFunction(stream, cx, script, nullptr);
+}
+
+NS_IMETHODIMP
+nsXPConnect::ReadScript(nsIObjectInputStream* stream, JSContext* cx, JSScript** scriptp)
+{
+ return ReadScriptOrFunction(stream, cx, scriptp, nullptr);
+}
+
+NS_IMETHODIMP
+nsXPConnect::WriteFunction(nsIObjectOutputStream* stream, JSContext* cx, JSObject* functionObjArg)
+{
+ RootedObject functionObj(cx, functionObjArg);
+ return WriteScriptOrFunction(stream, cx, nullptr, functionObj);
+}
+
+NS_IMETHODIMP
+nsXPConnect::ReadFunction(nsIObjectInputStream* stream, JSContext* cx, JSObject** functionObjp)
+{
+ return ReadScriptOrFunction(stream, cx, nullptr, functionObjp);
+}
+
+/* These are here to be callable from a debugger */
+extern "C" {
+JS_EXPORT_API(void) DumpJSStack()
+{
+ xpc_DumpJSStack(true, true, false);
+}
+
+JS_EXPORT_API(char*) PrintJSStack()
+{
+ nsresult rv;
+ nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
+ return (NS_SUCCEEDED(rv) && xpc) ?
+ xpc->DebugPrintJSStack(true, true, false) :
+ nullptr;
+}
+
+JS_EXPORT_API(void) DumpCompleteHeap()
+{
+ nsCOMPtr<nsICycleCollectorListener> listener =
+ do_CreateInstance("@mozilla.org/cycle-collector-logger;1");
+ if (!listener) {
+ NS_WARNING("Failed to create CC logger");
+ return;
+ }
+
+ nsCOMPtr<nsICycleCollectorListener> alltracesListener;
+ listener->AllTraces(getter_AddRefs(alltracesListener));
+ if (!alltracesListener) {
+ NS_WARNING("Failed to get all traces logger");
+ return;
+ }
+
+ nsJSContext::CycleCollectNow(alltracesListener);
+}
+
+} // extern "C"
+
+namespace xpc {
+
+bool
+Atob(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ if (!args.length())
+ return true;
+
+ return xpc::Base64Decode(cx, args[0], args.rval());
+}
+
+bool
+Btoa(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ if (!args.length())
+ return true;
+
+ return xpc::Base64Encode(cx, args[0], args.rval());
+}
+
+bool
+IsXrayWrapper(JSObject* obj)
+{
+ return WrapperFactory::IsXrayWrapper(obj);
+}
+
+JSAddonId*
+NewAddonId(JSContext* cx, const nsACString& id)
+{
+ JS::RootedString str(cx, JS_NewStringCopyN(cx, id.BeginReading(), id.Length()));
+ if (!str)
+ return nullptr;
+ return JS::NewAddonId(cx, str);
+}
+
+bool
+SetAddonInterposition(const nsACString& addonIdStr, nsIAddonInterposition* interposition)
+{
+ JSAddonId* addonId;
+ // We enter the junk scope just to allocate a string, which actually will go
+ // in the system zone.
+ AutoJSAPI jsapi;
+ if (!jsapi.Init(xpc::PrivilegedJunkScope()))
+ return false;
+ addonId = NewAddonId(jsapi.cx(), addonIdStr);
+ if (!addonId)
+ return false;
+ return XPCWrappedNativeScope::SetAddonInterposition(jsapi.cx(), addonId, interposition);
+}
+
+bool
+AllowCPOWsInAddon(const nsACString& addonIdStr, bool allow)
+{
+ JSAddonId* addonId;
+ // We enter the junk scope just to allocate a string, which actually will go
+ // in the system zone.
+ AutoJSAPI jsapi;
+ if (!jsapi.Init(xpc::PrivilegedJunkScope()))
+ return false;
+ addonId = NewAddonId(jsapi.cx(), addonIdStr);
+ if (!addonId)
+ return false;
+ return XPCWrappedNativeScope::AllowCPOWsInAddon(jsapi.cx(), addonId, allow);
+}
+
+} // namespace xpc
+
+namespace mozilla {
+namespace dom {
+
+bool
+IsChromeOrXBL(JSContext* cx, JSObject* /* unused */)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ JSCompartment* c = js::GetContextCompartment(cx);
+
+ // For remote XUL, we run XBL in the XUL scope. Given that we care about
+ // compat and not security for remote XUL, we just always claim to be XBL.
+ //
+ // Note that, for performance, we don't check AllowXULXBLForPrincipal here,
+ // and instead rely on the fact that AllowContentXBLScope() only returns false in
+ // remote XUL situations.
+ return AccessCheck::isChrome(c) || IsContentXBLScope(c) || !AllowContentXBLScope(c);
+}
+
+namespace workers {
+extern bool IsCurrentThreadRunningChromeWorker();
+} // namespace workers
+
+bool
+ThreadSafeIsChromeOrXBL(JSContext* cx, JSObject* obj)
+{
+ if (NS_IsMainThread()) {
+ return IsChromeOrXBL(cx, obj);
+ }
+ return workers::IsCurrentThreadRunningChromeWorker();
+}
+
+} // namespace dom
+} // namespace mozilla