summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/src/xpcpublic.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /js/xpconnect/src/xpcpublic.h
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/xpconnect/src/xpcpublic.h')
-rw-r--r--js/xpconnect/src/xpcpublic.h1023
1 files changed, 1023 insertions, 0 deletions
diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h
new file mode 100644
index 0000000000..08da56e2fc
--- /dev/null
+++ b/js/xpconnect/src/xpcpublic.h
@@ -0,0 +1,1023 @@
+/* -*- 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/. */
+
+#ifndef xpcpublic_h
+#define xpcpublic_h
+
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+#include "ErrorList.h"
+#include "js/BuildId.h"
+#include "js/ErrorReport.h"
+#include "js/GCAPI.h"
+#include "js/Object.h"
+#include "js/RootingAPI.h"
+#include "js/String.h"
+#include "js/TypeDecls.h"
+#include "js/Utility.h"
+#include "js/Value.h"
+#include "jsapi.h"
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/TextUtils.h"
+#include "mozilla/dom/DOMString.h"
+#include "mozilla/fallible.h"
+#include "nsAtom.h"
+#include "nsCOMPtr.h"
+#include "nsISupports.h"
+#include "nsIURI.h"
+#include "nsStringBuffer.h"
+#include "nsStringFwd.h"
+#include "nsTArray.h"
+#include "nsWrapperCache.h"
+
+// XXX only for NukeAllWrappersForRealm, which is only used in
+// dom/base/WindowDestroyedEvent.cpp outside of js
+#include "jsfriendapi.h"
+
+class JSObject;
+class JSString;
+class JSTracer;
+class nsGlobalWindowInner;
+class nsIGlobalObject;
+class nsIHandleReportCallback;
+class nsIPrincipal;
+class nsPIDOMWindowInner;
+struct JSContext;
+struct nsID;
+struct nsXPTInterfaceInfo;
+
+namespace JS {
+class Compartment;
+class ContextOptions;
+class PrefableCompileOptions;
+class Realm;
+class RealmOptions;
+class Value;
+struct RuntimeStats;
+} // namespace JS
+
+namespace mozilla {
+class BasePrincipal;
+
+namespace dom {
+class Exception;
+} // namespace dom
+} // namespace mozilla
+
+using xpcGCCallback = void (*)(JSGCStatus);
+
+namespace xpc {
+
+class Scriptability {
+ public:
+ explicit Scriptability(JS::Realm* realm);
+ bool Allowed();
+ bool IsImmuneToScriptPolicy();
+
+ void Block();
+ void Unblock();
+ void SetWindowAllowsScript(bool aAllowed);
+
+ static Scriptability& Get(JSObject* aScope);
+
+ // Returns true if scripting is allowed, false otherwise (if no Scriptability
+ // exists, like for example inside a ShadowRealm global, then script execution
+ // is assumed to be allowed)
+ static bool AllowedIfExists(JSObject* aScope);
+
+ private:
+ // Whenever a consumer wishes to prevent script from running on a global,
+ // it increments this value with a call to Block(). When it wishes to
+ // re-enable it (if ever), it decrements this value with a call to Unblock().
+ // Script may not run if this value is non-zero.
+ uint32_t mScriptBlocks;
+
+ // Whether the DOM window allows javascript in this scope. If this scope
+ // doesn't have a window, this value is always true.
+ bool mWindowAllowsScript;
+
+ // Whether this scope is immune to user-defined or addon-defined script
+ // policy.
+ bool mImmuneToScriptPolicy;
+
+ // Whether the new-style domain policy when this compartment was created
+ // forbids script execution.
+ bool mScriptBlockedByPolicy;
+};
+
+JSObject* TransplantObject(JSContext* cx, JS::Handle<JSObject*> origobj,
+ JS::Handle<JSObject*> target);
+
+JSObject* TransplantObjectRetainingXrayExpandos(JSContext* cx,
+ JS::Handle<JSObject*> origobj,
+ JS::Handle<JSObject*> target);
+
+// If origObj has an xray waiver, nuke it before transplant.
+JSObject* TransplantObjectNukingXrayWaiver(JSContext* cx,
+ JS::Handle<JSObject*> origObj,
+ JS::Handle<JSObject*> target);
+
+bool IsUAWidgetCompartment(JS::Compartment* compartment);
+bool IsUAWidgetScope(JS::Realm* realm);
+bool IsInUAWidgetScope(JSObject* obj);
+
+bool MightBeWebContentCompartment(JS::Compartment* compartment);
+
+void SetCompartmentChangedDocumentDomain(JS::Compartment* compartment);
+
+JSObject* GetUAWidgetScope(JSContext* cx, nsIPrincipal* principal);
+
+JSObject* GetUAWidgetScope(JSContext* cx, JSObject* contentScope);
+
+// Returns whether XBL scopes have been explicitly disabled for code running
+// in this compartment. See the comment around mAllowContentXBLScope.
+bool AllowContentXBLScope(JS::Realm* realm);
+
+// Get the scope for creating reflectors for native anonymous content
+// whose normal global would be the given global.
+JSObject* NACScope(JSObject* global);
+
+bool IsSandboxPrototypeProxy(JSObject* obj);
+bool IsWebExtensionContentScriptSandbox(JSObject* obj);
+
+// The JSContext argument represents the Realm that's asking the question. This
+// is needed to properly answer without exposing information unnecessarily
+// from behind security wrappers. There will be no exceptions thrown on this
+// JSContext.
+bool IsReflector(JSObject* obj, JSContext* cx);
+
+bool IsXrayWrapper(JSObject* obj);
+
+// If this function was created for a given XrayWrapper, returns the global of
+// the Xrayed object. Otherwise, returns the global of the function.
+//
+// To emphasize the obvious: the return value here is not necessarily same-
+// compartment with the argument.
+JSObject* XrayAwareCalleeGlobal(JSObject* fun);
+
+void TraceXPCGlobal(JSTracer* trc, JSObject* obj);
+
+/**
+ * Creates a new global object using the given aCOMObj as the global object.
+ * The object will be set up according to the flags (defined below).
+ * aCOMObj must implement nsIXPCScriptable so it can resolve the standard
+ * classes when asked by the JS engine.
+ *
+ * @param aJSContext the context to use while creating the global object.
+ * @param aCOMObj the native object that represents the global object.
+ * @param aPrincipal the principal of the code that will run in this
+ * compartment. Can be null if not on the main thread.
+ * @param aFlags one of the flags below specifying what options this
+ * global object wants.
+ * @param aOptions JSAPI-specific options for the new compartment.
+ */
+nsresult InitClassesWithNewWrappedGlobal(
+ JSContext* aJSContext, nsISupports* aCOMObj, nsIPrincipal* aPrincipal,
+ uint32_t aFlags, JS::RealmOptions& aOptions,
+ JS::MutableHandle<JSObject*> aNewGlobal);
+
+enum InitClassesFlag {
+ DONT_FIRE_ONNEWGLOBALHOOK = 1 << 0,
+ OMIT_COMPONENTS_OBJECT = 1 << 1,
+};
+
+} /* namespace xpc */
+
+namespace JS {
+
+struct RuntimeStats;
+
+} // namespace JS
+
+static_assert(JSCLASS_GLOBAL_APPLICATION_SLOTS > 0,
+ "Need at least one slot for JSCLASS_SLOT0_IS_NSISUPPORTS");
+
+#define XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(n) \
+ JSCLASS_DOM_GLOBAL | JSCLASS_SLOT0_IS_NSISUPPORTS | \
+ JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS + n)
+
+#define XPCONNECT_GLOBAL_EXTRA_SLOT_OFFSET \
+ (JSCLASS_GLOBAL_SLOT_COUNT + DOM_GLOBAL_SLOTS)
+
+#define XPCONNECT_GLOBAL_FLAGS XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(0)
+
+inline JSObject* xpc_FastGetCachedWrapper(JSContext* cx, nsWrapperCache* cache,
+ JS::MutableHandle<JS::Value> vp) {
+ if (cache) {
+ JSObject* wrapper = cache->GetWrapper();
+ if (wrapper &&
+ JS::GetCompartment(wrapper) == js::GetContextCompartment(cx)) {
+ vp.setObject(*wrapper);
+ return wrapper;
+ }
+ }
+
+ return nullptr;
+}
+
+// If aWrappedJS is a JS wrapper, unmark its JSObject.
+extern void xpc_TryUnmarkWrappedGrayObject(nsISupports* aWrappedJS);
+
+extern void xpc_UnmarkSkippableJSHolders();
+
+// Defined in XPCDebug.cpp.
+extern bool xpc_DumpJSStack(bool showArgs, bool showLocals, bool showThisProps);
+
+// Return a newly-allocated string containing a representation of the
+// current JS stack. Defined in XPCDebug.cpp.
+extern JS::UniqueChars xpc_PrintJSStack(JSContext* cx, bool showArgs,
+ bool showLocals, bool showThisProps);
+
+inline void AssignFromStringBuffer(nsStringBuffer* buffer, size_t len,
+ nsAString& dest) {
+ buffer->ToString(len, dest);
+}
+inline void AssignFromStringBuffer(nsStringBuffer* buffer, size_t len,
+ nsACString& dest) {
+ buffer->ToString(len, dest);
+}
+
+// readable string conversions, static methods and members only
+class XPCStringConvert {
+ public:
+ // If the string shares the readable's buffer, that buffer will
+ // get assigned to *sharedBuffer. Otherwise null will be
+ // assigned.
+ static bool ReadableToJSVal(JSContext* cx, const nsAString& readable,
+ nsStringBuffer** sharedBuffer,
+ JS::MutableHandle<JS::Value> vp);
+ static bool Latin1ToJSVal(JSContext* cx, const nsACString& latin1,
+ nsStringBuffer** sharedBuffer,
+ JS::MutableHandle<JS::Value> vp);
+ static bool UTF8ToJSVal(JSContext* cx, const nsACString& utf8,
+ nsStringBuffer** sharedBuffer,
+ JS::MutableHandle<JS::Value> vp);
+
+ // Convert the given stringbuffer/length pair to a jsval
+ static MOZ_ALWAYS_INLINE bool UCStringBufferToJSVal(
+ JSContext* cx, nsStringBuffer* buf, uint32_t length,
+ JS::MutableHandle<JS::Value> rval, bool* sharedBuffer) {
+ JSString* str = JS_NewMaybeExternalUCString(
+ cx, static_cast<const char16_t*>(buf->Data()), length,
+ &sDOMStringExternalString, sharedBuffer);
+ if (!str) {
+ return false;
+ }
+ rval.setString(str);
+ return true;
+ }
+
+ static MOZ_ALWAYS_INLINE bool Latin1StringBufferToJSVal(
+ JSContext* cx, nsStringBuffer* buf, uint32_t length,
+ JS::MutableHandle<JS::Value> rval, bool* sharedBuffer) {
+ JSString* str = JS_NewMaybeExternalStringLatin1(
+ cx, static_cast<const JS::Latin1Char*>(buf->Data()), length,
+ &sDOMStringExternalString, sharedBuffer);
+ if (!str) {
+ return false;
+ }
+ rval.setString(str);
+ return true;
+ }
+
+ static MOZ_ALWAYS_INLINE bool UTF8StringBufferToJSVal(
+ JSContext* cx, nsStringBuffer* buf, uint32_t length,
+ JS::MutableHandle<JS::Value> rval, bool* sharedBuffer) {
+ JSString* str = JS_NewMaybeExternalStringUTF8(
+ cx, {static_cast<const char*>(buf->Data()), length},
+ &sDOMStringExternalString, sharedBuffer);
+ if (!str) {
+ return false;
+ }
+ rval.setString(str);
+ return true;
+ }
+
+ static inline bool StringLiteralToJSVal(JSContext* cx,
+ const char16_t* literal,
+ uint32_t length,
+ JS::MutableHandle<JS::Value> rval) {
+ bool ignored;
+ JSString* str = JS_NewMaybeExternalUCString(
+ cx, literal, length, &sLiteralExternalString, &ignored);
+ if (!str) {
+ return false;
+ }
+ rval.setString(str);
+ return true;
+ }
+
+ static inline bool StringLiteralToJSVal(JSContext* cx,
+ const JS::Latin1Char* literal,
+ uint32_t length,
+ JS::MutableHandle<JS::Value> rval) {
+ bool ignored;
+ JSString* str = JS_NewMaybeExternalStringLatin1(
+ cx, literal, length, &sLiteralExternalString, &ignored);
+ if (!str) {
+ return false;
+ }
+ rval.setString(str);
+ return true;
+ }
+
+ static inline bool UTF8StringLiteralToJSVal(
+ JSContext* cx, const JS::UTF8Chars& chars,
+ JS::MutableHandle<JS::Value> rval) {
+ bool ignored;
+ JSString* str = JS_NewMaybeExternalStringUTF8(
+ cx, chars, &sLiteralExternalString, &ignored);
+ if (!str) {
+ return false;
+ }
+ rval.setString(str);
+ return true;
+ }
+
+ private:
+ static MOZ_ALWAYS_INLINE bool MaybeGetExternalStringChars(
+ JSString* str, const JSExternalStringCallbacks** callbacks,
+ const char16_t** chars) {
+ return JS::IsExternalUCString(str, callbacks, chars);
+ }
+ static MOZ_ALWAYS_INLINE bool MaybeGetExternalStringChars(
+ JSString* str, const JSExternalStringCallbacks** callbacks,
+ const JS::Latin1Char** chars) {
+ return JS::IsExternalStringLatin1(str, callbacks, chars);
+ }
+
+ enum class AcceptedEncoding { All, ASCII };
+
+ template <typename SrcCharT, typename DestCharT, AcceptedEncoding encoding,
+ typename T>
+ static MOZ_ALWAYS_INLINE bool MaybeAssignStringChars(JSString* s, size_t len,
+ T& dest) {
+ MOZ_ASSERT(len == JS::GetStringLength(s));
+ static_assert(sizeof(SrcCharT) == sizeof(DestCharT));
+ if constexpr (encoding == AcceptedEncoding::ASCII) {
+ static_assert(
+ std::is_same_v<DestCharT, char>,
+ "AcceptedEncoding::ASCII can be used only with single byte");
+ }
+
+ const JSExternalStringCallbacks* callbacks;
+ const DestCharT* chars;
+ if (!MaybeGetExternalStringChars(
+ s, &callbacks, reinterpret_cast<const SrcCharT**>(&chars))) {
+ return false;
+ }
+
+ if (callbacks == &sDOMStringExternalString) {
+ if constexpr (encoding == AcceptedEncoding::ASCII) {
+ if (!mozilla::IsAscii(mozilla::Span(chars, len))) {
+ return false;
+ }
+ }
+
+ // The characters represent an existing string buffer that we shared with
+ // JS. We can share that buffer ourselves if the string corresponds to
+ // the whole buffer; otherwise we have to copy.
+ if (chars[len] == '\0') {
+ // NOTE: No need to worry about SrcCharT vs DestCharT, given
+ // nsStringBuffer::FromData takes void*.
+ AssignFromStringBuffer(
+ nsStringBuffer::FromData(const_cast<DestCharT*>(chars)), len, dest);
+ return true;
+ }
+ } else if (callbacks == &sLiteralExternalString) {
+ if constexpr (encoding == AcceptedEncoding::ASCII) {
+ if (!mozilla::IsAscii(mozilla::Span(chars, len))) {
+ return false;
+ }
+ }
+
+ // The characters represent a literal string constant
+ // compiled into libxul; we can just use it as-is.
+ dest.AssignLiteral(chars, len);
+ return true;
+ }
+
+ return false;
+ }
+
+ public:
+ template <typename T>
+ static MOZ_ALWAYS_INLINE bool MaybeAssignUCStringChars(JSString* s,
+ size_t len, T& dest) {
+ return MaybeAssignStringChars<char16_t, char16_t, AcceptedEncoding::All>(
+ s, len, dest);
+ }
+
+ template <typename T>
+ static MOZ_ALWAYS_INLINE bool MaybeAssignLatin1StringChars(JSString* s,
+ size_t len,
+ T& dest) {
+ return MaybeAssignStringChars<JS::Latin1Char, char, AcceptedEncoding::All>(
+ s, len, dest);
+ }
+
+ template <typename T>
+ static MOZ_ALWAYS_INLINE bool MaybeAssignUTF8StringChars(JSString* s,
+ size_t len,
+ T& dest) {
+ return MaybeAssignStringChars<JS::Latin1Char, char,
+ AcceptedEncoding::ASCII>(s, len, dest);
+ }
+
+ private:
+ struct LiteralExternalString : public JSExternalStringCallbacks {
+ void finalize(JS::Latin1Char* aChars) const override;
+ void finalize(char16_t* aChars) const override;
+ size_t sizeOfBuffer(const JS::Latin1Char* aChars,
+ mozilla::MallocSizeOf aMallocSizeOf) const override;
+ size_t sizeOfBuffer(const char16_t* aChars,
+ mozilla::MallocSizeOf aMallocSizeOf) const override;
+ };
+ struct DOMStringExternalString : public JSExternalStringCallbacks {
+ void finalize(JS::Latin1Char* aChars) const override;
+ void finalize(char16_t* aChars) const override;
+ size_t sizeOfBuffer(const JS::Latin1Char* aChars,
+ mozilla::MallocSizeOf aMallocSizeOf) const override;
+ size_t sizeOfBuffer(const char16_t* aChars,
+ mozilla::MallocSizeOf aMallocSizeOf) const override;
+ };
+ static const LiteralExternalString sLiteralExternalString;
+ static const DOMStringExternalString sDOMStringExternalString;
+
+ XPCStringConvert() = delete;
+};
+
+namespace xpc {
+
+// If these functions return false, then an exception will be set on cx.
+bool Base64Encode(JSContext* cx, JS::Handle<JS::Value> val,
+ JS::MutableHandle<JS::Value> out);
+bool Base64Decode(JSContext* cx, JS::Handle<JS::Value> val,
+ JS::MutableHandle<JS::Value> out);
+
+/**
+ * Convert an nsString to jsval, returning true on success.
+ * Note, the ownership of the string buffer may be moved from str to rval.
+ * If that happens, str will point to an empty string after this call.
+ */
+bool NonVoidStringToJsval(JSContext* cx, nsAString& str,
+ JS::MutableHandle<JS::Value> rval);
+bool NonVoidStringToJsval(JSContext* cx, const nsAString& str,
+ JS::MutableHandle<JS::Value> rval);
+inline bool StringToJsval(JSContext* cx, nsAString& str,
+ JS::MutableHandle<JS::Value> rval) {
+ // From the T_ASTRING case in XPCConvert::NativeData2JS.
+ if (str.IsVoid()) {
+ rval.setNull();
+ return true;
+ }
+ return NonVoidStringToJsval(cx, str, rval);
+}
+
+inline bool StringToJsval(JSContext* cx, const nsAString& str,
+ JS::MutableHandle<JS::Value> rval) {
+ // From the T_ASTRING case in XPCConvert::NativeData2JS.
+ if (str.IsVoid()) {
+ rval.setNull();
+ return true;
+ }
+ return NonVoidStringToJsval(cx, str, rval);
+}
+
+/**
+ * As above, but for mozilla::dom::DOMString.
+ */
+inline bool NonVoidStringToJsval(JSContext* cx, mozilla::dom::DOMString& str,
+ JS::MutableHandle<JS::Value> rval) {
+ if (str.IsEmpty()) {
+ rval.set(JS_GetEmptyStringValue(cx));
+ return true;
+ }
+
+ if (str.HasStringBuffer()) {
+ uint32_t length = str.StringBufferLength();
+ nsStringBuffer* buf = str.StringBuffer();
+ bool shared;
+ if (!XPCStringConvert::UCStringBufferToJSVal(cx, buf, length, rval,
+ &shared)) {
+ return false;
+ }
+ if (shared) {
+ // JS now needs to hold a reference to the buffer
+ str.RelinquishBufferOwnership();
+ }
+ return true;
+ }
+
+ if (str.HasLiteral()) {
+ return XPCStringConvert::StringLiteralToJSVal(cx, str.Literal(),
+ str.LiteralLength(), rval);
+ }
+
+ // It's an actual XPCOM string
+ return NonVoidStringToJsval(cx, str.AsAString(), rval);
+}
+
+MOZ_ALWAYS_INLINE
+bool StringToJsval(JSContext* cx, mozilla::dom::DOMString& str,
+ JS::MutableHandle<JS::Value> rval) {
+ if (str.IsNull()) {
+ rval.setNull();
+ return true;
+ }
+ return NonVoidStringToJsval(cx, str, rval);
+}
+
+/**
+ * As above, but for nsACString with latin-1 (non-UTF8) content.
+ */
+bool NonVoidLatin1StringToJsval(JSContext* cx, nsACString& str,
+ JS::MutableHandle<JS::Value> rval);
+bool NonVoidLatin1StringToJsval(JSContext* cx, const nsACString& str,
+ JS::MutableHandle<JS::Value> rval);
+
+inline bool Latin1StringToJsval(JSContext* cx, nsACString& str,
+ JS::MutableHandle<JS::Value> rval) {
+ if (str.IsVoid()) {
+ rval.setNull();
+ return true;
+ }
+ return NonVoidLatin1StringToJsval(cx, str, rval);
+}
+
+inline bool Latin1StringToJsval(JSContext* cx, const nsACString& str,
+ JS::MutableHandle<JS::Value> rval) {
+ if (str.IsVoid()) {
+ rval.setNull();
+ return true;
+ }
+ return NonVoidLatin1StringToJsval(cx, str, rval);
+}
+
+/**
+ * As above, but for nsACString with UTF-8 content.
+ */
+bool NonVoidUTF8StringToJsval(JSContext* cx, nsACString& str,
+ JS::MutableHandle<JS::Value> rval);
+bool NonVoidUTF8StringToJsval(JSContext* cx, const nsACString& str,
+ JS::MutableHandle<JS::Value> rval);
+
+inline bool UTF8StringToJsval(JSContext* cx, nsACString& str,
+ JS::MutableHandle<JS::Value> rval) {
+ if (str.IsVoid()) {
+ rval.setNull();
+ return true;
+ }
+ return NonVoidUTF8StringToJsval(cx, str, rval);
+}
+
+inline bool UTF8StringToJsval(JSContext* cx, const nsACString& str,
+ JS::MutableHandle<JS::Value> rval) {
+ if (str.IsVoid()) {
+ rval.setNull();
+ return true;
+ }
+ return NonVoidUTF8StringToJsval(cx, str, rval);
+}
+
+mozilla::BasePrincipal* GetRealmPrincipal(JS::Realm* realm);
+
+void NukeAllWrappersForRealm(JSContext* cx, JS::Realm* realm,
+ js::NukeReferencesToWindow nukeReferencesToWindow =
+ js::NukeWindowReferences);
+
+void SetLocationForGlobal(JSObject* global, const nsACString& location);
+void SetLocationForGlobal(JSObject* global, nsIURI* locationURI);
+
+// ReportJSRuntimeExplicitTreeStats will expect this in the |extra| member
+// of JS::ZoneStats.
+class ZoneStatsExtras {
+ public:
+ ZoneStatsExtras() = default;
+
+ nsCString pathPrefix;
+
+ private:
+ ZoneStatsExtras(const ZoneStatsExtras& other) = delete;
+ ZoneStatsExtras& operator=(const ZoneStatsExtras& other) = delete;
+};
+
+// ReportJSRuntimeExplicitTreeStats will expect this in the |extra| member
+// of JS::RealmStats.
+class RealmStatsExtras {
+ public:
+ RealmStatsExtras() = default;
+
+ nsCString jsPathPrefix;
+ nsCString domPathPrefix;
+ nsCOMPtr<nsIURI> location;
+
+ private:
+ RealmStatsExtras(const RealmStatsExtras& other) = delete;
+ RealmStatsExtras& operator=(const RealmStatsExtras& other) = delete;
+};
+
+// This reports all the stats in |rtStats| that belong in the "explicit" tree,
+// (which isn't all of them).
+// @see ZoneStatsExtras
+// @see RealmStatsExtras
+void ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats& rtStats,
+ const nsACString& rtPath,
+ nsIHandleReportCallback* handleReport,
+ nsISupports* data, bool anonymize,
+ size_t* rtTotal = nullptr);
+
+/**
+ * Throws an exception on cx and returns false.
+ */
+bool Throw(JSContext* cx, nsresult rv);
+
+/**
+ * Returns the nsISupports native behind a given reflector (either DOM or
+ * XPCWN). If a non-reflector object is passed in, null will be returned.
+ *
+ * This function will not correctly handle Window or Location objects behind
+ * cross-compartment wrappers: it will return null. If you care about getting
+ * non-null for Window or Location, use ReflectorToISupportsDynamic.
+ */
+already_AddRefed<nsISupports> ReflectorToISupportsStatic(JSObject* reflector);
+
+/**
+ * Returns the nsISupports native behind a given reflector (either DOM or
+ * XPCWN). If a non-reflector object is passed in, null will be returned.
+ *
+ * The JSContext argument represents the Realm that's asking for the
+ * nsISupports. This is needed to properly handle Window and Location objects,
+ * which do dynamic security checks.
+ */
+already_AddRefed<nsISupports> ReflectorToISupportsDynamic(JSObject* reflector,
+ JSContext* cx);
+
+/**
+ * Singleton scopes for stuff that really doesn't fit anywhere else.
+ *
+ * If you find yourself wanting to use these compartments, you're probably doing
+ * something wrong. Callers MUST consult with the XPConnect module owner before
+ * using this compartment. If you don't, bholley will hunt you down.
+ */
+JSObject* UnprivilegedJunkScope();
+
+JSObject* UnprivilegedJunkScope(const mozilla::fallible_t&);
+
+bool IsUnprivilegedJunkScope(JSObject*);
+
+/**
+ * This will generally be the shared JSM global, but callers should not depend
+ * on that fact.
+ */
+JSObject* PrivilegedJunkScope();
+
+/**
+ * Shared compilation scope for XUL prototype documents and XBL
+ * precompilation.
+ */
+JSObject* CompilationScope();
+
+/**
+ * Returns the nsIGlobalObject corresponding to |obj|'s JS global. |obj| must
+ * not be a cross-compartment wrapper: CCWs are not associated with a single
+ * global.
+ */
+nsIGlobalObject* NativeGlobal(JSObject* obj);
+
+/**
+ * Returns the nsIGlobalObject corresponding to |cx|'s JS global. Must not be
+ * called when |cx| is not in a Realm.
+ */
+nsIGlobalObject* CurrentNativeGlobal(JSContext* cx);
+
+/**
+ * If |aObj| is a window, returns the associated nsGlobalWindow.
+ * Otherwise, returns null.
+ */
+nsGlobalWindowInner* WindowOrNull(JSObject* aObj);
+
+/**
+ * If |aObj| has a window for a global, returns the associated nsGlobalWindow.
+ * Otherwise, returns null. Note: aObj must not be a cross-compartment wrapper
+ * because CCWs are not associated with a single global/realm.
+ */
+nsGlobalWindowInner* WindowGlobalOrNull(JSObject* aObj);
+
+/**
+ * If |aObj| is a Sandbox object and it has a sandboxPrototype, then return
+ * that prototype.
+ * |aCx| is used for checked unwrapping of the prototype.
+ */
+JSObject* SandboxPrototypeOrNull(JSContext* aCx, JSObject* aObj);
+
+/**
+ * If |aObj| is a Sandbox object associated with a DOMWindow via a
+ * sandboxPrototype, then return that DOMWindow.
+ * |aCx| is used for checked unwrapping of the Window.
+ */
+inline nsGlobalWindowInner* SandboxWindowOrNull(JSObject* aObj,
+ JSContext* aCx) {
+ JSObject* proto = SandboxPrototypeOrNull(aCx, aObj);
+ return proto ? WindowOrNull(proto) : nullptr;
+}
+
+/**
+ * If |cx| is in a realm whose global is a window, returns the associated
+ * nsGlobalWindow. Otherwise, returns null.
+ */
+nsGlobalWindowInner* CurrentWindowOrNull(JSContext* cx);
+
+class MOZ_RAII AutoScriptActivity {
+ bool mActive;
+ bool mOldValue;
+
+ public:
+ explicit AutoScriptActivity(bool aActive);
+ ~AutoScriptActivity();
+};
+
+// This function may be used off-main-thread, in which case it is benignly
+// racey.
+bool ShouldDiscardSystemSource();
+
+void SetPrefableRealmOptions(JS::RealmOptions& options);
+void SetPrefableContextOptions(JS::ContextOptions& options);
+
+// This function may be used off-main-thread.
+void SetPrefableCompileOptions(JS::PrefableCompileOptions& options);
+
+// Modify the provided realm options, consistent with |aIsSystemPrincipal| and
+// with globally-cached values of various preferences.
+//
+// Call this function *before* |aOptions| is used to create the corresponding
+// global object, as not all of the options it sets can be modified on an
+// existing global object. (The type system should make this obvious, because
+// you can't get a *mutable* JS::RealmOptions& from an existing global
+// object.)
+void InitGlobalObjectOptions(JS::RealmOptions& aOptions,
+ bool aIsSystemPrincipal, bool aSecureContext,
+ bool aForceUTC, bool aAlwaysUseFdlibm,
+ bool aLocaleEnUS);
+
+class ErrorBase {
+ public:
+ nsString mErrorMsg;
+ nsString mFileName;
+ uint32_t mSourceId;
+ // Line number (1-origin).
+ uint32_t mLineNumber;
+ // Column number in UTF-16 code units (1-origin).
+ uint32_t mColumn;
+
+ ErrorBase() : mSourceId(0), mLineNumber(0), mColumn(0) {}
+
+ void Init(JSErrorBase* aReport);
+
+ void AppendErrorDetailsTo(nsCString& error);
+};
+
+class ErrorNote : public ErrorBase {
+ public:
+ void Init(JSErrorNotes::Note* aNote);
+
+ // Produce an error event message string from the given JSErrorNotes::Note.
+ // This may produce an empty string if aNote doesn't have a message
+ // attached.
+ static void ErrorNoteToMessageString(JSErrorNotes::Note* aNote,
+ nsAString& aString);
+
+ // Log the error note to the stderr.
+ void LogToStderr();
+};
+
+class ErrorReport : public ErrorBase {
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ErrorReport);
+
+ nsTArray<ErrorNote> mNotes;
+
+ nsCString mCategory;
+ nsString mSourceLine;
+ nsString mErrorMsgName;
+ uint64_t mWindowID;
+ bool mIsWarning;
+ bool mIsMuted;
+ bool mIsPromiseRejection;
+
+ ErrorReport()
+ : mWindowID(0),
+ mIsWarning(false),
+ mIsMuted(false),
+ mIsPromiseRejection(false) {}
+
+ void Init(JSErrorReport* aReport, const char* aToStringResult, bool aIsChrome,
+ uint64_t aWindowID);
+ void Init(JSContext* aCx, mozilla::dom::Exception* aException, bool aIsChrome,
+ uint64_t aWindowID);
+
+ // Log the error report to the console. Which console will depend on the
+ // window id it was initialized with.
+ void LogToConsole();
+ // Log to console, using the given stack object (which should be a stack of
+ // the sort that JS::CaptureCurrentStack produces). aStack is allowed to be
+ // null. If aStack is non-null, aStackGlobal must be a non-null global
+ // object that's same-compartment with aStack. Note that aStack might be a
+ // CCW.
+ void LogToConsoleWithStack(nsGlobalWindowInner* aWin,
+ JS::Handle<mozilla::Maybe<JS::Value>> aException,
+ JS::Handle<JSObject*> aStack,
+ JS::Handle<JSObject*> aStackGlobal);
+
+ // Produce an error event message string from the given JSErrorReport. Note
+ // that this may produce an empty string if aReport doesn't have a
+ // message attached.
+ static void ErrorReportToMessageString(JSErrorReport* aReport,
+ nsAString& aString);
+
+ // Log the error report to the stderr.
+ void LogToStderr();
+
+ bool IsWarning() const { return mIsWarning; };
+
+ private:
+ ~ErrorReport() = default;
+};
+
+void DispatchScriptErrorEvent(nsPIDOMWindowInner* win,
+ JS::RootingContext* rootingCx,
+ xpc::ErrorReport* xpcReport,
+ JS::Handle<JS::Value> exception,
+ JS::Handle<JSObject*> exceptionStack);
+
+// Get a stack (as stackObj outparam) of the sort that can be passed to
+// xpc::ErrorReport::LogToConsoleWithStack from the given exception value. Can
+// be nullptr if the exception value doesn't have an associated stack, and if
+// there is no stack supplied by the JS engine in exceptionStack. The
+// returned stack, if any, may also not be in the same compartment as
+// exceptionValue.
+//
+// The "win" argument passed in here should be the same as the window whose
+// WindowID() is used to initialize the xpc::ErrorReport. This may be null, of
+// course. If it's not null, this function may return a null stack object if
+// the window is far enough gone, because in those cases we don't want to have
+// the stack in the console message keeping the window alive.
+//
+// If this function sets stackObj to a non-null value, stackGlobal is set to
+// either the JS exception object's global or the global of the SavedFrame we
+// got from a DOM or XPConnect exception. In all cases, stackGlobal is an
+// unwrapped global object and is same-compartment with stackObj.
+void FindExceptionStackForConsoleReport(
+ nsPIDOMWindowInner* win, JS::Handle<JS::Value> exceptionValue,
+ JS::Handle<JSObject*> exceptionStack, JS::MutableHandle<JSObject*> stackObj,
+ JS::MutableHandle<JSObject*> stackGlobal);
+
+// Return a name for the realm.
+// This function makes reasonable efforts to make this name both mostly
+// human-readable and unique. However, there are no guarantees of either
+// property.
+extern void GetCurrentRealmName(JSContext*, nsCString& name);
+
+nsCString GetFunctionName(JSContext* cx, JS::Handle<JSObject*> obj);
+
+void AddGCCallback(xpcGCCallback cb);
+void RemoveGCCallback(xpcGCCallback cb);
+
+// We need an exact page size only if we run the binary in automation.
+#if (defined(XP_DARWIN) && defined(__aarch64__)) || defined(__loongarch__)
+const size_t kAutomationPageSize = 16384;
+#else
+const size_t kAutomationPageSize = 4096;
+#endif
+
+struct alignas(kAutomationPageSize) ReadOnlyPage final {
+ bool mNonLocalConnectionsDisabled = false;
+ bool mTurnOffAllSecurityPref = false;
+
+ static void Init();
+
+#ifdef MOZ_TSAN
+ // TSan is confused by write access to read-only section.
+ static ReadOnlyPage sInstance;
+#else
+ static const volatile ReadOnlyPage sInstance;
+#endif
+
+ private:
+ constexpr ReadOnlyPage() = default;
+ ReadOnlyPage(const ReadOnlyPage&) = delete;
+ void operator=(const ReadOnlyPage&) = delete;
+
+ static void Write(const volatile bool* aPtr, bool aValue);
+};
+
+inline bool AreNonLocalConnectionsDisabled() {
+ return ReadOnlyPage::sInstance.mNonLocalConnectionsDisabled;
+}
+
+inline bool IsInAutomation() {
+ if (!ReadOnlyPage::sInstance.mTurnOffAllSecurityPref) {
+ return false;
+ }
+ MOZ_RELEASE_ASSERT(AreNonLocalConnectionsDisabled());
+ return true;
+}
+
+void InitializeJSContext();
+
+/**
+ * Extract the native nsID object from a JS ID, IfaceID, ClassID, or ContractID
+ * value.
+ *
+ * Returns 'Nothing()' if 'aVal' does is not one of the supported ID types.
+ */
+mozilla::Maybe<nsID> JSValue2ID(JSContext* aCx, JS::Handle<JS::Value> aVal);
+
+/**
+ * Reflect an ID into JS
+ */
+bool ID2JSValue(JSContext* aCx, const nsID& aId,
+ JS::MutableHandle<JS::Value> aVal);
+
+/**
+ * Reflect an IfaceID into JS
+ *
+ * This object will expose constants from the selected interface, and support
+ * 'instanceof', in addition to the other methods available on JS ID objects.
+ *
+ * Use 'xpc::JSValue2ID' to unwrap JS::Values created with this function.
+ */
+bool IfaceID2JSValue(JSContext* aCx, const nsXPTInterfaceInfo& aInfo,
+ JS::MutableHandle<JS::Value> aVal);
+
+/**
+ * Reflect a ContractID into JS
+ *
+ * This object will expose 'getService' and 'createInstance' methods in addition
+ * to the other methods available on nsID objects.
+ *
+ * Use 'xpc::JSValue2ID' to unwrap JS::Values created with this function.
+ */
+bool ContractID2JSValue(JSContext* aCx, JSString* aContract,
+ JS::MutableHandle<JS::Value> aVal);
+
+class JSStackFrameBase {
+ public:
+ virtual void Clear() = 0;
+};
+
+void RegisterJSStackFrame(JS::Realm* aRealm, JSStackFrameBase* aStackFrame);
+void UnregisterJSStackFrame(JS::Realm* aRealm, JSStackFrameBase* aStackFrame);
+void NukeJSStackFrames(JS::Realm* aRealm);
+
+// Check whether the given jsid is a property name (string or symbol) whose
+// value can be gotten cross-origin. Cross-origin gets always return undefined
+// as the value, unless the Xray actually provides a different value.
+bool IsCrossOriginWhitelistedProp(JSContext* cx,
+ JS::Handle<JS::PropertyKey> id);
+
+// Appends to props the jsids for property names (strings or symbols) whose
+// value can be gotten cross-origin.
+bool AppendCrossOriginWhitelistedPropNames(
+ JSContext* cx, JS::MutableHandle<JS::StackGCVector<JS::PropertyKey>> props);
+} // namespace xpc
+
+namespace mozilla {
+namespace dom {
+
+/**
+ * This is used to prevent UA widget code from directly creating and adopting
+ * nodes via the content document, since they should use the special
+ * create-and-insert apis instead.
+ */
+bool IsNotUAWidget(JSContext* cx, JSObject* /* unused */);
+
+/**
+ * A test for whether WebIDL methods that should only be visible to
+ * chrome, XBL scopes, or UA Widget scopes.
+ */
+bool IsChromeOrUAWidget(JSContext* cx, JSObject* /* unused */);
+
+/**
+ * Same as IsChromeOrUAWidget but can be used in worker threads as well.
+ */
+bool ThreadSafeIsChromeOrUAWidget(JSContext* cx, JSObject* obj);
+
+} // namespace dom
+
+/**
+ * Fill the given vector with the buildid.
+ */
+bool GetBuildId(JS::BuildIdCharVector* aBuildID);
+
+} // namespace mozilla
+
+#endif