summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/src/XPCComponents.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/xpconnect/src/XPCComponents.cpp2665
1 files changed, 2665 insertions, 0 deletions
diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp
new file mode 100644
index 0000000000..77df85b5f8
--- /dev/null
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -0,0 +1,2665 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/* The "Components" xpcom objects for JavaScript. */
+
+#include "xpcprivate.h"
+#include "xpc_make_class.h"
+#include "JSServices.h"
+#include "XPCJSWeakReference.h"
+#include "AccessCheck.h"
+#include "WrapperFactory.h"
+#include "nsJSUtils.h"
+#include "mozJSModuleLoader.h"
+#include "nsContentUtils.h"
+#include "nsCycleCollector.h"
+#include "jsfriendapi.h"
+#include "js/Array.h" // JS::IsArrayObject
+#include "js/CallAndConstruct.h" // JS::IsCallable, JS_CallFunctionName, JS_CallFunctionValue
+#include "js/CharacterEncoding.h"
+#include "js/ContextOptions.h"
+#include "js/friend/WindowProxy.h" // js::ToWindowProxyIfWindow
+#include "js/Object.h" // JS::GetClass, JS::GetCompartment
+#include "js/PropertyAndElement.h" // JS_DefineProperty, JS_DefinePropertyById, JS_Enumerate, JS_GetProperty, JS_GetPropertyById, JS_HasProperty, JS_SetProperty, JS_SetPropertyById
+#include "js/SavedFrameAPI.h"
+#include "js/StructuredClone.h"
+#include "mozilla/AppShutdown.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/LoadContext.h"
+#include "mozilla/Preferences.h"
+#include "nsJSEnvironment.h"
+#include "mozilla/BasePrincipal.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/ResultExtensions.h"
+#include "mozilla/URLPreloader.h"
+#include "mozilla/dom/DOMException.h"
+#include "mozilla/dom/DOMExceptionBinding.h"
+#include "mozilla/dom/Exceptions.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/RemoteObjectProxy.h"
+#include "mozilla/dom/StructuredCloneTags.h"
+#include "mozilla/dom/WindowBinding.h"
+#include "nsZipArchive.h"
+#include "nsWindowMemoryReporter.h"
+#include "nsICycleCollectorListener.h"
+#include "nsIException.h"
+#include "nsIScriptError.h"
+#include "nsPIDOMWindow.h"
+#include "nsGlobalWindow.h"
+#include "nsScriptError.h"
+#include "GeckoProfiler.h"
+#include "ProfilerControl.h"
+#include "mozilla/EditorSpellCheck.h"
+#include "nsCommandLine.h"
+#include "nsCommandParams.h"
+#include "nsPersistentProperties.h"
+#include "nsIDocumentEncoder.h"
+
+using namespace mozilla;
+using namespace JS;
+using namespace js;
+using namespace xpc;
+using mozilla::dom::Exception;
+
+/***************************************************************************/
+// stuff used by all
+
+nsresult xpc::ThrowAndFail(nsresult errNum, JSContext* cx, bool* retval) {
+ XPCThrower::Throw(errNum, cx);
+ *retval = false;
+ return NS_OK;
+}
+
+static bool JSValIsInterfaceOfType(JSContext* cx, HandleValue v, REFNSIID iid) {
+ nsCOMPtr<nsIXPConnectWrappedNative> wn;
+ nsCOMPtr<nsISupports> iface;
+
+ if (v.isPrimitive()) {
+ return false;
+ }
+
+ nsIXPConnect* xpc = nsIXPConnect::XPConnect();
+ RootedObject obj(cx, &v.toObject());
+ return NS_SUCCEEDED(
+ xpc->GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wn))) &&
+ wn &&
+ NS_SUCCEEDED(
+ wn->Native()->QueryInterface(iid, getter_AddRefs(iface))) &&
+ iface;
+}
+
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+
+class nsXPCComponents_Interfaces final : public nsIXPCComponents_Interfaces,
+ public nsIXPCScriptable,
+ public nsIClassInfo {
+ public:
+ // all the interface method declarations...
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIXPCCOMPONENTS_INTERFACES
+ NS_DECL_NSIXPCSCRIPTABLE
+ NS_DECL_NSICLASSINFO
+
+ public:
+ nsXPCComponents_Interfaces();
+
+ private:
+ virtual ~nsXPCComponents_Interfaces();
+};
+
+NS_IMETHODIMP
+nsXPCComponents_Interfaces::GetInterfaces(nsTArray<nsIID>& aArray) {
+ aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Interfaces),
+ NS_GET_IID(nsIXPCScriptable)};
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Interfaces::GetScriptableHelper(nsIXPCScriptable** retval) {
+ *retval = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Interfaces::GetContractID(nsACString& aContractID) {
+ aContractID.SetIsVoid(true);
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Interfaces::GetClassDescription(nsACString& aClassDescription) {
+ aClassDescription.AssignLiteral("XPCComponents_Interfaces");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Interfaces::GetClassID(nsCID** aClassID) {
+ *aClassID = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Interfaces::GetFlags(uint32_t* aFlags) {
+ *aFlags = 0;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Interfaces::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+nsXPCComponents_Interfaces::nsXPCComponents_Interfaces() = default;
+
+nsXPCComponents_Interfaces::~nsXPCComponents_Interfaces() {
+ // empty
+}
+
+NS_IMPL_ISUPPORTS(nsXPCComponents_Interfaces, nsIXPCComponents_Interfaces,
+ nsIXPCScriptable, nsIClassInfo);
+
+// The nsIXPCScriptable map declaration that will generate stubs for us...
+#define XPC_MAP_CLASSNAME nsXPCComponents_Interfaces
+#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Interfaces"
+#define XPC_MAP_FLAGS \
+ (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
+ XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
+#include "xpc_map_end.h" /* This will #undef the above */
+
+NS_IMETHODIMP
+nsXPCComponents_Interfaces::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, JSObject* obj,
+ JS::MutableHandleIdVector properties,
+ bool enumerableOnly, bool* _retval) {
+ if (!properties.reserve(nsXPTInterfaceInfo::InterfaceCount())) {
+ *_retval = false;
+ return NS_OK;
+ }
+
+ for (uint32_t index = 0; index < nsXPTInterfaceInfo::InterfaceCount();
+ index++) {
+ const nsXPTInterfaceInfo* interface = nsXPTInterfaceInfo::ByIndex(index);
+ if (!interface) {
+ continue;
+ }
+
+ const char* name = interface->Name();
+ if (!name) {
+ continue;
+ }
+
+ RootedString idstr(cx, JS_NewStringCopyZ(cx, name));
+ if (!idstr) {
+ *_retval = false;
+ return NS_OK;
+ }
+
+ RootedId id(cx);
+ if (!JS_StringToId(cx, idstr, &id)) {
+ *_retval = false;
+ return NS_OK;
+ }
+
+ properties.infallibleAppend(id);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Interfaces::Resolve(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, JSObject* objArg, jsid idArg,
+ bool* resolvedp, bool* _retval) {
+ RootedObject obj(cx, objArg);
+ RootedId id(cx, idArg);
+
+ if (!id.isString()) {
+ return NS_OK;
+ }
+
+ RootedString str(cx, id.toString());
+ JS::UniqueChars name = JS_EncodeStringToLatin1(cx, str);
+
+ // we only allow interfaces by name here
+ if (name && name[0] != '{') {
+ const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByName(name.get());
+ if (!info) {
+ return NS_OK;
+ }
+
+ RootedValue iidv(cx);
+ if (xpc::IfaceID2JSValue(cx, *info, &iidv)) {
+ *resolvedp = true;
+ *_retval = JS_DefinePropertyById(cx, obj, id, iidv,
+ JSPROP_ENUMERATE | JSPROP_READONLY |
+ JSPROP_PERMANENT | JSPROP_RESOLVING);
+ }
+ }
+ return NS_OK;
+}
+
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+
+class nsXPCComponents_Classes final : public nsIXPCComponents_Classes,
+ public nsIXPCScriptable,
+ public nsIClassInfo {
+ public:
+ // all the interface method declarations...
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIXPCCOMPONENTS_CLASSES
+ NS_DECL_NSIXPCSCRIPTABLE
+ NS_DECL_NSICLASSINFO
+
+ public:
+ nsXPCComponents_Classes();
+
+ private:
+ virtual ~nsXPCComponents_Classes();
+};
+
+/***************************************************************************/
+NS_IMETHODIMP
+nsXPCComponents_Classes::GetInterfaces(nsTArray<nsIID>& aArray) {
+ aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Classes),
+ NS_GET_IID(nsIXPCScriptable)};
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Classes::GetScriptableHelper(nsIXPCScriptable** retval) {
+ *retval = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Classes::GetContractID(nsACString& aContractID) {
+ aContractID.SetIsVoid(true);
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Classes::GetClassDescription(nsACString& aClassDescription) {
+ aClassDescription.AssignLiteral("XPCComponents_Classes");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Classes::GetClassID(nsCID** aClassID) {
+ *aClassID = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Classes::GetFlags(uint32_t* aFlags) {
+ *aFlags = 0;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Classes::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+nsXPCComponents_Classes::nsXPCComponents_Classes() = default;
+
+nsXPCComponents_Classes::~nsXPCComponents_Classes() {
+ // empty
+}
+
+NS_IMPL_ISUPPORTS(nsXPCComponents_Classes, nsIXPCComponents_Classes,
+ nsIXPCScriptable, nsIClassInfo)
+
+// The nsIXPCScriptable map declaration that will generate stubs for us...
+#define XPC_MAP_CLASSNAME nsXPCComponents_Classes
+#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Classes"
+#define XPC_MAP_FLAGS \
+ (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
+ XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
+#include "xpc_map_end.h" /* This will #undef the above */
+
+NS_IMETHODIMP
+nsXPCComponents_Classes::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, JSObject* obj,
+ JS::MutableHandleIdVector properties,
+ bool enumerableOnly, bool* _retval) {
+ nsCOMPtr<nsIComponentRegistrar> compMgr;
+ if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) ||
+ !compMgr) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ nsTArray<nsCString> contractIDs;
+ if (NS_FAILED(compMgr->GetContractIDs(contractIDs))) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ for (const auto& name : contractIDs) {
+ RootedString idstr(cx, JS_NewStringCopyN(cx, name.get(), name.Length()));
+ if (!idstr) {
+ *_retval = false;
+ return NS_OK;
+ }
+
+ RootedId id(cx);
+ if (!JS_StringToId(cx, idstr, &id)) {
+ *_retval = false;
+ return NS_OK;
+ }
+
+ if (!properties.append(id)) {
+ *_retval = false;
+ return NS_OK;
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Classes::Resolve(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, JSObject* objArg, jsid idArg,
+ bool* resolvedp, bool* _retval)
+
+{
+ RootedId id(cx, idArg);
+ RootedObject obj(cx, objArg);
+
+ RootedValue cidv(cx);
+ if (id.isString() && xpc::ContractID2JSValue(cx, id.toString(), &cidv)) {
+ *resolvedp = true;
+ *_retval = JS_DefinePropertyById(cx, obj, id, cidv,
+ JSPROP_ENUMERATE | JSPROP_READONLY |
+ JSPROP_PERMANENT | JSPROP_RESOLVING);
+ }
+ return NS_OK;
+}
+
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+
+// Currently the possible results do not change at runtime, so they are only
+// cached once (unlike ContractIDs, CLSIDs, and IIDs)
+
+class nsXPCComponents_Results final : public nsIXPCComponents_Results,
+ public nsIXPCScriptable,
+ public nsIClassInfo {
+ public:
+ // all the interface method declarations...
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIXPCCOMPONENTS_RESULTS
+ NS_DECL_NSIXPCSCRIPTABLE
+ NS_DECL_NSICLASSINFO
+
+ public:
+ nsXPCComponents_Results();
+
+ private:
+ virtual ~nsXPCComponents_Results();
+};
+
+/***************************************************************************/
+NS_IMETHODIMP
+nsXPCComponents_Results::GetInterfaces(nsTArray<nsIID>& aArray) {
+ aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Results),
+ NS_GET_IID(nsIXPCScriptable)};
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Results::GetScriptableHelper(nsIXPCScriptable** retval) {
+ *retval = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Results::GetContractID(nsACString& aContractID) {
+ aContractID.SetIsVoid(true);
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Results::GetClassDescription(nsACString& aClassDescription) {
+ aClassDescription.AssignLiteral("XPCComponents_Results");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Results::GetClassID(nsCID** aClassID) {
+ *aClassID = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Results::GetFlags(uint32_t* aFlags) {
+ *aFlags = 0;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Results::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+nsXPCComponents_Results::nsXPCComponents_Results() = default;
+
+nsXPCComponents_Results::~nsXPCComponents_Results() {
+ // empty
+}
+
+NS_IMPL_ISUPPORTS(nsXPCComponents_Results, nsIXPCComponents_Results,
+ nsIXPCScriptable, nsIClassInfo)
+
+// The nsIXPCScriptable map declaration that will generate stubs for us...
+#define XPC_MAP_CLASSNAME nsXPCComponents_Results
+#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Results"
+#define XPC_MAP_FLAGS \
+ (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
+ XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
+#include "xpc_map_end.h" /* This will #undef the above */
+
+NS_IMETHODIMP
+nsXPCComponents_Results::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, JSObject* obj,
+ JS::MutableHandleIdVector properties,
+ bool enumerableOnly, bool* _retval) {
+ const char* name;
+ const void* iter = nullptr;
+ while (nsXPCException::IterateNSResults(nullptr, &name, nullptr, &iter)) {
+ RootedString idstr(cx, JS_NewStringCopyZ(cx, name));
+ if (!idstr) {
+ *_retval = false;
+ return NS_OK;
+ }
+
+ RootedId id(cx);
+ if (!JS_StringToId(cx, idstr, &id)) {
+ *_retval = false;
+ return NS_OK;
+ }
+
+ if (!properties.append(id)) {
+ *_retval = false;
+ return NS_OK;
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Results::Resolve(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, JSObject* objArg, jsid idArg,
+ bool* resolvedp, bool* _retval) {
+ RootedObject obj(cx, objArg);
+ RootedId id(cx, idArg);
+ if (!id.isString()) {
+ return NS_OK;
+ }
+
+ JS::UniqueChars name = JS_EncodeStringToLatin1(cx, id.toString());
+ if (name) {
+ const char* rv_name;
+ const void* iter = nullptr;
+ nsresult rv;
+ while (nsXPCException::IterateNSResults(&rv, &rv_name, nullptr, &iter)) {
+ if (!strcmp(name.get(), rv_name)) {
+ *resolvedp = true;
+ if (!JS_DefinePropertyById(cx, obj, id, (uint32_t)rv,
+ JSPROP_ENUMERATE | JSPROP_READONLY |
+ JSPROP_PERMANENT | JSPROP_RESOLVING)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ }
+ }
+ }
+ return NS_OK;
+}
+
+/***************************************************************************/
+// JavaScript Constructor for nsIJSID objects (Components.ID)
+
+class nsXPCComponents_ID final : public nsIXPCComponents_ID,
+ public nsIXPCScriptable,
+ public nsIClassInfo {
+ public:
+ // all the interface method declarations...
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIXPCCOMPONENTS_ID
+ NS_DECL_NSIXPCSCRIPTABLE
+ NS_DECL_NSICLASSINFO
+
+ public:
+ nsXPCComponents_ID();
+
+ private:
+ virtual ~nsXPCComponents_ID();
+ static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, HandleObject obj,
+ const CallArgs& args, bool* _retval);
+};
+
+/***************************************************************************/
+NS_IMETHODIMP
+nsXPCComponents_ID::GetInterfaces(nsTArray<nsIID>& aArray) {
+ aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_ID),
+ NS_GET_IID(nsIXPCScriptable)};
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_ID::GetScriptableHelper(nsIXPCScriptable** retval) {
+ *retval = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_ID::GetContractID(nsACString& aContractID) {
+ aContractID.SetIsVoid(true);
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_ID::GetClassDescription(nsACString& aClassDescription) {
+ aClassDescription.AssignLiteral("XPCComponents_ID");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_ID::GetClassID(nsCID** aClassID) {
+ *aClassID = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_ID::GetFlags(uint32_t* aFlags) {
+ *aFlags = 0;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_ID::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+nsXPCComponents_ID::nsXPCComponents_ID() = default;
+
+nsXPCComponents_ID::~nsXPCComponents_ID() {
+ // empty
+}
+
+NS_IMPL_ISUPPORTS(nsXPCComponents_ID, nsIXPCComponents_ID, nsIXPCScriptable,
+ nsIClassInfo)
+
+// The nsIXPCScriptable map declaration that will generate stubs for us...
+#define XPC_MAP_CLASSNAME nsXPCComponents_ID
+#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_ID"
+#define XPC_MAP_FLAGS \
+ (XPC_SCRIPTABLE_WANT_CALL | XPC_SCRIPTABLE_WANT_CONSTRUCT | \
+ XPC_SCRIPTABLE_WANT_HASINSTANCE | \
+ XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
+#include "xpc_map_end.h" /* This will #undef the above */
+
+NS_IMETHODIMP
+nsXPCComponents_ID::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
+ JSObject* objArg, const CallArgs& args,
+ bool* _retval) {
+ RootedObject obj(cx, objArg);
+ return CallOrConstruct(wrapper, cx, obj, args, _retval);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_ID::Construct(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
+ JSObject* objArg, const CallArgs& args,
+ bool* _retval) {
+ RootedObject obj(cx, objArg);
+ return CallOrConstruct(wrapper, cx, obj, args, _retval);
+}
+
+// static
+nsresult nsXPCComponents_ID::CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, HandleObject obj,
+ const CallArgs& args,
+ bool* _retval) {
+ // make sure we have at least one arg
+
+ if (args.length() < 1) {
+ return ThrowAndFail(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx, _retval);
+ }
+
+ // Prevent non-chrome code from creating ID objects.
+ if (!nsContentUtils::IsCallerChrome()) {
+ return ThrowAndFail(NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED, cx, _retval);
+ }
+
+ // convert the first argument into a string and see if it looks like an id
+
+ JSString* jsstr = ToString(cx, args[0]);
+ if (!jsstr) {
+ return ThrowAndFail(NS_ERROR_XPC_BAD_ID_STRING, cx, _retval);
+ }
+
+ JS::UniqueChars bytes = JS_EncodeStringToLatin1(cx, jsstr);
+ if (!bytes) {
+ return ThrowAndFail(NS_ERROR_XPC_BAD_ID_STRING, cx, _retval);
+ }
+
+ nsID id;
+ if (!id.Parse(bytes.get())) {
+ return ThrowAndFail(NS_ERROR_XPC_BAD_ID_STRING, cx, _retval);
+ }
+
+ // make the new object and return it.
+
+ if (!xpc::ID2JSValue(cx, id, args.rval())) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_ID::HasInstance(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, JSObject* obj, HandleValue val,
+ bool* bp, bool* _retval) {
+ if (bp) {
+ *bp = xpc::JSValue2ID(cx, val).isSome();
+ }
+ return NS_OK;
+}
+
+/***************************************************************************/
+// JavaScript Constructor for Exception objects (Components.Exception)
+
+class nsXPCComponents_Exception final : public nsIXPCComponents_Exception,
+ public nsIXPCScriptable,
+ public nsIClassInfo {
+ public:
+ // all the interface method declarations...
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIXPCCOMPONENTS_EXCEPTION
+ NS_DECL_NSIXPCSCRIPTABLE
+ NS_DECL_NSICLASSINFO
+
+ public:
+ nsXPCComponents_Exception();
+
+ private:
+ virtual ~nsXPCComponents_Exception();
+ static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, HandleObject obj,
+ const CallArgs& args, bool* _retval);
+};
+
+/***************************************************************************/
+NS_IMETHODIMP
+nsXPCComponents_Exception::GetInterfaces(nsTArray<nsIID>& aArray) {
+ aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Exception),
+ NS_GET_IID(nsIXPCScriptable)};
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Exception::GetScriptableHelper(nsIXPCScriptable** retval) {
+ *retval = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Exception::GetContractID(nsACString& aContractID) {
+ aContractID.SetIsVoid(true);
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Exception::GetClassDescription(nsACString& aClassDescription) {
+ aClassDescription.AssignLiteral("XPCComponents_Exception");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Exception::GetClassID(nsCID** aClassID) {
+ *aClassID = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Exception::GetFlags(uint32_t* aFlags) {
+ *aFlags = 0;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Exception::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+nsXPCComponents_Exception::nsXPCComponents_Exception() = default;
+
+nsXPCComponents_Exception::~nsXPCComponents_Exception() {
+ // empty
+}
+
+NS_IMPL_ISUPPORTS(nsXPCComponents_Exception, nsIXPCComponents_Exception,
+ nsIXPCScriptable, nsIClassInfo)
+
+// The nsIXPCScriptable map declaration that will generate stubs for us...
+#define XPC_MAP_CLASSNAME nsXPCComponents_Exception
+#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Exception"
+#define XPC_MAP_FLAGS \
+ (XPC_SCRIPTABLE_WANT_CALL | XPC_SCRIPTABLE_WANT_CONSTRUCT | \
+ XPC_SCRIPTABLE_WANT_HASINSTANCE | \
+ XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
+#include "xpc_map_end.h" /* This will #undef the above */
+
+NS_IMETHODIMP
+nsXPCComponents_Exception::Call(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, JSObject* objArg,
+ const CallArgs& args, bool* _retval) {
+ RootedObject obj(cx, objArg);
+ return CallOrConstruct(wrapper, cx, obj, args, _retval);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Exception::Construct(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, JSObject* objArg,
+ const CallArgs& args, bool* _retval) {
+ RootedObject obj(cx, objArg);
+ return CallOrConstruct(wrapper, cx, obj, args, _retval);
+}
+
+struct MOZ_STACK_CLASS ExceptionArgParser {
+ ExceptionArgParser(JSContext* context, nsIXPConnect* xpconnect)
+ : eMsg("exception"),
+ eResult(NS_ERROR_FAILURE),
+ cx(context),
+ xpc(xpconnect) {}
+
+ // Public exception parameter values. During construction, these are
+ // initialized to the appropriate defaults.
+ const char* eMsg;
+ nsresult eResult;
+ nsCOMPtr<nsIStackFrame> eStack;
+ nsCOMPtr<nsISupports> eData;
+
+ // Parse the constructor arguments into the above |eFoo| parameter values.
+ bool parse(const CallArgs& args) {
+ /*
+ * The Components.Exception takes a series of arguments, all of them
+ * optional:
+ *
+ * Argument 0: Exception message (defaults to 'exception').
+ * Argument 1: Result code (defaults to NS_ERROR_FAILURE) _or_ options
+ * object (see below).
+ * Argument 2: Stack (defaults to the current stack, which we trigger
+ * by leaving this nullptr in the parser).
+ * Argument 3: Optional user data (defaults to nullptr).
+ *
+ * To dig our way out of this clunky API, we now support passing an
+ * options object as the second parameter (as opposed to a result code).
+ * If this is the case, all subsequent arguments are ignored, and the
+ * following properties are parsed out of the object (using the
+ * associated default if the property does not exist):
+ *
+ * result: Result code (see argument 1).
+ * stack: Call stack (see argument 2).
+ * data: User data (see argument 3).
+ */
+ if (args.length() > 0 && !parseMessage(args[0])) {
+ return false;
+ }
+ if (args.length() > 1) {
+ if (args[1].isObject()) {
+ RootedObject obj(cx, &args[1].toObject());
+ return parseOptionsObject(obj);
+ }
+ if (!parseResult(args[1])) {
+ return false;
+ }
+ }
+ if (args.length() > 2) {
+ if (!parseStack(args[2])) {
+ return false;
+ }
+ }
+ if (args.length() > 3) {
+ if (!parseData(args[3])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected:
+ /*
+ * Parsing helpers.
+ */
+
+ bool parseMessage(HandleValue v) {
+ JSString* str = ToString(cx, v);
+ if (!str) {
+ return false;
+ }
+ messageBytes = JS_EncodeStringToLatin1(cx, str);
+ eMsg = messageBytes.get();
+ return !!eMsg;
+ }
+
+ bool parseResult(HandleValue v) {
+ return JS::ToUint32(cx, v, (uint32_t*)&eResult);
+ }
+
+ bool parseStack(HandleValue v) {
+ if (!v.isObject()) {
+ // eStack has already been initialized to null, which is what we want
+ // for any non-object values (including null).
+ return true;
+ }
+
+ RootedObject stackObj(cx, &v.toObject());
+ return NS_SUCCEEDED(xpc->WrapJS(cx, stackObj, NS_GET_IID(nsIStackFrame),
+ getter_AddRefs(eStack)));
+ }
+
+ bool parseData(HandleValue v) {
+ if (!v.isObject()) {
+ // eData has already been initialized to null, which is what we want
+ // for any non-object values (including null).
+ return true;
+ }
+
+ RootedObject obj(cx, &v.toObject());
+ return NS_SUCCEEDED(
+ xpc->WrapJS(cx, obj, NS_GET_IID(nsISupports), getter_AddRefs(eData)));
+ }
+
+ bool parseOptionsObject(HandleObject obj) {
+ RootedValue v(cx);
+
+ if (!getOption(obj, "result", &v) || (!v.isUndefined() && !parseResult(v)))
+ return false;
+
+ if (!getOption(obj, "stack", &v) || (!v.isUndefined() && !parseStack(v)))
+ return false;
+
+ if (!getOption(obj, "data", &v) || (!v.isUndefined() && !parseData(v)))
+ return false;
+
+ return true;
+ }
+
+ bool getOption(HandleObject obj, const char* name, MutableHandleValue rv) {
+ // Look for the property.
+ bool found;
+ if (!JS_HasProperty(cx, obj, name, &found)) {
+ return false;
+ }
+
+ // If it wasn't found, indicate with undefined.
+ if (!found) {
+ rv.setUndefined();
+ return true;
+ }
+
+ // Get the property.
+ return JS_GetProperty(cx, obj, name, rv);
+ }
+
+ /*
+ * Internal data members.
+ */
+
+ // If there's a non-default exception string, hold onto the allocated bytes.
+ JS::UniqueChars messageBytes;
+
+ // Various bits and pieces that are helpful to have around.
+ JSContext* cx;
+ nsIXPConnect* xpc;
+};
+
+// static
+nsresult nsXPCComponents_Exception::CallOrConstruct(
+ nsIXPConnectWrappedNative* wrapper, JSContext* cx, HandleObject obj,
+ const CallArgs& args, bool* _retval) {
+ nsIXPConnect* xpc = nsIXPConnect::XPConnect();
+
+ MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::IsCallerChrome());
+
+ // Parse the arguments to the Exception constructor.
+ ExceptionArgParser parser(cx, xpc);
+ if (!parser.parse(args)) {
+ return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
+ }
+
+ RefPtr<Exception> e = new Exception(nsCString(parser.eMsg), parser.eResult,
+ ""_ns, parser.eStack, parser.eData);
+
+ RootedObject newObj(cx);
+ if (NS_FAILED(xpc->WrapNative(cx, obj, e, NS_GET_IID(nsIException),
+ newObj.address())) ||
+ !newObj) {
+ return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval);
+ }
+
+ args.rval().setObject(*newObj);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Exception::HasInstance(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, JSObject* obj,
+ HandleValue val, bool* bp,
+ bool* _retval) {
+ using namespace mozilla::dom;
+
+ if (bp) {
+ *bp = (val.isObject() && IS_INSTANCE_OF(Exception, &val.toObject())) ||
+ JSValIsInterfaceOfType(cx, val, NS_GET_IID(nsIException));
+ }
+ return NS_OK;
+}
+
+/*******************************************************/
+// JavaScript Constructor for nsIXPCConstructor objects (Components.Constructor)
+
+class nsXPCComponents_Constructor final : public nsIXPCComponents_Constructor,
+ public nsIXPCScriptable,
+ public nsIClassInfo {
+ public:
+ // all the interface method declarations...
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIXPCCOMPONENTS_CONSTRUCTOR
+ NS_DECL_NSIXPCSCRIPTABLE
+ NS_DECL_NSICLASSINFO
+
+ public:
+ nsXPCComponents_Constructor();
+
+ private:
+ virtual ~nsXPCComponents_Constructor();
+ static bool InnerConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
+ static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, HandleObject obj,
+ const CallArgs& args, bool* _retval);
+};
+
+/***************************************************************************/
+NS_IMETHODIMP
+nsXPCComponents_Constructor::GetInterfaces(nsTArray<nsIID>& aArray) {
+ aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Constructor),
+ NS_GET_IID(nsIXPCScriptable)};
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Constructor::GetScriptableHelper(nsIXPCScriptable** retval) {
+ *retval = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Constructor::GetContractID(nsACString& aContractID) {
+ aContractID.SetIsVoid(true);
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Constructor::GetClassDescription(
+ nsACString& aClassDescription) {
+ aClassDescription.AssignLiteral("XPCComponents_Constructor");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Constructor::GetClassID(nsCID** aClassID) {
+ *aClassID = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Constructor::GetFlags(uint32_t* aFlags) {
+ *aFlags = 0;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Constructor::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+nsXPCComponents_Constructor::nsXPCComponents_Constructor() = default;
+
+nsXPCComponents_Constructor::~nsXPCComponents_Constructor() {
+ // empty
+}
+
+NS_IMPL_ISUPPORTS(nsXPCComponents_Constructor, nsIXPCComponents_Constructor,
+ nsIXPCScriptable, nsIClassInfo)
+
+// The nsIXPCScriptable map declaration that will generate stubs for us...
+#define XPC_MAP_CLASSNAME nsXPCComponents_Constructor
+#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Constructor"
+#define XPC_MAP_FLAGS \
+ (XPC_SCRIPTABLE_WANT_CALL | XPC_SCRIPTABLE_WANT_CONSTRUCT | \
+ XPC_SCRIPTABLE_WANT_HASINSTANCE | \
+ XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
+#include "xpc_map_end.h" /* This will #undef the above */
+
+// static
+bool nsXPCComponents_Constructor::InnerConstructor(JSContext* cx, unsigned argc,
+ JS::Value* vp) {
+ CallArgs args = CallArgsFromVp(argc, vp);
+ RootedObject callee(cx, &args.callee());
+
+ // Fetch the property name ids, so we can look them up.
+ XPCJSRuntime* runtime = XPCJSRuntime::Get();
+ HandleId classIDProp = runtime->GetStringID(XPCJSContext::IDX_CLASS_ID);
+ HandleId interfaceIDProp =
+ runtime->GetStringID(XPCJSContext::IDX_INTERFACE_ID);
+ HandleId initializerProp =
+ runtime->GetStringID(XPCJSContext::IDX_INITIALIZER);
+
+ // Get properties ('classID', 'interfaceID', and 'initializer') off the
+ // constructor object.
+ RootedValue classIDv(cx);
+ RootedValue interfaceID(cx);
+ RootedValue initializer(cx);
+ if (!JS_GetPropertyById(cx, callee, classIDProp, &classIDv) ||
+ !JS_GetPropertyById(cx, callee, interfaceIDProp, &interfaceID) ||
+ !JS_GetPropertyById(cx, callee, initializerProp, &initializer)) {
+ return false;
+ }
+ if (!classIDv.isObject() || !interfaceID.isObject()) {
+ XPCThrower::Throw(NS_ERROR_UNEXPECTED, cx);
+ return false;
+ }
+
+ // Call 'createInstance' on the 'classID' object to create the object.
+ RootedValue instancev(cx);
+ RootedObject classID(cx, &classIDv.toObject());
+ if (!JS_CallFunctionName(cx, classID, "createInstance",
+ HandleValueArray(interfaceID), &instancev)) {
+ return false;
+ }
+ if (!instancev.isObject()) {
+ XPCThrower::Throw(NS_ERROR_FAILURE, cx);
+ return false;
+ }
+
+ // Call the method 'initializer' on the instance, passing in our parameters.
+ if (!initializer.isUndefined()) {
+ RootedValue dummy(cx);
+ RootedValue initfunc(cx);
+ RootedId initid(cx);
+ RootedObject instance(cx, &instancev.toObject());
+ if (!JS_ValueToId(cx, initializer, &initid) ||
+ !JS_GetPropertyById(cx, instance, initid, &initfunc) ||
+ !JS_CallFunctionValue(cx, instance, initfunc, args, &dummy)) {
+ return false;
+ }
+ }
+
+ args.rval().set(instancev);
+ return true;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Constructor::Call(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, JSObject* objArg,
+ const CallArgs& args, bool* _retval) {
+ RootedObject obj(cx, objArg);
+ return CallOrConstruct(wrapper, cx, obj, args, _retval);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Constructor::Construct(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, JSObject* objArg,
+ const CallArgs& args, bool* _retval) {
+ RootedObject obj(cx, objArg);
+ return CallOrConstruct(wrapper, cx, obj, args, _retval);
+}
+
+// static
+nsresult nsXPCComponents_Constructor::CallOrConstruct(
+ nsIXPConnectWrappedNative* wrapper, JSContext* cx, HandleObject obj,
+ const CallArgs& args, bool* _retval) {
+ // make sure we have at least one arg
+
+ if (args.length() < 1) {
+ return ThrowAndFail(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx, _retval);
+ }
+
+ // Fetch the property name ids, so we can look them up.
+ XPCJSRuntime* runtime = XPCJSRuntime::Get();
+ HandleId classIDProp = runtime->GetStringID(XPCJSContext::IDX_CLASS_ID);
+ HandleId interfaceIDProp =
+ runtime->GetStringID(XPCJSContext::IDX_INTERFACE_ID);
+ HandleId initializerProp =
+ runtime->GetStringID(XPCJSContext::IDX_INITIALIZER);
+
+ // get the various other object pointers we need
+
+ nsIXPConnect* xpc = nsIXPConnect::XPConnect();
+ XPCWrappedNativeScope* scope = ObjectScope(obj);
+ nsCOMPtr<nsIXPCComponents> comp;
+
+ if (!xpc || !scope || !(comp = scope->GetComponents())) {
+ return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
+ }
+
+ // Prevent non-chrome code from creating constructor objects.
+ if (!nsContentUtils::IsCallerChrome()) {
+ return ThrowAndFail(NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED, cx, _retval);
+ }
+
+ JSFunction* ctorfn = JS_NewFunction(cx, InnerConstructor, 0,
+ JSFUN_CONSTRUCTOR, "XPCOM_Constructor");
+ if (!ctorfn) {
+ return ThrowAndFail(NS_ERROR_OUT_OF_MEMORY, cx, _retval);
+ }
+
+ JS::RootedObject ctor(cx, JS_GetFunctionObject(ctorfn));
+
+ if (args.length() >= 3) {
+ // args[2] is an initializer function or property name
+ RootedString str(cx, ToString(cx, args[2]));
+ if (!JS_DefinePropertyById(
+ cx, ctor, initializerProp, str,
+ JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
+ return ThrowAndFail(NS_ERROR_FAILURE, cx, _retval);
+ }
+ }
+
+ RootedString ifaceName(cx);
+ if (args.length() >= 2) {
+ ifaceName = ToString(cx, args[1]);
+ } else {
+ ifaceName = JS_NewStringCopyZ(cx, "nsISupports");
+ }
+
+ if (!ifaceName) {
+ return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
+ }
+
+ // a new scope to avoid warnings about shadowed names
+ {
+ nsCOMPtr<nsIXPCComponents_Interfaces> ifaces;
+ RootedObject ifacesObj(cx);
+
+ // we do the lookup by asking the Components.interfaces object
+ // for the property with this name - i.e. we let its caching of these
+ // nsIJSIID objects work for us.
+
+ if (NS_FAILED(comp->GetInterfaces(getter_AddRefs(ifaces))) ||
+ NS_FAILED(xpc->WrapNative(cx, obj, ifaces,
+ NS_GET_IID(nsIXPCComponents_Interfaces),
+ ifacesObj.address())) ||
+ !ifacesObj) {
+ return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
+ }
+
+ RootedId id(cx);
+ if (!JS_StringToId(cx, ifaceName, &id)) {
+ return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
+ }
+
+ RootedValue val(cx);
+ if (!JS_GetPropertyById(cx, ifacesObj, id, &val) || val.isPrimitive()) {
+ return ThrowAndFail(NS_ERROR_XPC_BAD_IID, cx, _retval);
+ }
+
+ if (!JS_DefinePropertyById(
+ cx, ctor, interfaceIDProp, val,
+ JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
+ return ThrowAndFail(NS_ERROR_FAILURE, cx, _retval);
+ }
+ }
+
+ // a new scope to avoid warnings about shadowed names
+ {
+ // argv[0] is a contractid name string
+
+ // we do the lookup by asking the Components.classes object
+ // for the property with this name - i.e. we let its caching of these
+ // nsIJSCID objects work for us.
+
+ nsCOMPtr<nsIXPCComponents_Classes> classes;
+ RootedObject classesObj(cx);
+
+ if (NS_FAILED(comp->GetClasses(getter_AddRefs(classes))) ||
+ NS_FAILED(xpc->WrapNative(cx, obj, classes,
+ NS_GET_IID(nsIXPCComponents_Classes),
+ classesObj.address())) ||
+ !classesObj) {
+ return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
+ }
+
+ RootedString str(cx, ToString(cx, args[0]));
+ RootedId id(cx);
+ if (!str || !JS_StringToId(cx, str, &id)) {
+ return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
+ }
+
+ RootedValue val(cx);
+ if (!JS_GetPropertyById(cx, classesObj, id, &val) || val.isPrimitive()) {
+ return ThrowAndFail(NS_ERROR_XPC_BAD_CID, cx, _retval);
+ }
+
+ if (!JS_DefinePropertyById(
+ cx, ctor, classIDProp, val,
+ JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
+ return ThrowAndFail(NS_ERROR_FAILURE, cx, _retval);
+ }
+ }
+
+ args.rval().setObject(*ctor);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Constructor::HasInstance(nsIXPConnectWrappedNative* wrapper,
+ JSContext* cx, JSObject* obj,
+ HandleValue val, bool* isa,
+ bool* _retval) {
+ *isa =
+ val.isObject() && JS_IsNativeFunction(&val.toObject(), InnerConstructor);
+ return NS_OK;
+}
+
+class nsXPCComponents_Utils final : public nsIXPCComponents_Utils,
+ public nsIXPCScriptable {
+ public:
+ // all the interface method declarations...
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIXPCSCRIPTABLE
+ NS_DECL_NSIXPCCOMPONENTS_UTILS
+
+ public:
+ nsXPCComponents_Utils() = default;
+
+ private:
+ virtual ~nsXPCComponents_Utils() = default;
+ nsCOMPtr<nsIXPCComponents_utils_Sandbox> mSandbox;
+};
+
+NS_IMPL_ISUPPORTS(nsXPCComponents_Utils, nsIXPCComponents_Utils,
+ nsIXPCScriptable)
+
+// The nsIXPCScriptable map declaration that will generate stubs for us...
+#define XPC_MAP_CLASSNAME nsXPCComponents_Utils
+#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Utils"
+#define XPC_MAP_FLAGS XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE
+#include "xpc_map_end.h" /* This will #undef the above */
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetSandbox(nsIXPCComponents_utils_Sandbox** aSandbox) {
+ NS_ENSURE_ARG_POINTER(aSandbox);
+ if (!mSandbox) {
+ mSandbox = NewSandboxConstructor();
+ }
+
+ nsCOMPtr<nsIXPCComponents_utils_Sandbox> rval = mSandbox;
+ rval.forget(aSandbox);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CreateServicesCache(JSContext* aCx,
+ MutableHandleValue aServices) {
+ if (JSObject* services = NewJSServices(aCx)) {
+ aServices.setObject(*services);
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::PrintStderr(const nsACString& message) {
+ printf_stderr("%s", PromiseFlatUTF8String(message).get());
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::ReportError(HandleValue error, HandleValue stack,
+ JSContext* cx) {
+ // This function shall never fail! Silently eat any failure conditions.
+
+ nsCOMPtr<nsIConsoleService> console(
+ do_GetService(NS_CONSOLESERVICE_CONTRACTID));
+ if (!console) {
+ return NS_OK;
+ }
+
+ nsGlobalWindowInner* win = CurrentWindowOrNull(cx);
+ const uint64_t innerWindowID = win ? win->WindowID() : 0;
+
+ Rooted<Maybe<Value>> exception(cx, Some(error));
+ if (!innerWindowID) {
+ // Leak mitigation: nsConsoleService::ClearMessagesForWindowID needs
+ // a WindowID for cleanup and exception values could hold arbitrary
+ // objects alive.
+ exception = Nothing();
+ }
+
+ nsCOMPtr<nsIScriptError> scripterr;
+ RootedObject errorObj(cx, error.isObject() ? &error.toObject() : nullptr);
+ if (errorObj) {
+ JS::RootedObject stackVal(cx);
+ JS::RootedObject stackGlobal(cx);
+ FindExceptionStackForConsoleReport(win, error, nullptr, &stackVal,
+ &stackGlobal);
+ if (stackVal) {
+ scripterr = CreateScriptError(win, exception, stackVal, stackGlobal);
+ }
+ }
+
+ nsString fileName;
+ uint32_t lineNo = 0;
+
+ if (!scripterr) {
+ RootedObject stackObj(cx);
+ RootedObject stackGlobal(cx);
+ if (stack.isObject()) {
+ if (!JS::IsMaybeWrappedSavedFrame(&stack.toObject())) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ // |stack| might be a wrapper, but it must be same-compartment with
+ // the current global.
+ stackObj = &stack.toObject();
+ stackGlobal = JS::CurrentGlobalOrNull(cx);
+ js::AssertSameCompartment(stackObj, stackGlobal);
+
+ JSPrincipals* principals =
+ JS::GetRealmPrincipals(js::GetContextRealm(cx));
+
+ if (GetSavedFrameLine(cx, principals, stackObj, &lineNo) !=
+ SavedFrameResult::Ok) {
+ JS_ClearPendingException(cx);
+ }
+
+ RootedString source(cx);
+ nsAutoJSString str;
+ if (GetSavedFrameSource(cx, principals, stackObj, &source) ==
+ SavedFrameResult::Ok &&
+ str.init(cx, source)) {
+ fileName = str;
+ } else {
+ JS_ClearPendingException(cx);
+ }
+ } else {
+ nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack();
+ if (frame) {
+ frame->GetFilename(cx, fileName);
+ lineNo = frame->GetLineNumber(cx);
+ JS::Rooted<JS::Value> stack(cx);
+ nsresult rv = frame->GetNativeSavedFrame(&stack);
+ if (NS_SUCCEEDED(rv) && stack.isObject()) {
+ stackObj = &stack.toObject();
+ MOZ_ASSERT(JS::IsUnwrappedSavedFrame(stackObj));
+ stackGlobal = JS::GetNonCCWObjectGlobal(stackObj);
+ }
+ }
+ }
+
+ if (stackObj) {
+ scripterr = CreateScriptError(win, exception, stackObj, stackGlobal);
+ }
+ }
+
+ if (!scripterr) {
+ scripterr = CreateScriptError(win, exception, nullptr, nullptr);
+ }
+
+ JSErrorReport* err = errorObj ? JS_ErrorFromException(cx, errorObj) : nullptr;
+ if (err) {
+ // It's a proper JS Error
+ nsAutoString fileUni;
+ CopyUTF8toUTF16(mozilla::MakeStringSpan(err->filename), fileUni);
+
+ uint32_t column = err->tokenOffset();
+
+ const char16_t* linebuf = err->linebuf();
+ uint32_t flags = err->isWarning() ? nsIScriptError::warningFlag
+ : nsIScriptError::errorFlag;
+
+ nsresult rv = scripterr->InitWithWindowID(
+ err->message() ? NS_ConvertUTF8toUTF16(err->message().c_str())
+ : EmptyString(),
+ fileUni,
+ linebuf ? nsDependentString(linebuf, err->linebufLength())
+ : EmptyString(),
+ err->lineno, column, flags, "XPConnect JavaScript", innerWindowID,
+ innerWindowID == 0 ? true : false);
+ NS_ENSURE_SUCCESS(rv, NS_OK);
+
+ console->LogMessage(scripterr);
+ return NS_OK;
+ }
+
+ // It's not a JS Error object, so we synthesize as best we're able.
+ RootedString msgstr(cx, ToString(cx, error));
+ if (!msgstr) {
+ return NS_OK;
+ }
+
+ nsAutoJSString msg;
+ if (!msg.init(cx, msgstr)) {
+ return NS_OK;
+ }
+
+ nsresult rv = scripterr->InitWithWindowID(
+ msg, fileName, u""_ns, lineNo, 0, 0, "XPConnect JavaScript",
+ innerWindowID, innerWindowID == 0 ? true : false);
+ NS_ENSURE_SUCCESS(rv, NS_OK);
+
+ console->LogMessage(scripterr);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::EvalInSandbox(
+ const nsAString& source, HandleValue sandboxVal, HandleValue version,
+ const nsACString& filenameArg, int32_t lineNumber,
+ bool enforceFilenameRestrictions, JSContext* cx, uint8_t optionalArgc,
+ MutableHandleValue retval) {
+ RootedObject sandbox(cx);
+ if (!JS_ValueToObject(cx, sandboxVal, &sandbox) || !sandbox) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ // Optional third argument: JS version, as a string, is unused.
+
+ // Optional fourth and fifth arguments: filename and line number.
+ int32_t lineNo = (optionalArgc >= 3) ? lineNumber : 1;
+ nsCString filename;
+ if (!filenameArg.IsVoid()) {
+ filename.Assign(filenameArg);
+ } else {
+ // Get the current source info.
+ nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack();
+ if (frame) {
+ nsString frameFile;
+ frame->GetFilename(cx, frameFile);
+ CopyUTF16toUTF8(frameFile, filename);
+ lineNo = frame->GetLineNumber(cx);
+ }
+ }
+ enforceFilenameRestrictions =
+ (optionalArgc >= 4) ? enforceFilenameRestrictions : true;
+
+ return xpc::EvalInSandbox(cx, sandbox, source, filename, lineNo,
+ enforceFilenameRestrictions, retval);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetUAWidgetScope(nsIPrincipal* principal, JSContext* cx,
+ MutableHandleValue rval) {
+ rval.set(UndefinedValue());
+
+ JSObject* scope = xpc::GetUAWidgetScope(cx, principal);
+
+ rval.set(JS::ObjectValue(*scope));
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetSandboxMetadata(HandleValue sandboxVal, JSContext* cx,
+ MutableHandleValue rval) {
+ if (!sandboxVal.isObject()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ RootedObject sandbox(cx, &sandboxVal.toObject());
+ // We only care about sandboxes here, so CheckedUnwrapStatic is fine.
+ sandbox = js::CheckedUnwrapStatic(sandbox);
+ if (!sandbox || !xpc::IsSandbox(sandbox)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ return xpc::GetSandboxMetadata(cx, sandbox, rval);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::SetSandboxMetadata(HandleValue sandboxVal,
+ HandleValue metadataVal,
+ JSContext* cx) {
+ if (!sandboxVal.isObject()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ RootedObject sandbox(cx, &sandboxVal.toObject());
+ // We only care about sandboxes here, so CheckedUnwrapStatic is fine.
+ sandbox = js::CheckedUnwrapStatic(sandbox);
+ if (!sandbox || !xpc::IsSandbox(sandbox)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ nsresult rv = xpc::SetSandboxMetadata(cx, sandbox, metadataVal);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::Import(const nsACString& registryLocation,
+ HandleValue targetObj, JSContext* cx,
+ uint8_t optionalArgc, MutableHandleValue retval) {
+ RefPtr moduleloader = mozJSModuleLoader::Get();
+ MOZ_ASSERT(moduleloader);
+
+ AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("nsXPCComponents_Utils::Import", OTHER,
+ registryLocation);
+
+ return moduleloader->ImportInto(registryLocation, targetObj, cx, optionalArgc,
+ retval);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::IsModuleLoaded(const nsACString& aResourceURI,
+ bool* retval) {
+ RefPtr moduleloader = mozJSModuleLoader::Get();
+ MOZ_ASSERT(moduleloader);
+ return moduleloader->IsModuleLoaded(aResourceURI, retval);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::IsJSModuleLoaded(const nsACString& aResourceURI,
+ bool* retval) {
+ RefPtr moduleloader = mozJSModuleLoader::Get();
+ MOZ_ASSERT(moduleloader);
+ return moduleloader->IsJSModuleLoaded(aResourceURI, retval);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::IsESModuleLoaded(const nsACString& aResourceURI,
+ bool* retval) {
+ RefPtr moduleloader = mozJSModuleLoader::Get();
+ MOZ_ASSERT(moduleloader);
+ return moduleloader->IsESModuleLoaded(aResourceURI, retval);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::Unload(const nsACString& registryLocation) {
+ RefPtr moduleloader = mozJSModuleLoader::Get();
+ MOZ_ASSERT(moduleloader);
+ return moduleloader->Unload(registryLocation);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::ImportGlobalProperties(HandleValue aPropertyList,
+ JSContext* cx) {
+ // Ensure we're working in the scripted caller's realm. This is not guaranteed
+ // to be the current realm because we switch realms when calling cross-realm
+ // functions.
+ RootedObject global(cx, JS::GetScriptedCallerGlobal(cx));
+ MOZ_ASSERT(global);
+ js::AssertSameCompartment(cx, global);
+ JSAutoRealm ar(cx, global);
+
+ // Don't allow doing this if the global is a Window.
+ nsGlobalWindowInner* win;
+ if (NS_SUCCEEDED(UNWRAP_NON_WRAPPER_OBJECT(Window, global, win))) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ GlobalProperties options;
+ NS_ENSURE_TRUE(aPropertyList.isObject(), NS_ERROR_INVALID_ARG);
+
+ RootedObject propertyList(cx, &aPropertyList.toObject());
+ bool isArray;
+ if (NS_WARN_IF(!JS::IsArrayObject(cx, propertyList, &isArray))) {
+ return NS_ERROR_FAILURE;
+ }
+ if (NS_WARN_IF(!isArray)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ if (!options.Parse(cx, propertyList) ||
+ !options.DefineInXPCComponents(cx, global)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetWeakReference(HandleValue object, JSContext* cx,
+ xpcIJSWeakReference** _retval) {
+ RefPtr<xpcJSWeakReference> ref = new xpcJSWeakReference();
+ nsresult rv = ref->Init(cx, object);
+ NS_ENSURE_SUCCESS(rv, rv);
+ ref.forget(_retval);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::ForceGC(JSContext* aCx) {
+ PrepareForFullGC(aCx);
+ NonIncrementalGC(aCx, GCOptions::Normal, GCReason::COMPONENT_UTILS);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::ForceCC(nsICycleCollectorListener* listener) {
+ nsJSContext::CycleCollectNow(CCReason::API, listener);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CreateCCLogger(nsICycleCollectorListener** aListener) {
+ NS_ENSURE_ARG_POINTER(aListener);
+ nsCOMPtr<nsICycleCollectorListener> logger = nsCycleCollector_createLogger();
+ logger.forget(aListener);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::FinishCC() {
+ nsCycleCollector_finishAnyCurrentCollection();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CcSlice(int64_t budget) {
+ nsJSContext::RunCycleCollectorWorkSlice(budget);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetMaxCCSliceTimeSinceClear(int32_t* out) {
+ *out = nsJSContext::GetMaxCCSliceTimeSinceClear();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::ClearMaxCCTime() {
+ nsJSContext::ClearMaxCCSliceTime();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::ForceShrinkingGC(JSContext* aCx) {
+ PrepareForFullGC(aCx);
+ NonIncrementalGC(aCx, GCOptions::Shrink, GCReason::COMPONENT_UTILS);
+ return NS_OK;
+}
+
+class PreciseGCRunnable : public Runnable {
+ public:
+ PreciseGCRunnable(nsIScheduledGCCallback* aCallback, bool aShrinking)
+ : mozilla::Runnable("PreciseGCRunnable"),
+ mCallback(aCallback),
+ mShrinking(aShrinking) {}
+
+ NS_IMETHOD Run() override {
+ nsJSContext::GarbageCollectNow(
+ GCReason::COMPONENT_UTILS,
+ mShrinking ? nsJSContext::ShrinkingGC : nsJSContext::NonShrinkingGC);
+
+ mCallback->Callback();
+ return NS_OK;
+ }
+
+ private:
+ nsCOMPtr<nsIScheduledGCCallback> mCallback;
+ bool mShrinking;
+};
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::SchedulePreciseGC(nsIScheduledGCCallback* aCallback) {
+ RefPtr<PreciseGCRunnable> event = new PreciseGCRunnable(aCallback, false);
+ return NS_DispatchToMainThread(event);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::SchedulePreciseShrinkingGC(
+ nsIScheduledGCCallback* aCallback) {
+ RefPtr<PreciseGCRunnable> event = new PreciseGCRunnable(aCallback, true);
+ return NS_DispatchToMainThread(event);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::UnlinkGhostWindows() {
+#ifdef DEBUG
+ nsWindowMemoryReporter::UnlinkGhostWindows();
+
+ if (XRE_IsParentProcess()) {
+ nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService();
+ if (obsvc) {
+ obsvc->NotifyObservers(nullptr, "child-ghost-request", nullptr);
+ }
+ }
+
+ return NS_OK;
+#else
+ return NS_ERROR_NOT_IMPLEMENTED;
+#endif
+}
+
+#ifdef NS_FREE_PERMANENT_DATA
+struct IntentionallyLeakedObject {
+ MOZ_COUNTED_DEFAULT_CTOR(IntentionallyLeakedObject)
+
+ MOZ_COUNTED_DTOR(IntentionallyLeakedObject)
+};
+#endif
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::IntentionallyLeak() {
+#ifdef NS_FREE_PERMANENT_DATA
+ Unused << new IntentionallyLeakedObject();
+ return NS_OK;
+#else
+ return NS_ERROR_NOT_IMPLEMENTED;
+#endif
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetJSTestingFunctions(JSContext* cx,
+ MutableHandleValue retval) {
+ JSObject* obj = js::GetTestingFunctions(cx);
+ if (!obj) {
+ return NS_ERROR_XPC_JAVASCRIPT_ERROR;
+ }
+ retval.setObject(*obj);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetFunctionSourceLocation(HandleValue funcValue,
+ JSContext* cx,
+ MutableHandleValue retval) {
+ NS_ENSURE_TRUE(funcValue.isObject(), NS_ERROR_INVALID_ARG);
+
+ nsAutoString filename;
+ uint32_t lineNumber;
+ {
+ RootedObject funcObj(cx, UncheckedUnwrap(&funcValue.toObject()));
+ JSAutoRealm ar(cx, funcObj);
+
+ Rooted<JSFunction*> func(cx, JS_GetObjectFunction(funcObj));
+ NS_ENSURE_TRUE(func, NS_ERROR_INVALID_ARG);
+
+ RootedScript script(cx, JS_GetFunctionScript(cx, func));
+ NS_ENSURE_TRUE(func, NS_ERROR_FAILURE);
+
+ AppendUTF8toUTF16(nsDependentCString(JS_GetScriptFilename(script)),
+ filename);
+ lineNumber = JS_GetScriptBaseLineNumber(cx, script) + 1;
+ }
+
+ RootedObject res(cx, JS_NewPlainObject(cx));
+ NS_ENSURE_TRUE(res, NS_ERROR_OUT_OF_MEMORY);
+
+ RootedValue filenameVal(cx);
+ if (!xpc::NonVoidStringToJsval(cx, filename, &filenameVal) ||
+ !JS_DefineProperty(cx, res, "filename", filenameVal, JSPROP_ENUMERATE)) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (!JS_DefineProperty(cx, res, "lineNumber", lineNumber, JSPROP_ENUMERATE)) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ retval.setObject(*res);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CallFunctionWithAsyncStack(HandleValue function,
+ nsIStackFrame* stack,
+ const nsAString& asyncCause,
+ JSContext* cx,
+ MutableHandleValue retval) {
+ nsresult rv;
+
+ if (!stack || asyncCause.IsEmpty()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ JS::Rooted<JS::Value> asyncStack(cx);
+ rv = stack->GetNativeSavedFrame(&asyncStack);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ if (!asyncStack.isObject()) {
+ JS_ReportErrorASCII(cx, "Must use a native JavaScript stack frame");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ JS::Rooted<JSObject*> asyncStackObj(cx, &asyncStack.toObject());
+
+ NS_ConvertUTF16toUTF8 utf8Cause(asyncCause);
+ JS::AutoSetAsyncStackForNewCalls sas(
+ cx, asyncStackObj, utf8Cause.get(),
+ JS::AutoSetAsyncStackForNewCalls::AsyncCallKind::EXPLICIT);
+
+ if (!JS_CallFunctionValue(cx, nullptr, function,
+ JS::HandleValueArray::empty(), retval)) {
+ return NS_ERROR_XPC_JAVASCRIPT_ERROR;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetGlobalForObject(HandleValue object, JSContext* cx,
+ MutableHandleValue retval) {
+ // First argument must be an object.
+ if (object.isPrimitive()) {
+ return NS_ERROR_XPC_BAD_CONVERT_JS;
+ }
+
+ // When getting the global for a cross-compartment wrapper, we really want
+ // a wrapper for the foreign global. So we need to unwrap before getting the
+ // global and then wrap the result.
+ Rooted<JSObject*> obj(cx, &object.toObject());
+ obj = JS::GetNonCCWObjectGlobal(js::UncheckedUnwrap(obj));
+
+ if (!JS_WrapObject(cx, &obj)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // Get the WindowProxy if necessary.
+ obj = js::ToWindowProxyIfWindow(obj);
+
+ retval.setObject(*obj);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::IsProxy(HandleValue vobj, JSContext* cx, bool* rval) {
+ if (!vobj.isObject()) {
+ *rval = false;
+ return NS_OK;
+ }
+
+ RootedObject obj(cx, &vobj.toObject());
+ // We need to do a dynamic unwrap, because we apparently want to treat
+ // "failure to unwrap" differently from "not a proxy" (throw for the former,
+ // return false for the latter).
+ obj = js::CheckedUnwrapDynamic(obj, cx, /* stopAtWindowProxy = */ false);
+ NS_ENSURE_TRUE(obj, NS_ERROR_FAILURE);
+
+ *rval = js::IsScriptedProxy(obj);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::ExportFunction(HandleValue vfunction, HandleValue vscope,
+ HandleValue voptions, JSContext* cx,
+ MutableHandleValue rval) {
+ if (!xpc::ExportFunction(cx, vfunction, vscope, voptions, rval)) {
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CreateObjectIn(HandleValue vobj, HandleValue voptions,
+ JSContext* cx, MutableHandleValue rval) {
+ RootedObject optionsObject(
+ cx, voptions.isObject() ? &voptions.toObject() : nullptr);
+ CreateObjectInOptions options(cx, optionsObject);
+ if (voptions.isObject() && !options.Parse()) {
+ return NS_ERROR_FAILURE;
+ }
+
+ if (!xpc::CreateObjectIn(cx, vobj, options, rval)) {
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::MakeObjectPropsNormal(HandleValue vobj, JSContext* cx) {
+ if (!cx) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // first argument must be an object
+ if (vobj.isPrimitive()) {
+ return NS_ERROR_XPC_BAD_CONVERT_JS;
+ }
+
+ RootedObject obj(cx, js::UncheckedUnwrap(&vobj.toObject()));
+ JSAutoRealm ar(cx, obj);
+ Rooted<IdVector> ida(cx, IdVector(cx));
+ if (!JS_Enumerate(cx, obj, &ida)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ RootedId id(cx);
+ RootedValue v(cx);
+ for (size_t i = 0; i < ida.length(); ++i) {
+ id = ida[i];
+
+ if (!JS_GetPropertyById(cx, obj, id, &v)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ if (v.isPrimitive()) {
+ continue;
+ }
+
+ RootedObject propobj(cx, &v.toObject());
+ // TODO Deal with non-functions.
+ if (!js::IsWrapper(propobj) || !JS::IsCallable(propobj)) {
+ continue;
+ }
+
+ FunctionForwarderOptions forwarderOptions;
+ if (!NewFunctionForwarder(cx, id, propobj, forwarderOptions, &v) ||
+ !JS_SetPropertyById(cx, obj, id, v))
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::IsDeadWrapper(HandleValue obj, bool* out) {
+ *out = false;
+ if (obj.isPrimitive()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ // We should never have cross-compartment wrappers for dead wrappers.
+ MOZ_ASSERT_IF(js::IsCrossCompartmentWrapper(&obj.toObject()),
+ !JS_IsDeadWrapper(js::UncheckedUnwrap(&obj.toObject())));
+
+ *out = JS_IsDeadWrapper(&obj.toObject());
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::IsRemoteProxy(HandleValue val, bool* out) {
+ if (val.isObject()) {
+ *out = dom::IsRemoteObjectProxy(UncheckedUnwrap(&val.toObject()));
+ ;
+ } else {
+ *out = false;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::RecomputeWrappers(HandleValue vobj, JSContext* cx) {
+ // Determine the compartment of the given object, if any.
+ JS::Compartment* c =
+ vobj.isObject()
+ ? JS::GetCompartment(js::UncheckedUnwrap(&vobj.toObject()))
+ : nullptr;
+
+ // If no compartment was given, recompute all.
+ if (!c) {
+ js::RecomputeWrappers(cx, js::AllCompartments(), js::AllCompartments());
+ // Otherwise, recompute wrappers for the given compartment.
+ } else {
+ js::RecomputeWrappers(cx, js::SingleCompartment(c),
+ js::AllCompartments()) &&
+ js::RecomputeWrappers(cx, js::AllCompartments(),
+ js::SingleCompartment(c));
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::SetWantXrays(HandleValue vscope, JSContext* cx) {
+ if (!vscope.isObject()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject());
+ MOZ_RELEASE_ASSERT(!AccessCheck::isChrome(scopeObj),
+ "Don't call setWantXrays on system-principal scopes");
+ JS::Compartment* compartment = JS::GetCompartment(scopeObj);
+ CompartmentPrivate::Get(scopeObj)->wantXrays = true;
+ bool ok = js::RecomputeWrappers(cx, js::SingleCompartment(compartment),
+ js::AllCompartments());
+ NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::Dispatch(HandleValue runnableArg, HandleValue scope,
+ JSContext* cx) {
+ RootedValue runnable(cx, runnableArg);
+ // Enter the given realm, if any, and rewrap runnable.
+ Maybe<JSAutoRealm> ar;
+ if (scope.isObject()) {
+ JSObject* scopeObj = js::UncheckedUnwrap(&scope.toObject());
+ if (!scopeObj) {
+ return NS_ERROR_FAILURE;
+ }
+ ar.emplace(cx, scopeObj);
+ if (!JS_WrapValue(cx, &runnable)) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ // Get an XPCWrappedJS for |runnable|.
+ if (!runnable.isObject()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ RootedObject runnableObj(cx, &runnable.toObject());
+ nsCOMPtr<nsIRunnable> run;
+ nsresult rv = nsXPConnect::XPConnect()->WrapJS(
+ cx, runnableObj, NS_GET_IID(nsIRunnable), getter_AddRefs(run));
+ NS_ENSURE_SUCCESS(rv, rv);
+ MOZ_ASSERT(run);
+
+ // Dispatch.
+ return NS_DispatchToMainThread(run);
+}
+
+#define GENERATE_JSCONTEXTOPTION_GETTER_SETTER(_attr, _getter, _setter) \
+ NS_IMETHODIMP \
+ nsXPCComponents_Utils::Get##_attr(JSContext* cx, bool* aValue) { \
+ *aValue = ContextOptionsRef(cx)._getter(); \
+ return NS_OK; \
+ } \
+ NS_IMETHODIMP \
+ nsXPCComponents_Utils::Set##_attr(JSContext* cx, bool aValue) { \
+ ContextOptionsRef(cx)._setter(aValue); \
+ return NS_OK; \
+ }
+
+GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Strict_mode, strictMode, setStrictMode)
+
+#undef GENERATE_JSCONTEXTOPTION_GETTER_SETTER
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::SetGCZeal(int32_t aValue, JSContext* cx) {
+#ifdef JS_GC_ZEAL
+ JS_SetGCZeal(cx, uint8_t(aValue), JS_DEFAULT_ZEAL_FREQ);
+#endif
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetIsInAutomation(bool* aResult) {
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ *aResult = xpc::IsInAutomation();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::ExitIfInAutomation() {
+ NS_ENSURE_TRUE(xpc::IsInAutomation(), NS_ERROR_FAILURE);
+
+ profiler_shutdown(IsFastShutdown::Yes);
+
+ mozilla::AppShutdown::DoImmediateExit();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CrashIfNotInAutomation() {
+ xpc::CrashIfNotInAutomation();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::NukeSandbox(HandleValue obj, JSContext* cx) {
+ AUTO_PROFILER_LABEL("nsXPCComponents_Utils::NukeSandbox", OTHER);
+ NS_ENSURE_TRUE(obj.isObject(), NS_ERROR_INVALID_ARG);
+ JSObject* wrapper = &obj.toObject();
+ NS_ENSURE_TRUE(IsWrapper(wrapper), NS_ERROR_INVALID_ARG);
+ RootedObject sb(cx, UncheckedUnwrap(wrapper));
+ NS_ENSURE_TRUE(IsSandbox(sb), NS_ERROR_INVALID_ARG);
+
+ xpc::NukeAllWrappersForRealm(cx, GetNonCCWObjectRealm(sb));
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::BlockScriptForGlobal(HandleValue globalArg,
+ JSContext* cx) {
+ NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG);
+ RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(),
+ /* stopAtWindowProxy = */ false));
+ NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG);
+ if (xpc::GetObjectPrincipal(global)->IsSystemPrincipal()) {
+ JS_ReportErrorASCII(cx, "Script may not be disabled for system globals");
+ return NS_ERROR_FAILURE;
+ }
+ Scriptability::Get(global).Block();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::UnblockScriptForGlobal(HandleValue globalArg,
+ JSContext* cx) {
+ NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG);
+ RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(),
+ /* stopAtWindowProxy = */ false));
+ NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG);
+ if (xpc::GetObjectPrincipal(global)->IsSystemPrincipal()) {
+ JS_ReportErrorASCII(cx, "Script may not be disabled for system globals");
+ return NS_ERROR_FAILURE;
+ }
+ Scriptability::Get(global).Unblock();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::IsOpaqueWrapper(HandleValue obj, bool* aRetval) {
+ *aRetval =
+ obj.isObject() && xpc::WrapperFactory::IsOpaqueWrapper(&obj.toObject());
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::IsXrayWrapper(HandleValue obj, bool* aRetval) {
+ *aRetval =
+ obj.isObject() && xpc::WrapperFactory::IsXrayWrapper(&obj.toObject());
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::WaiveXrays(HandleValue aVal, JSContext* aCx,
+ MutableHandleValue aRetval) {
+ RootedValue value(aCx, aVal);
+ if (!xpc::WrapperFactory::WaiveXrayAndWrap(aCx, &value)) {
+ return NS_ERROR_FAILURE;
+ }
+ aRetval.set(value);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::UnwaiveXrays(HandleValue aVal, JSContext* aCx,
+ MutableHandleValue aRetval) {
+ if (!aVal.isObject()) {
+ aRetval.set(aVal);
+ return NS_OK;
+ }
+
+ RootedObject obj(aCx, js::UncheckedUnwrap(&aVal.toObject()));
+ if (!JS_WrapObject(aCx, &obj)) {
+ return NS_ERROR_FAILURE;
+ }
+ aRetval.setObject(*obj);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetClassName(HandleValue aObj, bool aUnwrap,
+ JSContext* aCx, char** aRv) {
+ if (!aObj.isObject()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ RootedObject obj(aCx, &aObj.toObject());
+ if (aUnwrap) {
+ obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
+ }
+ *aRv = NS_xstrdup(JS::GetClass(obj)->name);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetDOMClassInfo(const nsAString& aClassName,
+ nsIClassInfo** aClassInfo) {
+ *aClassInfo = nullptr;
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetIncumbentGlobal(HandleValue aCallback, JSContext* aCx,
+ MutableHandleValue aOut) {
+ nsCOMPtr<nsIGlobalObject> global = mozilla::dom::GetIncumbentGlobal();
+ RootedValue globalVal(aCx);
+
+ if (!global) {
+ globalVal = NullValue();
+ } else {
+ // Note: We rely on the wrap call for outerization.
+ globalVal = ObjectValue(*global->GetGlobalJSObject());
+ if (!JS_WrapValue(aCx, &globalVal)) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ // Invoke the callback, if passed.
+ if (aCallback.isObject()) {
+ RootedValue ignored(aCx);
+ if (!JS_CallFunctionValue(aCx, nullptr, aCallback,
+ JS::HandleValueArray(globalVal), &ignored)) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ aOut.set(globalVal);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetDebugName(HandleValue aObj, JSContext* aCx,
+ nsACString& aOut) {
+ if (!aObj.isObject()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ RootedObject obj(aCx, &aObj.toObject());
+ aOut = xpc::GetFunctionName(aCx, obj);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetWatchdogTimestamp(const nsAString& aCategory,
+ PRTime* aOut) {
+ WatchdogTimestampCategory category;
+ if (aCategory.EqualsLiteral("ContextStateChange")) {
+ category = TimestampContextStateChange;
+ } else if (aCategory.EqualsLiteral("WatchdogWakeup")) {
+ category = TimestampWatchdogWakeup;
+ } else if (aCategory.EqualsLiteral("WatchdogHibernateStart")) {
+ category = TimestampWatchdogHibernateStart;
+ } else if (aCategory.EqualsLiteral("WatchdogHibernateStop")) {
+ category = TimestampWatchdogHibernateStop;
+ } else {
+ return NS_ERROR_INVALID_ARG;
+ }
+ *aOut = XPCJSContext::Get()->GetWatchdogTimestamp(category);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetJSEngineTelemetryValue(JSContext* cx,
+ MutableHandleValue rval) {
+ RootedObject obj(cx, JS_NewPlainObject(cx));
+ if (!obj) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ // No JS engine telemetry in use at the moment.
+
+ rval.setObject(*obj);
+ return NS_OK;
+}
+
+bool xpc::CloneInto(JSContext* aCx, HandleValue aValue, HandleValue aScope,
+ HandleValue aOptions, MutableHandleValue aCloned) {
+ if (!aScope.isObject()) {
+ return false;
+ }
+
+ RootedObject scope(aCx, &aScope.toObject());
+ // The scope could be a Window, so we need to CheckedUnwrapDynamic.
+ scope = js::CheckedUnwrapDynamic(scope, aCx);
+ if (!scope) {
+ JS_ReportErrorASCII(aCx, "Permission denied to clone object into scope");
+ return false;
+ }
+
+ if (!aOptions.isUndefined() && !aOptions.isObject()) {
+ JS_ReportErrorASCII(aCx, "Invalid argument");
+ return false;
+ }
+
+ RootedObject optionsObject(
+ aCx, aOptions.isObject() ? &aOptions.toObject() : nullptr);
+ StackScopedCloneOptions options(aCx, optionsObject);
+ if (aOptions.isObject() && !options.Parse()) {
+ return false;
+ }
+
+ js::AssertSameCompartment(aCx, aValue);
+ RootedObject sourceScope(aCx, JS::CurrentGlobalOrNull(aCx));
+
+ {
+ JSAutoRealm ar(aCx, scope);
+ aCloned.set(aValue);
+ if (!StackScopedClone(aCx, options, sourceScope, aCloned)) {
+ return false;
+ }
+ }
+
+ return JS_WrapValue(aCx, aCloned);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CloneInto(HandleValue aValue, HandleValue aScope,
+ HandleValue aOptions, JSContext* aCx,
+ MutableHandleValue aCloned) {
+ return xpc::CloneInto(aCx, aValue, aScope, aOptions, aCloned)
+ ? NS_OK
+ : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetWebIDLCallerPrincipal(nsIPrincipal** aResult) {
+ // This API may only be when the Entry Settings Object corresponds to a
+ // JS-implemented WebIDL call. In all other cases, the value will be null,
+ // and we throw.
+ nsCOMPtr<nsIPrincipal> callerPrin = mozilla::dom::GetWebIDLCallerPrincipal();
+ if (!callerPrin) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ callerPrin.forget(aResult);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetObjectPrincipal(HandleValue val, JSContext* cx,
+ nsIPrincipal** result) {
+ if (!val.isObject()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ RootedObject obj(cx, &val.toObject());
+ // We need to be able to unwrap to WindowProxy or Location here, so
+ // use CheckedUnwrapDynamic.
+ obj = js::CheckedUnwrapDynamic(obj, cx);
+ MOZ_ASSERT(obj);
+
+ nsCOMPtr<nsIPrincipal> prin = nsContentUtils::ObjectPrincipal(obj);
+ prin.forget(result);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetRealmLocation(HandleValue val, JSContext* cx,
+ nsACString& result) {
+ if (!val.isObject()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ RootedObject obj(cx, &val.toObject());
+ // We need to be able to unwrap to WindowProxy or Location here, so
+ // use CheckedUnwrapDynamic.
+ obj = js::CheckedUnwrapDynamic(obj, cx);
+ MOZ_ASSERT(obj);
+
+ result = xpc::RealmPrivate::Get(obj)->GetLocation();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::ReadUTF8File(nsIFile* aFile, nsACString& aResult) {
+ NS_ENSURE_TRUE(aFile, NS_ERROR_INVALID_ARG);
+
+ MOZ_TRY_VAR(aResult, URLPreloader::ReadFile(aFile));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::ReadUTF8URI(nsIURI* aURI, nsACString& aResult) {
+ NS_ENSURE_TRUE(aURI, NS_ERROR_INVALID_ARG);
+
+ MOZ_TRY_VAR(aResult, URLPreloader::ReadURI(aURI));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::Now(double* aRetval) {
+ TimeStamp start = TimeStamp::ProcessCreation();
+ *aRetval = (TimeStamp::Now() - start).ToMilliseconds();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CreateSpellChecker(nsIEditorSpellCheck** aSpellChecker) {
+ NS_ENSURE_ARG_POINTER(aSpellChecker);
+ nsCOMPtr<nsIEditorSpellCheck> spellChecker = new mozilla::EditorSpellCheck();
+ spellChecker.forget(aSpellChecker);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CreateCommandLine(const nsTArray<nsCString>& aArgs,
+ nsIFile* aWorkingDir, uint32_t aState,
+ nsISupports** aCommandLine) {
+ NS_ENSURE_ARG_MAX(aState, nsICommandLine::STATE_REMOTE_EXPLICIT);
+ NS_ENSURE_ARG_POINTER(aCommandLine);
+
+ nsCOMPtr<nsISupports> commandLine = new nsCommandLine();
+ nsCOMPtr<nsICommandLineRunner> runner = do_QueryInterface(commandLine);
+
+ nsTArray<const char*> fakeArgv(aArgs.Length() + 2);
+
+ // Prepend a dummy argument for the program name, which will be ignored.
+ fakeArgv.AppendElement(nullptr);
+ for (const nsCString& arg : aArgs) {
+ fakeArgv.AppendElement(arg.get());
+ }
+ // Append a null terminator.
+ fakeArgv.AppendElement(nullptr);
+
+ nsresult rv = runner->Init(fakeArgv.Length() - 1, fakeArgv.Elements(),
+ aWorkingDir, aState);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ commandLine.forget(aCommandLine);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CreateCommandParams(nsICommandParams** aCommandParams) {
+ NS_ENSURE_ARG_POINTER(aCommandParams);
+ nsCOMPtr<nsICommandParams> commandParams = new nsCommandParams();
+ commandParams.forget(aCommandParams);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CreateLoadContext(nsILoadContext** aLoadContext) {
+ NS_ENSURE_ARG_POINTER(aLoadContext);
+ nsCOMPtr<nsILoadContext> loadContext = ::CreateLoadContext();
+ loadContext.forget(aLoadContext);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CreatePrivateLoadContext(nsILoadContext** aLoadContext) {
+ NS_ENSURE_ARG_POINTER(aLoadContext);
+ nsCOMPtr<nsILoadContext> loadContext = ::CreatePrivateLoadContext();
+ loadContext.forget(aLoadContext);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CreatePersistentProperties(
+ nsIPersistentProperties** aPersistentProperties) {
+ NS_ENSURE_ARG_POINTER(aPersistentProperties);
+ nsCOMPtr<nsIPersistentProperties> props = new nsPersistentProperties();
+ props.forget(aPersistentProperties);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CreateDocumentEncoder(
+ const char* aContentType, nsIDocumentEncoder** aDocumentEncoder) {
+ NS_ENSURE_ARG_POINTER(aDocumentEncoder);
+ nsCOMPtr<nsIDocumentEncoder> encoder = do_createDocumentEncoder(aContentType);
+ encoder.forget(aDocumentEncoder);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::CreateHTMLCopyEncoder(
+ nsIDocumentEncoder** aDocumentEncoder) {
+ NS_ENSURE_ARG_POINTER(aDocumentEncoder);
+ nsCOMPtr<nsIDocumentEncoder> encoder = do_createHTMLCopyEncoder();
+ encoder.forget(aDocumentEncoder);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetLoadedModules(nsTArray<nsCString>& aLoadedModules) {
+ return mozJSModuleLoader::Get()->GetLoadedJSAndESModules(aLoadedModules);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetLoadedJSModules(
+ nsTArray<nsCString>& aLoadedJSModules) {
+ mozJSModuleLoader::Get()->GetLoadedModules(aLoadedJSModules);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetLoadedESModules(
+ nsTArray<nsCString>& aLoadedESModules) {
+ return mozJSModuleLoader::Get()->GetLoadedESModules(aLoadedESModules);
+}
+
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetModuleImportStack(const nsACString& aLocation,
+ nsACString& aRetval) {
+ nsresult rv =
+ mozJSModuleLoader::Get()->GetModuleImportStack(aLocation, aRetval);
+ // Fallback the query to the DevTools loader if not found in the shared loader
+ if (rv == NS_ERROR_FAILURE && mozJSModuleLoader::GetDevToolsLoader()) {
+ return mozJSModuleLoader::GetDevToolsLoader()->GetModuleImportStack(
+ aLocation, aRetval);
+ }
+ return rv;
+}
+
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+
+nsXPCComponents::nsXPCComponents(XPCWrappedNativeScope* aScope)
+ : mScope(aScope) {
+ MOZ_ASSERT(aScope, "aScope must not be null");
+}
+
+nsXPCComponents::~nsXPCComponents() = default;
+
+void nsXPCComponents::ClearMembers() {
+ mInterfaces = nullptr;
+ mResults = nullptr;
+ mClasses = nullptr;
+ mID = nullptr;
+ mException = nullptr;
+ mConstructor = nullptr;
+ mUtils = nullptr;
+}
+
+/*******************************************/
+#define XPC_IMPL_GET_OBJ_METHOD(_class, _n) \
+ NS_IMETHODIMP _class::Get##_n(nsIXPCComponents_##_n** a##_n) { \
+ NS_ENSURE_ARG_POINTER(a##_n); \
+ if (!m##_n) m##_n = new nsXPCComponents_##_n(); \
+ RefPtr<nsXPCComponents_##_n> ret = m##_n; \
+ ret.forget(a##_n); \
+ return NS_OK; \
+ }
+
+XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Interfaces)
+XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Classes)
+XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Results)
+XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, ID)
+XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Exception)
+XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Constructor)
+XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Utils)
+
+#undef XPC_IMPL_GET_OBJ_METHOD
+/*******************************************/
+
+NS_IMETHODIMP
+nsXPCComponents::IsSuccessCode(nsresult result, bool* out) {
+ *out = NS_SUCCEEDED(result);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents::GetStack(nsIStackFrame** aStack) {
+ nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack();
+ frame.forget(aStack);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents::GetManager(nsIComponentManager** aManager) {
+ MOZ_ASSERT(aManager, "bad param");
+ return NS_GetComponentManager(aManager);
+}
+
+NS_IMETHODIMP
+nsXPCComponents::GetReturnCode(JSContext* aCx, MutableHandleValue aOut) {
+ nsresult res = XPCJSContext::Get()->GetPendingResult();
+ aOut.setNumber(static_cast<uint32_t>(res));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCComponents::SetReturnCode(JSContext* aCx, HandleValue aCode) {
+ nsresult rv;
+ if (!ToUint32(aCx, aCode, (uint32_t*)&rv)) {
+ return NS_ERROR_FAILURE;
+ }
+ XPCJSContext::Get()->SetPendingResult(rv);
+ return NS_OK;
+}
+
+/**********************************************/
+
+class ComponentsSH : public nsIXPCScriptable {
+ public:
+ explicit constexpr ComponentsSH(unsigned dummy) {}
+
+ // We don't actually inherit any ref counting infrastructure, but we don't
+ // need an nsAutoRefCnt member, so the _INHERITED macro is a hack to avoid
+ // having one.
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIXPCSCRIPTABLE
+ static nsresult Get(nsIXPCScriptable** helper) {
+ *helper = &singleton;
+ return NS_OK;
+ }
+
+ private:
+ static ComponentsSH singleton;
+};
+
+ComponentsSH ComponentsSH::singleton(0);
+
+// Singleton refcounting.
+NS_IMETHODIMP_(MozExternalRefCountType) ComponentsSH::AddRef(void) { return 1; }
+NS_IMETHODIMP_(MozExternalRefCountType) ComponentsSH::Release(void) {
+ return 1;
+}
+
+NS_IMPL_QUERY_INTERFACE(ComponentsSH, nsIXPCScriptable)
+
+#define NSXPCCOMPONENTS_CID \
+ { \
+ 0x3649f405, 0xf0ec, 0x4c28, { \
+ 0xae, 0xb0, 0xaf, 0x9a, 0x51, 0xe4, 0x4c, 0x81 \
+ } \
+ }
+
+NS_IMPL_CLASSINFO(nsXPCComponents, &ComponentsSH::Get, 0, NSXPCCOMPONENTS_CID)
+NS_IMPL_ISUPPORTS_CI(nsXPCComponents, nsIXPCComponents)
+
+// The nsIXPCScriptable map declaration that will generate stubs for us
+#define XPC_MAP_CLASSNAME ComponentsSH
+#define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents"
+#define XPC_MAP_FLAGS XPC_SCRIPTABLE_WANT_PRECREATE
+#include "xpc_map_end.h" /* This will #undef the above */
+
+NS_IMETHODIMP
+ComponentsSH::PreCreate(nsISupports* nativeObj, JSContext* cx,
+ JSObject* globalObj, JSObject** parentObj) {
+ nsXPCComponents* self = static_cast<nsXPCComponents*>(nativeObj);
+ // this should never happen
+ if (!self->GetScope()) {
+ NS_WARNING(
+ "mScope must not be null when nsXPCComponents::PreCreate is called");
+ return NS_ERROR_FAILURE;
+ }
+ *parentObj = self->GetScope()->GetGlobalForWrappedNatives();
+ return NS_OK;
+}