summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/src/xpcprivate.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/xpconnect/src/xpcprivate.h')
-rw-r--r--js/xpconnect/src/xpcprivate.h3426
1 files changed, 3426 insertions, 0 deletions
diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h
new file mode 100644
index 000000000..d7d5586b8
--- /dev/null
+++ b/js/xpconnect/src/xpcprivate.h
@@ -0,0 +1,3426 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=99: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * XPConnect allows JS code to manipulate C++ object and C++ code to manipulate
+ * JS objects. JS manipulation of C++ objects tends to be significantly more
+ * complex. This comment explains how it is orchestrated by XPConnect.
+ *
+ * For each C++ object to be manipulated in JS, there is a corresponding JS
+ * object. This is called the "flattened JS object". By default, there is an
+ * additional C++ object involved of type XPCWrappedNative. The XPCWrappedNative
+ * holds pointers to the C++ object and the flat JS object.
+ *
+ * All XPCWrappedNative objects belong to an XPCWrappedNativeScope. These scopes
+ * are essentially in 1:1 correspondence with JS global objects. The
+ * XPCWrappedNativeScope has a pointer to the JS global object. The parent of a
+ * flattened JS object is, by default, the global JS object corresponding to the
+ * wrapper's XPCWrappedNativeScope (the exception to this rule is when a
+ * PreCreate hook asks for a different parent; see nsIXPCScriptable below).
+ *
+ * Some C++ objects (notably DOM objects) have information associated with them
+ * that lists the interfaces implemented by these objects. A C++ object exposes
+ * this information by implementing nsIClassInfo. If a C++ object implements
+ * nsIClassInfo, then JS code can call its methods without needing to use
+ * QueryInterface first. Typically, all instances of a C++ class share the same
+ * nsIClassInfo instance. (That is, obj->QueryInterface(nsIClassInfo) returns
+ * the same result for every obj of a given class.)
+ *
+ * XPConnect tracks nsIClassInfo information in an XPCWrappedNativeProto object.
+ * A given XPCWrappedNativeScope will have one XPCWrappedNativeProto for each
+ * nsIClassInfo instance being used. The XPCWrappedNativeProto has an associated
+ * JS object, which is used as the prototype of all flattened JS objects created
+ * for C++ objects with the given nsIClassInfo.
+ *
+ * Each XPCWrappedNativeProto has a pointer to its XPCWrappedNativeScope. If an
+ * XPCWrappedNative wraps a C++ object with class info, then it points to its
+ * XPCWrappedNativeProto. Otherwise it points to its XPCWrappedNativeScope. (The
+ * pointers are smooshed together in a tagged union.) Either way it can reach
+ * its scope.
+ *
+ * An XPCWrappedNativeProto keeps track of the set of interfaces implemented by
+ * the C++ object in an XPCNativeSet. (The list of interfaces is obtained by
+ * calling a method on the nsIClassInfo.) An XPCNativeSet is a collection of
+ * XPCNativeInterfaces. Each interface stores the list of members, which can be
+ * methods, constants, getters, or setters.
+ *
+ * An XPCWrappedNative also points to an XPCNativeSet. Initially this starts out
+ * the same as the XPCWrappedNativeProto's set. If there is no proto, it starts
+ * out as a singleton set containing nsISupports. If JS code QI's new interfaces
+ * outside of the existing set, the set will grow. All QueryInterface results
+ * are cached in XPCWrappedNativeTearOff objects, which are linked off of the
+ * XPCWrappedNative.
+ *
+ * Besides having class info, a C++ object may be "scriptable" (i.e., implement
+ * nsIXPCScriptable). This allows it to implement a more DOM-like interface,
+ * besides just exposing XPCOM methods and constants. An nsIXPCScriptable
+ * instance has hooks that correspond to all the normal JSClass hooks. Each
+ * nsIXPCScriptable instance is mirrored by an XPCNativeScriptableInfo in
+ * XPConnect. These can have pointers from XPCWrappedNativeProto and
+ * XPCWrappedNative (since C++ objects can have scriptable info without having
+ * class info).
+ */
+
+/* All the XPConnect private declarations - only include locally. */
+
+#ifndef xpcprivate_h___
+#define xpcprivate_h___
+
+#include "mozilla/Alignment.h"
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/CycleCollectedJSContext.h"
+#include "mozilla/GuardObjects.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/UniquePtr.h"
+
+#include "mozilla/dom/ScriptSettings.h"
+
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xpcpublic.h"
+#include "js/TracingAPI.h"
+#include "js/WeakMapPtr.h"
+#include "PLDHashTable.h"
+#include "nscore.h"
+#include "nsXPCOM.h"
+#include "nsAutoPtr.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsDebug.h"
+#include "nsISupports.h"
+#include "nsIServiceManager.h"
+#include "nsIClassInfoImpl.h"
+#include "nsIComponentManager.h"
+#include "nsIComponentRegistrar.h"
+#include "nsISupportsPrimitives.h"
+#include "nsMemory.h"
+#include "nsIXPConnect.h"
+#include "nsIInterfaceInfo.h"
+#include "nsIXPCScriptable.h"
+#include "nsIObserver.h"
+#include "nsWeakReference.h"
+#include "nsCOMPtr.h"
+#include "nsXPTCUtils.h"
+#include "xptinfo.h"
+#include "XPCForwards.h"
+#include "XPCLog.h"
+#include "xpccomponents.h"
+#include "xpcexception.h"
+#include "xpcjsid.h"
+#include "prenv.h"
+#include "prclist.h"
+#include "prcvar.h"
+#include "nsString.h"
+#include "nsReadableUtils.h"
+#include "nsXPIDLString.h"
+
+#include "MainThreadUtils.h"
+
+#include "nsIConsoleService.h"
+#include "nsIScriptError.h"
+#include "nsIException.h"
+
+#include "nsVariant.h"
+#include "nsIPropertyBag.h"
+#include "nsIProperty.h"
+#include "nsCOMArray.h"
+#include "nsTArray.h"
+#include "nsBaseHashtable.h"
+#include "nsHashKeys.h"
+#include "nsWrapperCache.h"
+#include "nsStringBuffer.h"
+#include "nsDataHashtable.h"
+#include "nsDeque.h"
+
+#include "nsIScriptSecurityManager.h"
+
+#include "nsIPrincipal.h"
+#include "nsJSPrincipals.h"
+#include "nsIScriptObjectPrincipal.h"
+#include "xpcObjectHelper.h"
+
+#include "SandboxPrivate.h"
+#include "BackstagePass.h"
+#include "nsAXPCNativeCallContext.h"
+
+#ifdef XP_WIN
+// Nasty MS defines
+#ifdef GetClassInfo
+#undef GetClassInfo
+#endif
+#ifdef GetClassName
+#undef GetClassName
+#endif
+#endif /* XP_WIN */
+
+/***************************************************************************/
+// default initial sizes for maps (hashtables)
+
+#define XPC_JS_MAP_LENGTH 32
+#define XPC_JS_CLASS_MAP_LENGTH 32
+
+#define XPC_NATIVE_MAP_LENGTH 8
+#define XPC_NATIVE_PROTO_MAP_LENGTH 8
+#define XPC_DYING_NATIVE_PROTO_MAP_LENGTH 8
+#define XPC_NATIVE_INTERFACE_MAP_LENGTH 32
+#define XPC_NATIVE_SET_MAP_LENGTH 32
+#define XPC_THIS_TRANSLATOR_MAP_LENGTH 4
+#define XPC_WRAPPER_MAP_LENGTH 8
+
+/***************************************************************************/
+// data declarations...
+extern const char XPC_CONTEXT_STACK_CONTRACTID[];
+extern const char XPC_EXCEPTION_CONTRACTID[];
+extern const char XPC_CONSOLE_CONTRACTID[];
+extern const char XPC_SCRIPT_ERROR_CONTRACTID[];
+extern const char XPC_ID_CONTRACTID[];
+extern const char XPC_XPCONNECT_CONTRACTID[];
+
+/***************************************************************************/
+// Useful macros...
+
+#define XPC_STRING_GETTER_BODY(dest, src) \
+ NS_ENSURE_ARG_POINTER(dest); \
+ char* result; \
+ if (src) \
+ result = (char*) nsMemory::Clone(src, \
+ sizeof(char)*(strlen(src)+1)); \
+ else \
+ result = nullptr; \
+ *dest = result; \
+ return (result || !src) ? NS_OK : NS_ERROR_OUT_OF_MEMORY
+
+// If IS_WN_CLASS for the JSClass of an object is true, the object is a
+// wrappednative wrapper, holding the XPCWrappedNative in its private slot.
+static inline bool IS_WN_CLASS(const js::Class* clazz)
+{
+ return clazz->isWrappedNative();
+}
+
+static inline bool IS_WN_REFLECTOR(JSObject* obj)
+{
+ return IS_WN_CLASS(js::GetObjectClass(obj));
+}
+
+/***************************************************************************
+****************************************************************************
+*
+* Core runtime and context classes...
+*
+****************************************************************************
+***************************************************************************/
+
+// We have a general rule internally that getters that return addref'd interface
+// pointer generally do so using an 'out' parm. When interface pointers are
+// returned as function call result values they are not addref'd. Exceptions
+// to this rule are noted explicitly.
+
+class nsXPConnect final : public nsIXPConnect
+{
+public:
+ // all the interface method declarations...
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIXPCONNECT
+
+ // non-interface implementation
+public:
+ // These get non-addref'd pointers
+ static nsXPConnect* XPConnect()
+ {
+ // Do a release-mode assert that we're not doing anything significant in
+ // XPConnect off the main thread. If you're an extension developer hitting
+ // this, you need to change your code. See bug 716167.
+ if (!MOZ_LIKELY(NS_IsMainThread()))
+ MOZ_CRASH();
+
+ return gSelf;
+ }
+
+ static XPCJSContext* GetContextInstance();
+ XPCJSContext* GetContext() {return mContext;}
+
+ static bool IsISupportsDescendant(nsIInterfaceInfo* info);
+
+ static nsIScriptSecurityManager* SecurityManager()
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(gScriptSecurityManager);
+ return gScriptSecurityManager;
+ }
+
+ static nsIPrincipal* SystemPrincipal()
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(gSystemPrincipal);
+ return gSystemPrincipal;
+ }
+
+ // This returns an AddRef'd pointer. It does not do this with an 'out' param
+ // only because this form is required by the generic module macro:
+ // NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR
+ static nsXPConnect* GetSingleton();
+
+ // Called by module code in dll startup
+ static void InitStatics();
+ // Called by module code on dll shutdown.
+ static void ReleaseXPConnectSingleton();
+
+ bool IsShuttingDown() const {return mShuttingDown;}
+
+ nsresult GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info);
+ nsresult GetInfoForName(const char * name, nsIInterfaceInfo** info);
+
+ virtual nsIPrincipal* GetPrincipal(JSObject* obj,
+ bool allowShortCircuit) const override;
+
+ void RecordTraversal(void* p, nsISupports* s);
+ virtual char* DebugPrintJSStack(bool showArgs,
+ bool showLocals,
+ bool showThisProps) override;
+
+protected:
+ virtual ~nsXPConnect();
+
+ nsXPConnect();
+
+private:
+ // Singleton instance
+ static nsXPConnect* gSelf;
+ static bool gOnceAliveNowDead;
+
+ XPCJSContext* mContext;
+ bool mShuttingDown;
+
+public:
+ static nsIScriptSecurityManager* gScriptSecurityManager;
+ static nsIPrincipal* gSystemPrincipal;
+};
+
+/***************************************************************************/
+
+class XPCRootSetElem
+{
+public:
+ XPCRootSetElem()
+ {
+#ifdef DEBUG
+ mNext = nullptr;
+ mSelfp = nullptr;
+#endif
+ }
+
+ ~XPCRootSetElem()
+ {
+ MOZ_ASSERT(!mNext, "Must be unlinked");
+ MOZ_ASSERT(!mSelfp, "Must be unlinked");
+ }
+
+ inline XPCRootSetElem* GetNextRoot() { return mNext; }
+ void AddToRootSet(XPCRootSetElem** listHead);
+ void RemoveFromRootSet();
+
+private:
+ XPCRootSetElem* mNext;
+ XPCRootSetElem** mSelfp;
+};
+
+/***************************************************************************/
+
+// In the current xpconnect system there can only be one XPCJSContext.
+// So, xpconnect can only be used on one JSContext within the process.
+
+class WatchdogManager;
+
+enum WatchdogTimestampCategory
+{
+ TimestampContextStateChange = 0,
+ TimestampWatchdogWakeup,
+ TimestampWatchdogHibernateStart,
+ TimestampWatchdogHibernateStop,
+ TimestampCount
+};
+
+class AsyncFreeSnowWhite;
+
+template <class StringType>
+class ShortLivedStringBuffer
+{
+public:
+ StringType* Create()
+ {
+ for (uint32_t i = 0; i < ArrayLength(mStrings); ++i) {
+ if (!mStrings[i]) {
+ mStrings[i].emplace();
+ return mStrings[i].ptr();
+ }
+ }
+
+ // All our internal string wrappers are used, allocate a new string.
+ return new StringType();
+ }
+
+ void Destroy(StringType* string)
+ {
+ for (uint32_t i = 0; i < ArrayLength(mStrings); ++i) {
+ if (mStrings[i] && mStrings[i].ptr() == string) {
+ // One of our internal strings is no longer in use, mark
+ // it as such and free its data.
+ mStrings[i].reset();
+ return;
+ }
+ }
+
+ // We're done with a string that's not one of our internal
+ // strings, delete it.
+ delete string;
+ }
+
+ ~ShortLivedStringBuffer()
+ {
+#ifdef DEBUG
+ for (uint32_t i = 0; i < ArrayLength(mStrings); ++i) {
+ MOZ_ASSERT(!mStrings[i], "Short lived string still in use");
+ }
+#endif
+ }
+
+private:
+ mozilla::Maybe<StringType> mStrings[2];
+};
+
+class XPCJSContext final : public mozilla::CycleCollectedJSContext
+{
+public:
+ static XPCJSContext* newXPCJSContext();
+ static XPCJSContext* Get() { return nsXPConnect::XPConnect()->GetContext(); }
+
+ void RemoveWrappedJS(nsXPCWrappedJS* wrapper);
+ void AssertInvalidWrappedJSNotInTable(nsXPCWrappedJS* wrapper) const;
+
+ XPCCallContext* GetCallContext() const {return mCallContext;}
+ XPCCallContext* SetCallContext(XPCCallContext* ccx)
+ {XPCCallContext* old = mCallContext; mCallContext = ccx; return old;}
+
+ jsid GetResolveName() const {return mResolveName;}
+ jsid SetResolveName(jsid name)
+ {jsid old = mResolveName; mResolveName = name; return old;}
+
+ XPCWrappedNative* GetResolvingWrapper() const {return mResolvingWrapper;}
+ XPCWrappedNative* SetResolvingWrapper(XPCWrappedNative* w)
+ {XPCWrappedNative* old = mResolvingWrapper;
+ mResolvingWrapper = w; return old;}
+
+ JSObject2WrappedJSMap* GetMultiCompartmentWrappedJSMap() const
+ {return mWrappedJSMap;}
+
+ IID2WrappedJSClassMap* GetWrappedJSClassMap() const
+ {return mWrappedJSClassMap;}
+
+ IID2NativeInterfaceMap* GetIID2NativeInterfaceMap() const
+ {return mIID2NativeInterfaceMap;}
+
+ ClassInfo2NativeSetMap* GetClassInfo2NativeSetMap() const
+ {return mClassInfo2NativeSetMap;}
+
+ NativeSetMap* GetNativeSetMap() const
+ {return mNativeSetMap;}
+
+ IID2ThisTranslatorMap* GetThisTranslatorMap() const
+ {return mThisTranslatorMap;}
+
+ XPCWrappedNativeProtoMap* GetDyingWrappedNativeProtoMap() const
+ {return mDyingWrappedNativeProtoMap;}
+
+ bool JSContextInitialized(JSContext* cx);
+
+ virtual bool
+ DescribeCustomObjects(JSObject* aObject, const js::Class* aClasp,
+ char (&aName)[72]) const override;
+ virtual bool
+ NoteCustomGCThingXPCOMChildren(const js::Class* aClasp, JSObject* aObj,
+ nsCycleCollectionTraversalCallback& aCb) const override;
+
+ virtual void BeforeProcessTask(bool aMightBlock) override;
+ virtual void AfterProcessTask(uint32_t aNewRecursionDepth) override;
+
+ /**
+ * Infrastructure for classes that need to defer part of the finalization
+ * until after the GC has run, for example for objects that we don't want to
+ * destroy during the GC.
+ */
+
+public:
+ bool GetDoingFinalization() const {return mDoingFinalization;}
+
+ // Mapping of often used strings to jsid atoms that live 'forever'.
+ //
+ // To add a new string: add to this list and to XPCJSContext::mStrings
+ // at the top of XPCJSContext.cpp
+ enum {
+ IDX_CONSTRUCTOR = 0 ,
+ IDX_TO_STRING ,
+ IDX_TO_SOURCE ,
+ IDX_LAST_RESULT ,
+ IDX_RETURN_CODE ,
+ IDX_VALUE ,
+ IDX_QUERY_INTERFACE ,
+ IDX_COMPONENTS ,
+ IDX_WRAPPED_JSOBJECT ,
+ IDX_OBJECT ,
+ IDX_FUNCTION ,
+ IDX_PROTOTYPE ,
+ IDX_CREATE_INSTANCE ,
+ IDX_ITEM ,
+ IDX_PROTO ,
+ IDX_ITERATOR ,
+ IDX_EXPOSEDPROPS ,
+ IDX_EVAL ,
+ IDX_CONTROLLERS ,
+ IDX_REALFRAMEELEMENT ,
+ IDX_LENGTH ,
+ IDX_NAME ,
+ IDX_UNDEFINED ,
+ IDX_EMPTYSTRING ,
+ IDX_FILENAME ,
+ IDX_LINENUMBER ,
+ IDX_COLUMNNUMBER ,
+ IDX_STACK ,
+ IDX_MESSAGE ,
+ IDX_LASTINDEX ,
+ IDX_TOTAL_COUNT // just a count of the above
+ };
+
+ JS::HandleId GetStringID(unsigned index) const
+ {
+ MOZ_ASSERT(index < IDX_TOTAL_COUNT, "index out of range");
+ // fromMarkedLocation() is safe because the string is interned.
+ return JS::HandleId::fromMarkedLocation(&mStrIDs[index]);
+ }
+ JS::HandleValue GetStringJSVal(unsigned index) const
+ {
+ MOZ_ASSERT(index < IDX_TOTAL_COUNT, "index out of range");
+ // fromMarkedLocation() is safe because the string is interned.
+ return JS::HandleValue::fromMarkedLocation(&mStrJSVals[index]);
+ }
+ const char* GetStringName(unsigned index) const
+ {
+ MOZ_ASSERT(index < IDX_TOTAL_COUNT, "index out of range");
+ return mStrings[index];
+ }
+
+ virtual bool UsefulToMergeZones() const override;
+ void TraceNativeBlackRoots(JSTracer* trc) override;
+ void TraceAdditionalNativeGrayRoots(JSTracer* aTracer) override;
+ void TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback& cb) override;
+ void UnmarkSkippableJSHolders();
+ void PrepareForForgetSkippable() override;
+ void BeginCycleCollectionCallback() override;
+ void EndCycleCollectionCallback(mozilla::CycleCollectorResults& aResults) override;
+ void DispatchDeferredDeletion(bool aContinuation, bool aPurge = false) override;
+
+ void CustomGCCallback(JSGCStatus status) override;
+ void CustomOutOfMemoryCallback() override;
+ void CustomLargeAllocationFailureCallback() override;
+ static void GCSliceCallback(JSContext* cx,
+ JS::GCProgress progress,
+ const JS::GCDescription& desc);
+ static void DoCycleCollectionCallback(JSContext* cx);
+ static void FinalizeCallback(JSFreeOp* fop,
+ JSFinalizeStatus status,
+ bool isZoneGC,
+ void* data);
+ static void WeakPointerZoneGroupCallback(JSContext* cx, void* data);
+ static void WeakPointerCompartmentCallback(JSContext* cx, JSCompartment* comp, void* data);
+
+ inline void AddVariantRoot(XPCTraceableVariant* variant);
+ inline void AddWrappedJSRoot(nsXPCWrappedJS* wrappedJS);
+ inline void AddObjectHolderRoot(XPCJSObjectHolder* holder);
+
+ void DebugDump(int16_t depth);
+
+ bool GCIsRunning() const {return mGCIsRunning;}
+
+ ~XPCJSContext();
+
+ ShortLivedStringBuffer<nsString> mScratchStrings;
+ ShortLivedStringBuffer<nsCString> mScratchCStrings;
+
+ void AddGCCallback(xpcGCCallback cb);
+ void RemoveGCCallback(xpcGCCallback cb);
+
+ static void ActivityCallback(void* arg, bool active);
+ static bool InterruptCallback(JSContext* cx);
+
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
+
+ AutoMarkingPtr** GetAutoRootsAdr() {return &mAutoRoots;}
+
+ JSObject* UnprivilegedJunkScope() { return mUnprivilegedJunkScope; }
+ JSObject* PrivilegedJunkScope() { return mPrivilegedJunkScope; }
+ JSObject* CompilationScope() { return mCompilationScope; }
+
+ void InitSingletonScopes();
+ void DeleteSingletonScopes();
+
+ PRTime GetWatchdogTimestamp(WatchdogTimestampCategory aCategory);
+
+ nsresult GetPendingResult() { return mPendingResult; }
+ void SetPendingResult(nsresult rv) { mPendingResult = rv; }
+
+private:
+ XPCJSContext();
+
+ MOZ_IS_CLASS_INIT
+ nsresult Initialize();
+
+ void ReleaseIncrementally(nsTArray<nsISupports*>& array);
+
+ static const char* const mStrings[IDX_TOTAL_COUNT];
+ jsid mStrIDs[IDX_TOTAL_COUNT];
+ JS::Value mStrJSVals[IDX_TOTAL_COUNT];
+
+ XPCCallContext* mCallContext;
+ AutoMarkingPtr* mAutoRoots;
+ jsid mResolveName;
+ XPCWrappedNative* mResolvingWrapper;
+ JSObject2WrappedJSMap* mWrappedJSMap;
+ IID2WrappedJSClassMap* mWrappedJSClassMap;
+ IID2NativeInterfaceMap* mIID2NativeInterfaceMap;
+ ClassInfo2NativeSetMap* mClassInfo2NativeSetMap;
+ NativeSetMap* mNativeSetMap;
+ IID2ThisTranslatorMap* mThisTranslatorMap;
+ XPCWrappedNativeProtoMap* mDyingWrappedNativeProtoMap;
+ bool mGCIsRunning;
+ nsTArray<nsISupports*> mNativesToReleaseArray;
+ bool mDoingFinalization;
+ XPCRootSetElem* mVariantRoots;
+ XPCRootSetElem* mWrappedJSRoots;
+ XPCRootSetElem* mObjectHolderRoots;
+ nsTArray<xpcGCCallback> extraGCCallbacks;
+ RefPtr<WatchdogManager> mWatchdogManager;
+ JS::GCSliceCallback mPrevGCSliceCallback;
+ JS::DoCycleCollectionCallback mPrevDoCycleCollectionCallback;
+ JS::PersistentRootedObject mUnprivilegedJunkScope;
+ JS::PersistentRootedObject mPrivilegedJunkScope;
+ JS::PersistentRootedObject mCompilationScope;
+ RefPtr<AsyncFreeSnowWhite> mAsyncSnowWhiteFreer;
+
+ // If we spend too much time running JS code in an event handler, then we
+ // want to show the slow script UI. The timeout T is controlled by prefs. We
+ // invoke the interrupt callback once after T/2 seconds and set
+ // mSlowScriptSecondHalf to true. After another T/2 seconds, we invoke the
+ // interrupt callback again. Since mSlowScriptSecondHalf is now true, it
+ // shows the slow script UI. The reason we invoke the callback twice is to
+ // ensure that putting the computer to sleep while running a script doesn't
+ // cause the UI to be shown. If the laptop goes to sleep during one of the
+ // timeout periods, the script still has the other T/2 seconds to complete
+ // before the slow script UI is shown.
+ bool mSlowScriptSecondHalf;
+
+ // mSlowScriptCheckpoint is set to the time when:
+ // 1. We started processing the current event, or
+ // 2. mSlowScriptSecondHalf was set to true
+ // (whichever comes later). We use it to determine whether the interrupt
+ // callback needs to do anything.
+ mozilla::TimeStamp mSlowScriptCheckpoint;
+ // Accumulates total time we actually waited for telemetry
+ mozilla::TimeDuration mSlowScriptActualWait;
+ bool mTimeoutAccumulated;
+
+ // mPendingResult is used to implement Components.returnCode. Only really
+ // meaningful while calling through XPCWrappedJS.
+ nsresult mPendingResult;
+
+ friend class Watchdog;
+ friend class AutoLockWatchdog;
+ friend class XPCIncrementalReleaseRunnable;
+};
+
+/***************************************************************************/
+
+// No virtuals
+// XPCCallContext is ALWAYS declared as a local variable in some function;
+// i.e. instance lifetime is always controled by some C++ function returning.
+//
+// These things are created frequently in many places. We *intentionally* do
+// not inialialize all members in order to save on construction overhead.
+// Some constructor pass more valid params than others. We init what must be
+// init'd and leave other members undefined. In debug builds the accessors
+// use a CHECK_STATE macro to track whether or not the object is in a valid
+// state to answer the question a caller might be asking. As long as this
+// class is maintained correctly it can do its job without a bunch of added
+// overhead from useless initializations and non-DEBUG error checking.
+//
+// Note that most accessors are inlined.
+
+class MOZ_STACK_CLASS XPCCallContext final : public nsAXPCNativeCallContext
+{
+public:
+ NS_IMETHOD GetCallee(nsISupports** aResult);
+ NS_IMETHOD GetCalleeMethodIndex(uint16_t* aResult);
+ NS_IMETHOD GetJSContext(JSContext** aResult);
+ NS_IMETHOD GetArgc(uint32_t* aResult);
+ NS_IMETHOD GetArgvPtr(JS::Value** aResult);
+ NS_IMETHOD GetCalleeInterface(nsIInterfaceInfo** aResult);
+ NS_IMETHOD GetCalleeClassInfo(nsIClassInfo** aResult);
+ NS_IMETHOD GetPreviousCallContext(nsAXPCNativeCallContext** aResult);
+
+ enum {NO_ARGS = (unsigned) -1};
+
+ explicit XPCCallContext(JSContext* cx,
+ JS::HandleObject obj = nullptr,
+ JS::HandleObject funobj = nullptr,
+ JS::HandleId id = JSID_VOIDHANDLE,
+ unsigned argc = NO_ARGS,
+ JS::Value* argv = nullptr,
+ JS::Value* rval = nullptr);
+
+ virtual ~XPCCallContext();
+
+ inline bool IsValid() const ;
+
+ inline XPCJSContext* GetContext() const ;
+ inline JSContext* GetJSContext() const ;
+ inline bool GetContextPopRequired() const ;
+ inline XPCCallContext* GetPrevCallContext() const ;
+
+ inline JSObject* GetFlattenedJSObject() const ;
+ inline nsISupports* GetIdentityObject() const ;
+ inline XPCWrappedNative* GetWrapper() const ;
+ inline XPCWrappedNativeProto* GetProto() const ;
+
+ inline bool CanGetTearOff() const ;
+ inline XPCWrappedNativeTearOff* GetTearOff() const ;
+
+ inline XPCNativeScriptableInfo* GetScriptableInfo() const ;
+ inline bool CanGetSet() const ;
+ inline XPCNativeSet* GetSet() const ;
+ inline bool CanGetInterface() const ;
+ inline XPCNativeInterface* GetInterface() const ;
+ inline XPCNativeMember* GetMember() const ;
+ inline bool HasInterfaceAndMember() const ;
+ inline jsid GetName() const ;
+ inline bool GetStaticMemberIsLocal() const ;
+ inline unsigned GetArgc() const ;
+ inline JS::Value* GetArgv() const ;
+ inline JS::Value* GetRetVal() const ;
+
+ inline uint16_t GetMethodIndex() const ;
+ inline void SetMethodIndex(uint16_t index) ;
+
+ inline jsid GetResolveName() const;
+ inline jsid SetResolveName(JS::HandleId name);
+
+ inline XPCWrappedNative* GetResolvingWrapper() const;
+ inline XPCWrappedNative* SetResolvingWrapper(XPCWrappedNative* w);
+
+ inline void SetRetVal(const JS::Value& val);
+
+ void SetName(jsid name);
+ void SetArgsAndResultPtr(unsigned argc, JS::Value* argv, JS::Value* rval);
+ void SetCallInfo(XPCNativeInterface* iface, XPCNativeMember* member,
+ bool isSetter);
+
+ nsresult CanCallNow();
+
+ void SystemIsBeingShutDown();
+
+ operator JSContext*() const {return GetJSContext();}
+
+private:
+
+ // no copy ctor or assignment allowed
+ XPCCallContext(const XPCCallContext& r) = delete;
+ XPCCallContext& operator= (const XPCCallContext& r) = delete;
+
+private:
+ // posible values for mState
+ enum State {
+ INIT_FAILED,
+ SYSTEM_SHUTDOWN,
+ HAVE_CONTEXT,
+ HAVE_OBJECT,
+ HAVE_NAME,
+ HAVE_ARGS,
+ READY_TO_CALL,
+ CALL_DONE
+ };
+
+#ifdef DEBUG
+inline void CHECK_STATE(int s) const {MOZ_ASSERT(mState >= s, "bad state");}
+#else
+#define CHECK_STATE(s) ((void)0)
+#endif
+
+private:
+ JSAutoRequest mAr;
+ State mState;
+
+ RefPtr<nsXPConnect> mXPC;
+
+ XPCJSContext* mXPCJSContext;
+ JSContext* mJSContext;
+
+ // ctor does not necessarily init the following. BEWARE!
+
+ XPCCallContext* mPrevCallContext;
+
+ XPCWrappedNative* mWrapper;
+ XPCWrappedNativeTearOff* mTearOff;
+
+ XPCNativeScriptableInfo* mScriptableInfo;
+
+ RefPtr<XPCNativeSet> mSet;
+ RefPtr<XPCNativeInterface> mInterface;
+ XPCNativeMember* mMember;
+
+ JS::RootedId mName;
+ bool mStaticMemberIsLocal;
+
+ unsigned mArgc;
+ JS::Value* mArgv;
+ JS::Value* mRetVal;
+
+ uint16_t mMethodIndex;
+};
+
+/***************************************************************************
+****************************************************************************
+*
+* Core classes for wrapped native objects for use from JavaScript...
+*
+****************************************************************************
+***************************************************************************/
+
+// These are the various JSClasses and callbacks whose use that required
+// visibility from more than one .cpp file.
+
+extern const js::Class XPC_WN_NoHelper_JSClass;
+extern const js::Class XPC_WN_NoMods_Proto_JSClass;
+extern const js::Class XPC_WN_ModsAllowed_Proto_JSClass;
+extern const js::Class XPC_WN_Tearoff_JSClass;
+#define XPC_WN_TEAROFF_RESERVED_SLOTS 1
+#define XPC_WN_TEAROFF_FLAT_OBJECT_SLOT 0
+extern const js::Class XPC_WN_NoHelper_Proto_JSClass;
+
+extern bool
+XPC_WN_CallMethod(JSContext* cx, unsigned argc, JS::Value* vp);
+
+extern bool
+XPC_WN_GetterSetter(JSContext* cx, unsigned argc, JS::Value* vp);
+
+// Maybe this macro should check for class->enumerate ==
+// XPC_WN_Shared_Proto_Enumerate or something rather than checking for
+// 4 classes?
+static inline bool IS_PROTO_CLASS(const js::Class* clazz)
+{
+ return clazz == &XPC_WN_NoMods_Proto_JSClass ||
+ clazz == &XPC_WN_ModsAllowed_Proto_JSClass;
+}
+
+typedef js::HashSet<size_t,
+ js::DefaultHasher<size_t>,
+ js::SystemAllocPolicy> InterpositionWhitelist;
+
+struct InterpositionWhitelistPair {
+ nsIAddonInterposition* interposition;
+ InterpositionWhitelist whitelist;
+};
+
+typedef nsTArray<InterpositionWhitelistPair> InterpositionWhitelistArray;
+
+/***************************************************************************/
+// XPCWrappedNativeScope is one-to-one with a JS global object.
+
+class nsIAddonInterposition;
+class nsXPCComponentsBase;
+class XPCWrappedNativeScope final : public PRCList
+{
+public:
+
+ XPCJSContext*
+ GetContext() const {return XPCJSContext::Get();}
+
+ Native2WrappedNativeMap*
+ GetWrappedNativeMap() const {return mWrappedNativeMap;}
+
+ ClassInfo2WrappedNativeProtoMap*
+ GetWrappedNativeProtoMap() const {return mWrappedNativeProtoMap;}
+
+ nsXPCComponentsBase*
+ GetComponents() const {return mComponents;}
+
+ // Forces the creation of a privileged |Components| object, even in
+ // content scopes. This will crash if used outside of automation.
+ void
+ ForcePrivilegedComponents();
+
+ bool AttachComponentsObject(JSContext* aCx);
+
+ // Returns the JS object reflection of the Components object.
+ bool
+ GetComponentsJSObject(JS::MutableHandleObject obj);
+
+ JSObject*
+ GetGlobalJSObject() const {
+ return mGlobalJSObject;
+ }
+
+ JSObject*
+ GetGlobalJSObjectPreserveColor() const {return mGlobalJSObject.unbarrieredGet();}
+
+ nsIPrincipal*
+ GetPrincipal() const {
+ JSCompartment* c = js::GetObjectCompartment(mGlobalJSObject);
+ return nsJSPrincipals::get(JS_GetCompartmentPrincipals(c));
+ }
+
+ JSObject*
+ GetExpandoChain(JS::HandleObject target);
+
+ bool
+ SetExpandoChain(JSContext* cx, JS::HandleObject target, JS::HandleObject chain);
+
+ static void
+ SystemIsBeingShutDown();
+
+ static void
+ TraceWrappedNativesInAllScopes(JSTracer* trc, XPCJSContext* cx);
+
+ void TraceSelf(JSTracer* trc) {
+ MOZ_ASSERT(mGlobalJSObject);
+ mGlobalJSObject.trace(trc, "XPCWrappedNativeScope::mGlobalJSObject");
+ }
+
+ void TraceInside(JSTracer* trc) {
+ if (mContentXBLScope)
+ mContentXBLScope.trace(trc, "XPCWrappedNativeScope::mXBLScope");
+ for (size_t i = 0; i < mAddonScopes.Length(); i++)
+ mAddonScopes[i].trace(trc, "XPCWrappedNativeScope::mAddonScopes");
+ if (mXrayExpandos.initialized())
+ mXrayExpandos.trace(trc);
+ }
+
+ static void
+ SuspectAllWrappers(XPCJSContext* cx, nsCycleCollectionNoteRootCallback& cb);
+
+ static void
+ SweepAllWrappedNativeTearOffs();
+
+ static void
+ UpdateWeakPointersAfterGC(XPCJSContext* cx);
+
+ static void
+ KillDyingScopes();
+
+ static void
+ DebugDumpAllScopes(int16_t depth);
+
+ void
+ DebugDump(int16_t depth);
+
+ struct ScopeSizeInfo {
+ explicit ScopeSizeInfo(mozilla::MallocSizeOf mallocSizeOf)
+ : mMallocSizeOf(mallocSizeOf),
+ mScopeAndMapSize(0),
+ mProtoAndIfaceCacheSize(0)
+ {}
+
+ mozilla::MallocSizeOf mMallocSizeOf;
+ size_t mScopeAndMapSize;
+ size_t mProtoAndIfaceCacheSize;
+ };
+
+ static void
+ AddSizeOfAllScopesIncludingThis(ScopeSizeInfo* scopeSizeInfo);
+
+ void
+ AddSizeOfIncludingThis(ScopeSizeInfo* scopeSizeInfo);
+
+ bool
+ IsValid() const {return mContext != nullptr;}
+
+ static bool
+ IsDyingScope(XPCWrappedNativeScope* scope);
+
+ typedef js::HashSet<JS::Heap<JSObject*>,
+ js::MovableCellHasher<JS::Heap<JSObject*>>,
+ js::SystemAllocPolicy> DOMExpandoSet;
+
+ bool RegisterDOMExpandoObject(JSObject* expando) {
+ // Expandos are proxy objects, and proxies are always tenured.
+ JS::AssertGCThingMustBeTenured(expando);
+ if (!mDOMExpandoSet) {
+ mDOMExpandoSet = new DOMExpandoSet();
+ if (!mDOMExpandoSet->init(8))
+ return false;
+ }
+ return mDOMExpandoSet->put(JS::Heap<JSObject*>(expando));
+ }
+ void RemoveDOMExpandoObject(JSObject* expando) {
+ if (mDOMExpandoSet) {
+ DOMExpandoSet::Ptr p = mDOMExpandoSet->lookup(JS::Heap<JSObject*>(expando));
+ MOZ_ASSERT(p.found());
+ mDOMExpandoSet->remove(p);
+ }
+ }
+
+ typedef js::HashMap<JSAddonId*,
+ nsCOMPtr<nsIAddonInterposition>,
+ js::PointerHasher<JSAddonId*, 3>,
+ js::SystemAllocPolicy> InterpositionMap;
+
+ typedef js::HashSet<JSAddonId*,
+ js::PointerHasher<JSAddonId*, 3>,
+ js::SystemAllocPolicy> AddonSet;
+
+ // Gets the appropriate scope object for XBL in this scope. The context
+ // must be same-compartment with the global upon entering, and the scope
+ // object is wrapped into the compartment of the global.
+ JSObject* EnsureContentXBLScope(JSContext* cx);
+
+ JSObject* EnsureAddonScope(JSContext* cx, JSAddonId* addonId);
+
+ XPCWrappedNativeScope(JSContext* cx, JS::HandleObject aGlobal);
+
+ nsAutoPtr<JSObject2JSObjectMap> mWaiverWrapperMap;
+
+ bool IsContentXBLScope() { return mIsContentXBLScope; }
+ bool AllowContentXBLScope();
+ bool UseContentXBLScope() { return mUseContentXBLScope; }
+ void ClearContentXBLScope() { mContentXBLScope = nullptr; }
+
+ bool IsAddonScope() { return mIsAddonScope; }
+
+ bool HasInterposition() { return mInterposition; }
+ nsCOMPtr<nsIAddonInterposition> GetInterposition();
+
+ static bool SetAddonInterposition(JSContext* cx,
+ JSAddonId* addonId,
+ nsIAddonInterposition* interp);
+
+ static InterpositionWhitelist* GetInterpositionWhitelist(nsIAddonInterposition* interposition);
+ static bool UpdateInterpositionWhitelist(JSContext* cx,
+ nsIAddonInterposition* interposition);
+
+ void SetAddonCallInterposition() { mHasCallInterpositions = true; }
+ bool HasCallInterposition() { return mHasCallInterpositions; };
+
+ static bool AllowCPOWsInAddon(JSContext* cx, JSAddonId* addonId, bool allow);
+
+protected:
+ virtual ~XPCWrappedNativeScope();
+
+ XPCWrappedNativeScope() = delete;
+
+private:
+ class ClearInterpositionsObserver final : public nsIObserver {
+ ~ClearInterpositionsObserver() {}
+
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+ };
+
+ static XPCWrappedNativeScope* gScopes;
+ static XPCWrappedNativeScope* gDyingScopes;
+
+ static bool gShutdownObserverInitialized;
+ static InterpositionMap* gInterpositionMap;
+ static AddonSet* gAllowCPOWAddonSet;
+
+ static InterpositionWhitelistArray* gInterpositionWhitelists;
+
+ XPCJSContext* mContext;
+ Native2WrappedNativeMap* mWrappedNativeMap;
+ ClassInfo2WrappedNativeProtoMap* mWrappedNativeProtoMap;
+ RefPtr<nsXPCComponentsBase> mComponents;
+ XPCWrappedNativeScope* mNext;
+ // The JS global object for this scope. If non-null, this will be the
+ // default parent for the XPCWrappedNatives that have us as the scope,
+ // unless a PreCreate hook overrides it. Note that this _may_ be null (see
+ // constructor).
+ JS::ObjectPtr mGlobalJSObject;
+
+ // XBL Scope. This is is a lazily-created sandbox for non-system scopes.
+ // EnsureContentXBLScope() decides whether it needs to be created or not.
+ // This reference is wrapped into the compartment of mGlobalJSObject.
+ JS::ObjectPtr mContentXBLScope;
+
+ // Lazily created sandboxes for addon code.
+ nsTArray<JS::ObjectPtr> mAddonScopes;
+
+ // This is a service that will be use to interpose on some property accesses on
+ // objects from other scope, for add-on compatibility reasons.
+ nsCOMPtr<nsIAddonInterposition> mInterposition;
+
+ // If this flag is set, we intercept function calls on vanilla JS function objects
+ // from this scope if the caller scope has mInterposition set.
+ bool mHasCallInterpositions;
+
+ nsAutoPtr<DOMExpandoSet> mDOMExpandoSet;
+
+ JS::WeakMapPtr<JSObject*, JSObject*> mXrayExpandos;
+
+ bool mIsContentXBLScope;
+ bool mIsAddonScope;
+
+ // For remote XUL domains, we run all XBL in the content scope for compat
+ // reasons (though we sometimes pref this off for automation). We separately
+ // track the result of this decision (mAllowContentXBLScope), from the decision
+ // of whether to actually _use_ an XBL scope (mUseContentXBLScope), which depends
+ // on the type of global and whether the compartment is system principal
+ // or not.
+ //
+ // This distinction is useful primarily because, if true, we know that we
+ // have no way of distinguishing XBL script from content script for the
+ // given scope. In these (unsupported) situations, we just always claim to
+ // be XBL.
+ bool mAllowContentXBLScope;
+ bool mUseContentXBLScope;
+};
+
+/***************************************************************************/
+// Slots we use for our functions
+#define XPC_FUNCTION_NATIVE_MEMBER_SLOT 0
+#define XPC_FUNCTION_PARENT_OBJECT_SLOT 1
+
+/***************************************************************************/
+// XPCNativeMember represents a single idl declared method, attribute or
+// constant.
+
+// Tight. No virtual methods. Can be bitwise copied (until any resolution done).
+
+class XPCNativeMember final
+{
+public:
+ static bool GetCallInfo(JSObject* funobj,
+ RefPtr<XPCNativeInterface>* pInterface,
+ XPCNativeMember** pMember);
+
+ jsid GetName() const {return mName;}
+
+ uint16_t GetIndex() const {return mIndex;}
+
+ bool GetConstantValue(XPCCallContext& ccx, XPCNativeInterface* iface,
+ JS::Value* pval)
+ {MOZ_ASSERT(IsConstant(),
+ "Only call this if you're sure this is a constant!");
+ return Resolve(ccx, iface, nullptr, pval);}
+
+ bool NewFunctionObject(XPCCallContext& ccx, XPCNativeInterface* iface,
+ JS::HandleObject parent, JS::Value* pval);
+
+ bool IsMethod() const
+ {return 0 != (mFlags & METHOD);}
+
+ bool IsConstant() const
+ {return 0 != (mFlags & CONSTANT);}
+
+ bool IsAttribute() const
+ {return 0 != (mFlags & GETTER);}
+
+ bool IsWritableAttribute() const
+ {return 0 != (mFlags & SETTER_TOO);}
+
+ bool IsReadOnlyAttribute() const
+ {return IsAttribute() && !IsWritableAttribute();}
+
+
+ void SetName(jsid a) {mName = a;}
+
+ void SetMethod(uint16_t index)
+ {mFlags = METHOD; mIndex = index;}
+
+ void SetConstant(uint16_t index)
+ {mFlags = CONSTANT; mIndex = index;}
+
+ void SetReadOnlyAttribute(uint16_t index)
+ {mFlags = GETTER; mIndex = index;}
+
+ void SetWritableAttribute()
+ {MOZ_ASSERT(mFlags == GETTER,"bad"); mFlags = GETTER | SETTER_TOO;}
+
+ static uint16_t GetMaxIndexInInterface()
+ {return (1<<12) - 1;}
+
+ inline XPCNativeInterface* GetInterface() const;
+
+ void SetIndexInInterface(uint16_t index)
+ {mIndexInInterface = index;}
+
+ /* default ctor - leave random contents */
+ XPCNativeMember() {MOZ_COUNT_CTOR(XPCNativeMember);}
+ ~XPCNativeMember() {MOZ_COUNT_DTOR(XPCNativeMember);}
+
+private:
+ bool Resolve(XPCCallContext& ccx, XPCNativeInterface* iface,
+ JS::HandleObject parent, JS::Value* vp);
+
+ enum {
+ METHOD = 0x01,
+ CONSTANT = 0x02,
+ GETTER = 0x04,
+ SETTER_TOO = 0x08
+ // If you add a flag here, you may need to make mFlags wider and either
+ // make mIndexInInterface narrower (and adjust
+ // XPCNativeInterface::NewInstance accordingly) or make this object
+ // bigger.
+ };
+
+private:
+ // our only data...
+ jsid mName;
+ uint16_t mIndex;
+ // mFlags needs to be wide enogh to hold the flags in the above enum.
+ uint16_t mFlags : 4;
+ // mIndexInInterface is the index of this in our XPCNativeInterface's
+ // mMembers. In theory our XPCNativeInterface could have as many as 2^15-1
+ // members (since mMemberCount is 15-bit) but in practice we prevent
+ // creation of XPCNativeInterfaces which have more than 2^12 members.
+ // If the width of this field changes, update GetMaxIndexInInterface.
+ uint16_t mIndexInInterface : 12;
+} JS_HAZ_NON_GC_POINTER; // Only stores a pinned string
+
+/***************************************************************************/
+// XPCNativeInterface represents a single idl declared interface. This is
+// primarily the set of XPCNativeMembers.
+
+// Tight. No virtual methods.
+
+class XPCNativeInterface final
+{
+ public:
+ NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(XPCNativeInterface,
+ DestroyInstance(this))
+
+ static already_AddRefed<XPCNativeInterface> GetNewOrUsed(const nsIID* iid);
+ static already_AddRefed<XPCNativeInterface> GetNewOrUsed(nsIInterfaceInfo* info);
+ static already_AddRefed<XPCNativeInterface> GetNewOrUsed(const char* name);
+ static already_AddRefed<XPCNativeInterface> GetISupports();
+
+ inline nsIInterfaceInfo* GetInterfaceInfo() const {return mInfo.get();}
+ inline jsid GetName() const {return mName;}
+
+ inline const nsIID* GetIID() const;
+ inline const char* GetNameString() const;
+ inline XPCNativeMember* FindMember(jsid name) const;
+
+ inline bool HasAncestor(const nsIID* iid) const;
+ static inline size_t OffsetOfMembers();
+
+ uint16_t GetMemberCount() const {
+ return mMemberCount;
+ }
+ XPCNativeMember* GetMemberAt(uint16_t i) {
+ MOZ_ASSERT(i < mMemberCount, "bad index");
+ return &mMembers[i];
+ }
+
+ void DebugDump(int16_t depth);
+
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
+
+ protected:
+ static already_AddRefed<XPCNativeInterface> NewInstance(nsIInterfaceInfo* aInfo);
+
+ XPCNativeInterface() = delete;
+ XPCNativeInterface(nsIInterfaceInfo* aInfo, jsid aName)
+ : mInfo(aInfo), mName(aName), mMemberCount(0)
+ {}
+ ~XPCNativeInterface();
+
+ void* operator new(size_t, void* p) CPP_THROW_NEW {return p;}
+
+ XPCNativeInterface(const XPCNativeInterface& r) = delete;
+ XPCNativeInterface& operator= (const XPCNativeInterface& r) = delete;
+
+ static void DestroyInstance(XPCNativeInterface* inst);
+
+private:
+ nsCOMPtr<nsIInterfaceInfo> mInfo;
+ jsid mName;
+ uint16_t mMemberCount;
+ XPCNativeMember mMembers[1]; // always last - object sized for array
+};
+
+/***************************************************************************/
+// XPCNativeSetKey is used to key a XPCNativeSet in a NativeSetMap.
+// It represents a new XPCNativeSet we are considering constructing, without
+// requiring that the set actually be built.
+
+class MOZ_STACK_CLASS XPCNativeSetKey final
+{
+public:
+ // This represents an existing set |baseSet|.
+ explicit XPCNativeSetKey(XPCNativeSet* baseSet)
+ : mBaseSet(baseSet), mAddition(nullptr)
+ {
+ MOZ_ASSERT(baseSet);
+ }
+
+ // This represents a new set containing only nsISupports and
+ // |addition|.
+ explicit XPCNativeSetKey(XPCNativeInterface* addition)
+ : mBaseSet(nullptr), mAddition(addition)
+ {
+ MOZ_ASSERT(addition);
+ }
+
+ // This represents the existing set |baseSet| with the interface
+ // |addition| inserted after existing interfaces. |addition| must
+ // not already be present in |baseSet|.
+ explicit XPCNativeSetKey(XPCNativeSet* baseSet,
+ XPCNativeInterface* addition);
+ ~XPCNativeSetKey() {}
+
+ XPCNativeSet* GetBaseSet() const {return mBaseSet;}
+ XPCNativeInterface* GetAddition() const {return mAddition;}
+
+ PLDHashNumber Hash() const;
+
+ // Allow shallow copy
+
+private:
+ RefPtr<XPCNativeSet> mBaseSet;
+ RefPtr<XPCNativeInterface> mAddition;
+};
+
+/***************************************************************************/
+// XPCNativeSet represents an ordered collection of XPCNativeInterface pointers.
+
+class XPCNativeSet final
+{
+ public:
+ NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(XPCNativeSet,
+ DestroyInstance(this))
+
+ static already_AddRefed<XPCNativeSet> GetNewOrUsed(const nsIID* iid);
+ static already_AddRefed<XPCNativeSet> GetNewOrUsed(nsIClassInfo* classInfo);
+ static already_AddRefed<XPCNativeSet> GetNewOrUsed(XPCNativeSetKey* key);
+
+ // This generates a union set.
+ //
+ // If preserveFirstSetOrder is true, the elements from |firstSet| come first,
+ // followed by any non-duplicate items from |secondSet|. If false, the same
+ // algorithm is applied; but if we detect that |secondSet| is a superset of
+ // |firstSet|, we return |secondSet| without worrying about whether the
+ // ordering might differ from |firstSet|.
+ static already_AddRefed<XPCNativeSet> GetNewOrUsed(XPCNativeSet* firstSet,
+ XPCNativeSet* secondSet,
+ bool preserveFirstSetOrder);
+
+ static void ClearCacheEntryForClassInfo(nsIClassInfo* classInfo);
+
+ inline bool FindMember(jsid name, XPCNativeMember** pMember,
+ uint16_t* pInterfaceIndex) const;
+
+ inline bool FindMember(jsid name, XPCNativeMember** pMember,
+ RefPtr<XPCNativeInterface>* pInterface) const;
+
+ inline bool FindMember(JS::HandleId name,
+ XPCNativeMember** pMember,
+ RefPtr<XPCNativeInterface>* pInterface,
+ XPCNativeSet* protoSet,
+ bool* pIsLocal) const;
+
+ inline bool HasInterface(XPCNativeInterface* aInterface) const;
+ inline bool HasInterfaceWithAncestor(XPCNativeInterface* aInterface) const;
+ inline bool HasInterfaceWithAncestor(const nsIID* iid) const;
+
+ inline XPCNativeInterface* FindInterfaceWithIID(const nsIID& iid) const;
+
+ inline XPCNativeInterface* FindNamedInterface(jsid name) const;
+
+ uint16_t GetMemberCount() const {
+ return mMemberCount;
+ }
+ uint16_t GetInterfaceCount() const {
+ return mInterfaceCount;
+ }
+ XPCNativeInterface** GetInterfaceArray() {
+ return mInterfaces;
+ }
+
+ XPCNativeInterface* GetInterfaceAt(uint16_t i)
+ {MOZ_ASSERT(i < mInterfaceCount, "bad index"); return mInterfaces[i];}
+
+ inline bool MatchesSetUpToInterface(const XPCNativeSet* other,
+ XPCNativeInterface* iface) const;
+
+ void DebugDump(int16_t depth);
+
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
+
+ protected:
+ static already_AddRefed<XPCNativeSet> NewInstance(nsTArray<RefPtr<XPCNativeInterface>>&& array);
+ static already_AddRefed<XPCNativeSet> NewInstanceMutate(XPCNativeSetKey* key);
+
+ XPCNativeSet()
+ : mMemberCount(0), mInterfaceCount(0)
+ {}
+ ~XPCNativeSet();
+ void* operator new(size_t, void* p) CPP_THROW_NEW {return p;}
+
+ static void DestroyInstance(XPCNativeSet* inst);
+
+ private:
+ uint16_t mMemberCount;
+ uint16_t mInterfaceCount;
+ // Always last - object sized for array.
+ // These are strong references.
+ XPCNativeInterface* mInterfaces[1];
+};
+
+/***************************************************************************/
+// XPCNativeScriptableFlags is a wrapper class that holds the flags returned
+// from calls to nsIXPCScriptable::GetScriptableFlags(). It has convenience
+// methods to check for particular bitflags.
+
+class XPCNativeScriptableFlags final
+{
+public:
+ explicit XPCNativeScriptableFlags(uint32_t flags = 0) : mFlags(flags) {}
+
+ uint32_t GetFlags() const { return mFlags; }
+ void SetFlags(uint32_t flags) { mFlags = flags; }
+
+ operator uint32_t() const { return GetFlags(); }
+
+ XPCNativeScriptableFlags(const XPCNativeScriptableFlags& r)
+ {
+ mFlags = r.GetFlags();
+ }
+
+ XPCNativeScriptableFlags& operator= (const XPCNativeScriptableFlags& r)
+ {
+ mFlags = r.GetFlags();
+ return *this;
+ }
+
+#ifdef GET_IT
+#undef GET_IT
+#endif
+#define GET_IT(f_) const { return 0 != (mFlags & nsIXPCScriptable:: f_ ); }
+
+ bool WantPreCreate() GET_IT(WANT_PRECREATE)
+ bool WantAddProperty() GET_IT(WANT_ADDPROPERTY)
+ bool WantGetProperty() GET_IT(WANT_GETPROPERTY)
+ bool WantSetProperty() GET_IT(WANT_SETPROPERTY)
+ bool WantEnumerate() GET_IT(WANT_ENUMERATE)
+ bool WantNewEnumerate() GET_IT(WANT_NEWENUMERATE)
+ bool WantResolve() GET_IT(WANT_RESOLVE)
+ bool WantFinalize() GET_IT(WANT_FINALIZE)
+ bool WantCall() GET_IT(WANT_CALL)
+ bool WantConstruct() GET_IT(WANT_CONSTRUCT)
+ bool WantHasInstance() GET_IT(WANT_HASINSTANCE)
+ bool UseJSStubForAddProperty() GET_IT(USE_JSSTUB_FOR_ADDPROPERTY)
+ bool UseJSStubForDelProperty() GET_IT(USE_JSSTUB_FOR_DELPROPERTY)
+ bool UseJSStubForSetProperty() GET_IT(USE_JSSTUB_FOR_SETPROPERTY)
+ bool DontEnumQueryInterface() GET_IT(DONT_ENUM_QUERY_INTERFACE)
+ bool DontAskInstanceForScriptable() GET_IT(DONT_ASK_INSTANCE_FOR_SCRIPTABLE)
+ bool ClassInfoInterfacesOnly() GET_IT(CLASSINFO_INTERFACES_ONLY)
+ bool AllowPropModsDuringResolve() GET_IT(ALLOW_PROP_MODS_DURING_RESOLVE)
+ bool AllowPropModsToPrototype() GET_IT(ALLOW_PROP_MODS_TO_PROTOTYPE)
+ bool IsGlobalObject() GET_IT(IS_GLOBAL_OBJECT)
+ bool DontReflectInterfaceNames() GET_IT(DONT_REFLECT_INTERFACE_NAMES)
+
+#undef GET_IT
+
+private:
+ uint32_t mFlags;
+};
+
+/***************************************************************************/
+// XPCNativeScriptableInfo is a trivial wrapper for nsIXPCScriptable which
+// should be removed eventually.
+
+class XPCNativeScriptableInfo final
+{
+public:
+ static XPCNativeScriptableInfo*
+ Construct(const XPCNativeScriptableCreateInfo* sci);
+
+ nsIXPCScriptable*
+ GetCallback() const { return mCallback; }
+
+ XPCNativeScriptableFlags
+ GetFlags() const { return XPCNativeScriptableFlags(mCallback->GetScriptableFlags()); }
+
+ const JSClass*
+ GetJSClass() { return Jsvalify(mCallback->GetClass()); }
+
+protected:
+ explicit XPCNativeScriptableInfo(nsIXPCScriptable* aCallback)
+ : mCallback(aCallback)
+ {
+ MOZ_COUNT_CTOR(XPCNativeScriptableInfo);
+ }
+public:
+ ~XPCNativeScriptableInfo()
+ {
+ MOZ_COUNT_DTOR(XPCNativeScriptableInfo);
+ }
+private:
+
+ // disable copy ctor and assignment
+ XPCNativeScriptableInfo(const XPCNativeScriptableInfo& r) = delete;
+ XPCNativeScriptableInfo& operator= (const XPCNativeScriptableInfo& r) = delete;
+
+private:
+ nsCOMPtr<nsIXPCScriptable> mCallback;
+};
+
+/***************************************************************************/
+// XPCNativeScriptableCreateInfo is used in creating new wrapper and protos.
+// it abstracts out the scriptable interface pointer and the flags. After
+// creation these are factored differently using XPCNativeScriptableInfo.
+
+class MOZ_STACK_CLASS XPCNativeScriptableCreateInfo final
+{
+public:
+
+ explicit XPCNativeScriptableCreateInfo(const XPCNativeScriptableInfo& si)
+ : mCallback(si.GetCallback()), mFlags(si.GetFlags()) {}
+
+ XPCNativeScriptableCreateInfo(already_AddRefed<nsIXPCScriptable>&& callback,
+ XPCNativeScriptableFlags flags)
+ : mCallback(callback), mFlags(flags) {}
+
+ XPCNativeScriptableCreateInfo()
+ : mFlags(0) {}
+
+
+ nsIXPCScriptable*
+ GetCallback() const {return mCallback;}
+
+ const XPCNativeScriptableFlags&
+ GetFlags() const {return mFlags;}
+
+ void
+ SetCallback(already_AddRefed<nsIXPCScriptable>&& callback)
+ {mCallback = callback;}
+
+ void
+ SetFlags(const XPCNativeScriptableFlags& flags) {mFlags = flags;}
+
+private:
+ // XXX: the flags are the same as the ones gettable from the callback. This
+ // redundancy should be removed eventually.
+ nsCOMPtr<nsIXPCScriptable> mCallback;
+ XPCNativeScriptableFlags mFlags;
+};
+
+/***********************************************/
+// XPCWrappedNativeProto hold the additional shared wrapper data
+// for XPCWrappedNative whose native objects expose nsIClassInfo.
+
+class XPCWrappedNativeProto final
+{
+public:
+ static XPCWrappedNativeProto*
+ GetNewOrUsed(XPCWrappedNativeScope* scope,
+ nsIClassInfo* classInfo,
+ const XPCNativeScriptableCreateInfo* scriptableCreateInfo,
+ bool callPostCreatePrototype = true);
+
+ XPCWrappedNativeScope*
+ GetScope() const {return mScope;}
+
+ XPCJSContext*
+ GetContext() const {return mScope->GetContext();}
+
+ JSObject*
+ GetJSProtoObject() const { return mJSProtoObject; }
+
+ nsIClassInfo*
+ GetClassInfo() const {return mClassInfo;}
+
+ XPCNativeSet*
+ GetSet() const {return mSet;}
+
+ XPCNativeScriptableInfo*
+ GetScriptableInfo() {return mScriptableInfo;}
+
+ bool CallPostCreatePrototype();
+ void JSProtoObjectFinalized(js::FreeOp* fop, JSObject* obj);
+ void JSProtoObjectMoved(JSObject* obj, const JSObject* old);
+
+ void SystemIsBeingShutDown();
+
+ void DebugDump(int16_t depth);
+
+ void TraceSelf(JSTracer* trc) {
+ if (mJSProtoObject)
+ mJSProtoObject.trace(trc, "XPCWrappedNativeProto::mJSProtoObject");
+ }
+
+ void TraceInside(JSTracer* trc) {
+ GetScope()->TraceSelf(trc);
+ }
+
+ void TraceJS(JSTracer* trc) {
+ TraceSelf(trc);
+ TraceInside(trc);
+ }
+
+ void WriteBarrierPre(JSContext* cx)
+ {
+ if (JS::IsIncrementalBarrierNeeded(cx) && mJSProtoObject)
+ mJSProtoObject.writeBarrierPre(cx);
+ }
+
+ // NOP. This is just here to make the AutoMarkingPtr code compile.
+ void Mark() const {}
+ inline void AutoTrace(JSTracer* trc) {}
+
+ ~XPCWrappedNativeProto();
+
+protected:
+ // disable copy ctor and assignment
+ XPCWrappedNativeProto(const XPCWrappedNativeProto& r) = delete;
+ XPCWrappedNativeProto& operator= (const XPCWrappedNativeProto& r) = delete;
+
+ // hide ctor
+ XPCWrappedNativeProto(XPCWrappedNativeScope* Scope,
+ nsIClassInfo* ClassInfo,
+ already_AddRefed<XPCNativeSet>&& Set);
+
+ bool Init(const XPCNativeScriptableCreateInfo* scriptableCreateInfo,
+ bool callPostCreatePrototype);
+
+private:
+#ifdef DEBUG
+ static int32_t gDEBUG_LiveProtoCount;
+#endif
+
+private:
+ XPCWrappedNativeScope* mScope;
+ JS::ObjectPtr mJSProtoObject;
+ nsCOMPtr<nsIClassInfo> mClassInfo;
+ RefPtr<XPCNativeSet> mSet;
+ XPCNativeScriptableInfo* mScriptableInfo;
+};
+
+/***********************************************/
+// XPCWrappedNativeTearOff represents the info needed to make calls to one
+// interface on the underlying native object of a XPCWrappedNative.
+
+class XPCWrappedNativeTearOff final
+{
+public:
+ bool IsAvailable() const {return mInterface == nullptr;}
+ bool IsReserved() const {return mInterface == (XPCNativeInterface*)1;}
+ bool IsValid() const {return !IsAvailable() && !IsReserved();}
+ void SetReserved() {mInterface = (XPCNativeInterface*)1;}
+
+ XPCNativeInterface* GetInterface() const {return mInterface;}
+ nsISupports* GetNative() const {return mNative;}
+ JSObject* GetJSObject();
+ JSObject* GetJSObjectPreserveColor() const;
+ void SetInterface(XPCNativeInterface* Interface) {mInterface = Interface;}
+ void SetNative(nsISupports* Native) {mNative = Native;}
+ already_AddRefed<nsISupports> TakeNative() { return mNative.forget(); }
+ void SetJSObject(JSObject* JSObj);
+
+ void JSObjectFinalized() {SetJSObject(nullptr);}
+ void JSObjectMoved(JSObject* obj, const JSObject* old);
+
+ XPCWrappedNativeTearOff()
+ : mInterface(nullptr), mJSObject(nullptr)
+ {
+ MOZ_COUNT_CTOR(XPCWrappedNativeTearOff);
+ }
+ ~XPCWrappedNativeTearOff();
+
+ // NOP. This is just here to make the AutoMarkingPtr code compile.
+ inline void TraceJS(JSTracer* trc) {}
+ inline void AutoTrace(JSTracer* trc) {}
+
+ void Mark() {mJSObject.setFlags(1);}
+ void Unmark() {mJSObject.unsetFlags(1);}
+ bool IsMarked() const {return mJSObject.hasFlag(1);}
+
+ XPCWrappedNativeTearOff* AddTearOff()
+ {
+ MOZ_ASSERT(!mNextTearOff);
+ mNextTearOff = mozilla::MakeUnique<XPCWrappedNativeTearOff>();
+ return mNextTearOff.get();
+ }
+
+ XPCWrappedNativeTearOff* GetNextTearOff() {return mNextTearOff.get();}
+
+private:
+ XPCWrappedNativeTearOff(const XPCWrappedNativeTearOff& r) = delete;
+ XPCWrappedNativeTearOff& operator= (const XPCWrappedNativeTearOff& r) = delete;
+
+private:
+ XPCNativeInterface* mInterface;
+ // mNative is an nsRefPtr not an nsCOMPtr because it may not be the canonical
+ // nsISupports pointer.
+ RefPtr<nsISupports> mNative;
+ JS::TenuredHeap<JSObject*> mJSObject;
+ mozilla::UniquePtr<XPCWrappedNativeTearOff> mNextTearOff;
+};
+
+
+/***************************************************************************/
+// XPCWrappedNative the wrapper around one instance of a native xpcom object
+// to be used from JavaScript.
+
+class XPCWrappedNative final : public nsIXPConnectWrappedNative
+{
+public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
+ NS_DECL_NSIXPCONNECTWRAPPEDNATIVE
+
+ NS_DECL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
+
+ nsIPrincipal* GetObjectPrincipal() const;
+
+ bool
+ IsValid() const { return mFlatJSObject.hasFlag(FLAT_JS_OBJECT_VALID); }
+
+#define XPC_SCOPE_WORD(s) (intptr_t(s))
+#define XPC_SCOPE_MASK (intptr_t(0x3))
+#define XPC_SCOPE_TAG (intptr_t(0x1))
+#define XPC_WRAPPER_EXPIRED (intptr_t(0x2))
+
+ static inline bool
+ IsTaggedScope(XPCWrappedNativeScope* s)
+ {return XPC_SCOPE_WORD(s) & XPC_SCOPE_TAG;}
+
+ static inline XPCWrappedNativeScope*
+ TagScope(XPCWrappedNativeScope* s)
+ {MOZ_ASSERT(!IsTaggedScope(s), "bad pointer!");
+ return (XPCWrappedNativeScope*)(XPC_SCOPE_WORD(s) | XPC_SCOPE_TAG);}
+
+ static inline XPCWrappedNativeScope*
+ UnTagScope(XPCWrappedNativeScope* s)
+ {return (XPCWrappedNativeScope*)(XPC_SCOPE_WORD(s) & ~XPC_SCOPE_TAG);}
+
+ inline bool
+ IsWrapperExpired() const
+ {return XPC_SCOPE_WORD(mMaybeScope) & XPC_WRAPPER_EXPIRED;}
+
+ bool
+ HasProto() const {return !IsTaggedScope(mMaybeScope);}
+
+ XPCWrappedNativeProto*
+ GetProto() const
+ {return HasProto() ?
+ (XPCWrappedNativeProto*)
+ (XPC_SCOPE_WORD(mMaybeProto) & ~XPC_SCOPE_MASK) : nullptr;}
+
+ void SetProto(XPCWrappedNativeProto* p);
+
+ XPCWrappedNativeScope*
+ GetScope() const
+ {return GetProto() ? GetProto()->GetScope() :
+ (XPCWrappedNativeScope*)
+ (XPC_SCOPE_WORD(mMaybeScope) & ~XPC_SCOPE_MASK);}
+
+ nsISupports*
+ GetIdentityObject() const {return mIdentity;}
+
+ /**
+ * This getter clears the gray bit before handing out the JSObject which
+ * means that the object is guaranteed to be kept alive past the next CC.
+ */
+ JSObject* GetFlatJSObject() const { return mFlatJSObject; }
+
+ /**
+ * This getter does not change the color of the JSObject meaning that the
+ * object returned is not guaranteed to be kept alive past the next CC.
+ *
+ * This should only be called if you are certain that the return value won't
+ * be passed into a JS API function and that it won't be stored without
+ * being rooted (or otherwise signaling the stored value to the CC).
+ */
+ JSObject*
+ GetFlatJSObjectPreserveColor() const {
+ return mFlatJSObject.unbarrieredGetPtr();
+ }
+
+ XPCNativeSet*
+ GetSet() const {return mSet;}
+
+ void
+ SetSet(already_AddRefed<XPCNativeSet> set) {mSet = set;}
+
+ static XPCWrappedNative* Get(JSObject* obj) {
+ MOZ_ASSERT(IS_WN_REFLECTOR(obj));
+ return (XPCWrappedNative*)js::GetObjectPrivate(obj);
+ }
+
+private:
+ inline void
+ ExpireWrapper()
+ {mMaybeScope = (XPCWrappedNativeScope*)
+ (XPC_SCOPE_WORD(mMaybeScope) | XPC_WRAPPER_EXPIRED);}
+
+public:
+
+ XPCNativeScriptableInfo*
+ GetScriptableInfo() const {return mScriptableInfo;}
+
+ nsIXPCScriptable* // call this wrong and you deserve to crash
+ GetScriptableCallback() const {return mScriptableInfo->GetCallback();}
+
+ nsIClassInfo*
+ GetClassInfo() const {return IsValid() && HasProto() ?
+ GetProto()->GetClassInfo() : nullptr;}
+
+ bool
+ HasMutatedSet() const {return IsValid() &&
+ (!HasProto() ||
+ GetSet() != GetProto()->GetSet());}
+
+ XPCJSContext*
+ GetContext() const {XPCWrappedNativeScope* scope = GetScope();
+ return scope ? scope->GetContext() : nullptr;}
+
+ static nsresult
+ WrapNewGlobal(xpcObjectHelper& nativeHelper,
+ nsIPrincipal* principal, bool initStandardClasses,
+ JS::CompartmentOptions& aOptions,
+ XPCWrappedNative** wrappedGlobal);
+
+ static nsresult
+ GetNewOrUsed(xpcObjectHelper& helper,
+ XPCWrappedNativeScope* Scope,
+ XPCNativeInterface* Interface,
+ XPCWrappedNative** wrapper);
+
+ static nsresult
+ GetUsedOnly(nsISupports* Object,
+ XPCWrappedNativeScope* Scope,
+ XPCNativeInterface* Interface,
+ XPCWrappedNative** wrapper);
+
+ void FlatJSObjectFinalized();
+ void FlatJSObjectMoved(JSObject* obj, const JSObject* old);
+
+ void SystemIsBeingShutDown();
+
+ enum CallMode {CALL_METHOD, CALL_GETTER, CALL_SETTER};
+
+ static bool CallMethod(XPCCallContext& ccx,
+ CallMode mode = CALL_METHOD);
+
+ static bool GetAttribute(XPCCallContext& ccx)
+ {return CallMethod(ccx, CALL_GETTER);}
+
+ static bool SetAttribute(XPCCallContext& ccx)
+ {return CallMethod(ccx, CALL_SETTER);}
+
+ inline bool HasInterfaceNoQI(const nsIID& iid);
+
+ XPCWrappedNativeTearOff* FindTearOff(XPCNativeInterface* aInterface,
+ bool needJSObject = false,
+ nsresult* pError = nullptr);
+ XPCWrappedNativeTearOff* FindTearOff(const nsIID& iid);
+
+ void Mark() const {}
+
+ inline void TraceInside(JSTracer* trc) {
+ if (HasProto())
+ GetProto()->TraceSelf(trc);
+ else
+ GetScope()->TraceSelf(trc);
+
+ JSObject* obj = mFlatJSObject.unbarrieredGetPtr();
+ if (obj && JS_IsGlobalObject(obj)) {
+ xpc::TraceXPCGlobal(trc, obj);
+ }
+ }
+
+ void TraceJS(JSTracer* trc) {
+ TraceInside(trc);
+ }
+
+ void TraceSelf(JSTracer* trc) {
+ // If this got called, we're being kept alive by someone who really
+ // needs us alive and whole. Do not let our mFlatJSObject go away.
+ // This is the only time we should be tracing our mFlatJSObject,
+ // normally somebody else is doing that.
+ JS::TraceEdge(trc, &mFlatJSObject, "XPCWrappedNative::mFlatJSObject");
+ }
+
+ static void Trace(JSTracer* trc, JSObject* obj);
+
+ void AutoTrace(JSTracer* trc) {
+ TraceSelf(trc);
+ }
+
+ inline void SweepTearOffs();
+
+ // Returns a string that shuld be free'd using JS_smprintf_free (or null).
+ char* ToString(XPCWrappedNativeTearOff* to = nullptr) const;
+
+ static void GatherProtoScriptableCreateInfo(nsIClassInfo* classInfo,
+ XPCNativeScriptableCreateInfo& sciProto);
+
+ bool HasExternalReference() const {return mRefCnt > 1;}
+
+ void Suspect(nsCycleCollectionNoteRootCallback& cb);
+ void NoteTearoffs(nsCycleCollectionTraversalCallback& cb);
+
+ // Make ctor and dtor protected (rather than private) to placate nsCOMPtr.
+protected:
+ XPCWrappedNative() = delete;
+
+ // This ctor is used if this object will have a proto.
+ XPCWrappedNative(already_AddRefed<nsISupports>&& aIdentity,
+ XPCWrappedNativeProto* aProto);
+
+ // This ctor is used if this object will NOT have a proto.
+ XPCWrappedNative(already_AddRefed<nsISupports>&& aIdentity,
+ XPCWrappedNativeScope* aScope,
+ already_AddRefed<XPCNativeSet>&& aSet);
+
+ virtual ~XPCWrappedNative();
+ void Destroy();
+
+ void UpdateScriptableInfo(XPCNativeScriptableInfo* si);
+
+private:
+ enum {
+ // Flags bits for mFlatJSObject:
+ FLAT_JS_OBJECT_VALID = JS_BIT(0)
+ };
+
+ bool Init(const XPCNativeScriptableCreateInfo* sci);
+ bool FinishInit();
+
+ bool ExtendSet(XPCNativeInterface* aInterface);
+
+ nsresult InitTearOff(XPCWrappedNativeTearOff* aTearOff,
+ XPCNativeInterface* aInterface,
+ bool needJSObject);
+
+ bool InitTearOffJSObject(XPCWrappedNativeTearOff* to);
+
+public:
+ static const XPCNativeScriptableCreateInfo& GatherScriptableCreateInfo(nsISupports* obj,
+ nsIClassInfo* classInfo,
+ XPCNativeScriptableCreateInfo& sciProto,
+ XPCNativeScriptableCreateInfo& sciWrapper);
+
+private:
+ union
+ {
+ XPCWrappedNativeScope* mMaybeScope;
+ XPCWrappedNativeProto* mMaybeProto;
+ };
+ RefPtr<XPCNativeSet> mSet;
+ JS::TenuredHeap<JSObject*> mFlatJSObject;
+ XPCNativeScriptableInfo* mScriptableInfo;
+ XPCWrappedNativeTearOff mFirstTearOff;
+};
+
+/***************************************************************************
+****************************************************************************
+*
+* Core classes for wrapped JSObject for use from native code...
+*
+****************************************************************************
+***************************************************************************/
+
+// this interfaces exists so we can refcount nsXPCWrappedJSClass
+// {2453EBA0-A9B8-11d2-BA64-00805F8A5DD7}
+#define NS_IXPCONNECT_WRAPPED_JS_CLASS_IID \
+{ 0x2453eba0, 0xa9b8, 0x11d2, \
+ { 0xba, 0x64, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } }
+
+class nsIXPCWrappedJSClass : public nsISupports
+{
+public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXPCONNECT_WRAPPED_JS_CLASS_IID)
+ NS_IMETHOD DebugDump(int16_t depth) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIXPCWrappedJSClass,
+ NS_IXPCONNECT_WRAPPED_JS_CLASS_IID)
+
+/*************************/
+// nsXPCWrappedJSClass represents the sharable factored out common code and
+// data for nsXPCWrappedJS instances for the same interface type.
+
+class nsXPCWrappedJSClass final : public nsIXPCWrappedJSClass
+{
+ // all the interface method declarations...
+ NS_DECL_ISUPPORTS
+ NS_IMETHOD DebugDump(int16_t depth) override;
+public:
+
+ static already_AddRefed<nsXPCWrappedJSClass>
+ GetNewOrUsed(JSContext* cx,
+ REFNSIID aIID,
+ bool allowNonScriptable = false);
+
+ REFNSIID GetIID() const {return mIID;}
+ XPCJSContext* GetContext() const {return mContext;}
+ nsIInterfaceInfo* GetInterfaceInfo() const {return mInfo;}
+ const char* GetInterfaceName();
+
+ static bool IsWrappedJS(nsISupports* aPtr);
+
+ NS_IMETHOD DelegatedQueryInterface(nsXPCWrappedJS* self, REFNSIID aIID,
+ void** aInstancePtr);
+
+ JSObject* GetRootJSObject(JSContext* cx, JSObject* aJSObj);
+
+ NS_IMETHOD CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
+ const XPTMethodDescriptor* info,
+ nsXPTCMiniVariant* params);
+
+ JSObject* CallQueryInterfaceOnJSObject(JSContext* cx,
+ JSObject* jsobj, REFNSIID aIID);
+
+ static nsresult BuildPropertyEnumerator(XPCCallContext& ccx,
+ JSObject* aJSObj,
+ nsISimpleEnumerator** aEnumerate);
+
+ static nsresult GetNamedPropertyAsVariant(XPCCallContext& ccx,
+ JSObject* aJSObj,
+ const nsAString& aName,
+ nsIVariant** aResult);
+
+private:
+ // aSyntheticException, if not null, is the exception we should be using.
+ // If null, look for an exception on the JSContext hanging off the
+ // XPCCallContext.
+ static nsresult CheckForException(XPCCallContext & ccx,
+ mozilla::dom::AutoEntryScript& aes,
+ const char * aPropertyName,
+ const char * anInterfaceName,
+ nsIException* aSyntheticException = nullptr);
+ virtual ~nsXPCWrappedJSClass();
+
+ nsXPCWrappedJSClass() = delete;
+ nsXPCWrappedJSClass(JSContext* cx, REFNSIID aIID,
+ nsIInterfaceInfo* aInfo);
+
+ bool IsReflectable(uint16_t i) const
+ {return (bool)(mDescriptors[i/32] & (1 << (i%32)));}
+ void SetReflectable(uint16_t i, bool b)
+ {if (b) mDescriptors[i/32] |= (1 << (i%32));
+ else mDescriptors[i/32] &= ~(1 << (i%32));}
+
+ bool GetArraySizeFromParam(JSContext* cx,
+ const XPTMethodDescriptor* method,
+ const nsXPTParamInfo& param,
+ uint16_t methodIndex,
+ uint8_t paramIndex,
+ nsXPTCMiniVariant* params,
+ uint32_t* result) const;
+
+ bool GetInterfaceTypeFromParam(JSContext* cx,
+ const XPTMethodDescriptor* method,
+ const nsXPTParamInfo& param,
+ uint16_t methodIndex,
+ const nsXPTType& type,
+ nsXPTCMiniVariant* params,
+ nsID* result) const;
+
+ static void CleanupPointerArray(const nsXPTType& datum_type,
+ uint32_t array_count,
+ void** arrayp);
+
+ static void CleanupPointerTypeObject(const nsXPTType& type,
+ void** pp);
+
+ void CleanupOutparams(JSContext* cx, uint16_t methodIndex, const nsXPTMethodInfo* info,
+ nsXPTCMiniVariant* nativeParams, bool inOutOnly, uint8_t n) const;
+
+private:
+ XPCJSContext* mContext;
+ nsCOMPtr<nsIInterfaceInfo> mInfo;
+ char* mName;
+ nsIID mIID;
+ uint32_t* mDescriptors;
+};
+
+/*************************/
+// nsXPCWrappedJS is a wrapper for a single JSObject for use from native code.
+// nsXPCWrappedJS objects are chained together to represent the various
+// interface on the single underlying (possibly aggregate) JSObject.
+
+class nsXPCWrappedJS final : protected nsAutoXPTCStub,
+ public nsIXPConnectWrappedJSUnmarkGray,
+ public nsSupportsWeakReference,
+ public nsIPropertyBag,
+ public XPCRootSetElem
+{
+public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
+ NS_DECL_NSIXPCONNECTWRAPPEDJS
+ NS_DECL_NSIXPCONNECTWRAPPEDJSUNMARKGRAY
+ NS_DECL_NSISUPPORTSWEAKREFERENCE
+ NS_DECL_NSIPROPERTYBAG
+
+ NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS_AMBIGUOUS(nsXPCWrappedJS, nsIXPConnectWrappedJS)
+
+ NS_IMETHOD CallMethod(uint16_t methodIndex,
+ const XPTMethodDescriptor* info,
+ nsXPTCMiniVariant* params) override;
+
+ /*
+ * This is rarely called directly. Instead one usually calls
+ * XPCConvert::JSObject2NativeInterface which will handles cases where the
+ * JS object is already a wrapped native or a DOM object.
+ */
+
+ static nsresult
+ GetNewOrUsed(JS::HandleObject aJSObj,
+ REFNSIID aIID,
+ nsXPCWrappedJS** wrapper);
+
+ nsISomeInterface* GetXPTCStub() { return mXPTCStub; }
+
+ /**
+ * This getter does not change the color of the JSObject meaning that the
+ * object returned is not guaranteed to be kept alive past the next CC.
+ *
+ * This should only be called if you are certain that the return value won't
+ * be passed into a JS API function and that it won't be stored without
+ * being rooted (or otherwise signaling the stored value to the CC).
+ */
+ JSObject* GetJSObjectPreserveColor() const { return mJSObj.unbarrieredGet(); }
+
+ // Returns true if the wrapper chain contains references to multiple
+ // compartments. If the wrapper chain contains references to multiple
+ // compartments, then it must be registered on the XPCJSContext. Otherwise,
+ // it should be registered in the CompartmentPrivate for the compartment of
+ // the root's JS object. This will only return correct results when called
+ // on the root wrapper and will assert if not called on a root wrapper.
+ bool IsMultiCompartment() const;
+
+ nsXPCWrappedJSClass* GetClass() const {return mClass;}
+ REFNSIID GetIID() const {return GetClass()->GetIID();}
+ nsXPCWrappedJS* GetRootWrapper() const {return mRoot;}
+ nsXPCWrappedJS* GetNextWrapper() const {return mNext;}
+
+ nsXPCWrappedJS* Find(REFNSIID aIID);
+ nsXPCWrappedJS* FindInherited(REFNSIID aIID);
+ nsXPCWrappedJS* FindOrFindInherited(REFNSIID aIID) {
+ nsXPCWrappedJS* wrapper = Find(aIID);
+ if (wrapper)
+ return wrapper;
+ return FindInherited(aIID);
+ }
+
+ bool IsRootWrapper() const { return mRoot == this; }
+ bool IsValid() const { return bool(mJSObj); }
+ void SystemIsBeingShutDown();
+
+ // These two methods are used by JSObject2WrappedJSMap::FindDyingJSObjects
+ // to find non-rooting wrappers for dying JS objects. See the top of
+ // XPCWrappedJS.cpp for more details.
+ bool IsSubjectToFinalization() const {return IsValid() && mRefCnt == 1;}
+ void UpdateObjectPointerAfterGC() {JS_UpdateWeakPointerAfterGC(&mJSObj);}
+
+ bool IsAggregatedToNative() const {return mRoot->mOuter != nullptr;}
+ nsISupports* GetAggregatedNativeObject() const {return mRoot->mOuter;}
+ void SetAggregatedNativeObject(nsISupports* aNative) {
+ MOZ_ASSERT(aNative);
+ if (mRoot->mOuter) {
+ MOZ_ASSERT(mRoot->mOuter == aNative,
+ "Only one aggregated native can be set");
+ return;
+ }
+ mRoot->mOuter = aNative;
+ }
+
+ void TraceJS(JSTracer* trc);
+
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+
+ virtual ~nsXPCWrappedJS();
+protected:
+ nsXPCWrappedJS() = delete;
+ nsXPCWrappedJS(JSContext* cx,
+ JSObject* aJSObj,
+ nsXPCWrappedJSClass* aClass,
+ nsXPCWrappedJS* root,
+ nsresult* rv);
+
+ bool CanSkip();
+ void Destroy();
+ void Unlink();
+
+private:
+ JSCompartment* Compartment() const {
+ return js::GetObjectCompartment(mJSObj.unbarrieredGet());
+ }
+
+ JS::Heap<JSObject*> mJSObj;
+ RefPtr<nsXPCWrappedJSClass> mClass;
+ nsXPCWrappedJS* mRoot; // If mRoot != this, it is an owning pointer.
+ nsXPCWrappedJS* mNext;
+ nsCOMPtr<nsISupports> mOuter; // only set in root
+};
+
+/***************************************************************************/
+
+class XPCJSObjectHolder final : public nsIXPConnectJSObjectHolder,
+ public XPCRootSetElem
+{
+public:
+ // all the interface method declarations...
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIXPCONNECTJSOBJECTHOLDER
+
+ // non-interface implementation
+
+public:
+ void TraceJS(JSTracer* trc);
+
+ explicit XPCJSObjectHolder(JSObject* obj);
+
+private:
+ virtual ~XPCJSObjectHolder();
+
+ XPCJSObjectHolder() = delete;
+
+ JS::Heap<JSObject*> mJSObj;
+};
+
+/***************************************************************************
+****************************************************************************
+*
+* All manner of utility classes follow...
+*
+****************************************************************************
+***************************************************************************/
+
+class xpcProperty : public nsIProperty
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIPROPERTY
+
+ xpcProperty(const char16_t* aName, uint32_t aNameLen, nsIVariant* aValue);
+
+private:
+ virtual ~xpcProperty() {}
+
+ nsString mName;
+ nsCOMPtr<nsIVariant> mValue;
+};
+
+/***************************************************************************/
+// class here just for static methods
+class XPCConvert
+{
+public:
+ static bool IsMethodReflectable(const XPTMethodDescriptor& info);
+
+ /**
+ * Convert a native object into a JS::Value.
+ *
+ * @param d [out] the resulting JS::Value
+ * @param s the native object we're working with
+ * @param type the type of object that s is
+ * @param iid the interface of s that we want
+ * @param scope the default scope to put on the new JSObject's parent
+ * chain
+ * @param pErr [out] relevant error code, if any.
+ */
+
+ static bool NativeData2JS(JS::MutableHandleValue d,
+ const void* s, const nsXPTType& type,
+ const nsID* iid, nsresult* pErr);
+
+ static bool JSData2Native(void* d, JS::HandleValue s,
+ const nsXPTType& type,
+ const nsID* iid,
+ nsresult* pErr);
+
+ /**
+ * Convert a native nsISupports into a JSObject.
+ *
+ * @param dest [out] the resulting JSObject
+ * @param src the native object we're working with
+ * @param iid the interface of src that we want (may be null)
+ * @param cache the wrapper cache for src (may be null, in which case src
+ * will be QI'ed to get the cache)
+ * @param allowNativeWrapper if true, this method may wrap the resulting
+ * JSObject in an XPCNativeWrapper and return that, as needed.
+ * @param pErr [out] relevant error code, if any.
+ * @param src_is_identity optional performance hint. Set to true only
+ * if src is the identity pointer.
+ */
+ static bool NativeInterface2JSObject(JS::MutableHandleValue d,
+ nsIXPConnectJSObjectHolder** dest,
+ xpcObjectHelper& aHelper,
+ const nsID* iid,
+ bool allowNativeWrapper,
+ nsresult* pErr);
+
+ static bool GetNativeInterfaceFromJSObject(void** dest, JSObject* src,
+ const nsID* iid,
+ nsresult* pErr);
+ static bool JSObject2NativeInterface(void** dest, JS::HandleObject src,
+ const nsID* iid,
+ nsISupports* aOuter,
+ nsresult* pErr);
+
+ // Note - This return the XPCWrappedNative, rather than the native itself,
+ // for the WN case. You probably want UnwrapReflectorToISupports.
+ static bool GetISupportsFromJSObject(JSObject* obj, nsISupports** iface);
+
+ /**
+ * Convert a native array into a JS::Value.
+ *
+ * @param d [out] the resulting JS::Value
+ * @param s the native array we're working with
+ * @param type the type of objects in the array
+ * @param iid the interface of each object in the array that we want
+ * @param count the number of items in the array
+ * @param scope the default scope to put on the new JSObjects' parent chain
+ * @param pErr [out] relevant error code, if any.
+ */
+ static bool NativeArray2JS(JS::MutableHandleValue d, const void** s,
+ const nsXPTType& type, const nsID* iid,
+ uint32_t count, nsresult* pErr);
+
+ static bool JSArray2Native(void** d, JS::HandleValue s,
+ uint32_t count, const nsXPTType& type,
+ const nsID* iid, nsresult* pErr);
+
+ static bool JSTypedArray2Native(void** d,
+ JSObject* jsarray,
+ uint32_t count,
+ const nsXPTType& type,
+ nsresult* pErr);
+
+ static bool NativeStringWithSize2JS(JS::MutableHandleValue d, const void* s,
+ const nsXPTType& type,
+ uint32_t count,
+ nsresult* pErr);
+
+ static bool JSStringWithSize2Native(void* d, JS::HandleValue s,
+ uint32_t count, const nsXPTType& type,
+ nsresult* pErr);
+
+ static nsresult JSValToXPCException(JS::MutableHandleValue s,
+ const char* ifaceName,
+ const char* methodName,
+ nsIException** exception);
+
+ static nsresult ConstructException(nsresult rv, const char* message,
+ const char* ifaceName,
+ const char* methodName,
+ nsISupports* data,
+ nsIException** exception,
+ JSContext* cx,
+ JS::Value* jsExceptionPtr);
+
+private:
+ XPCConvert() = delete;
+
+};
+
+/***************************************************************************/
+// code for throwing exceptions into JS
+
+class nsXPCException;
+
+class XPCThrower
+{
+public:
+ static void Throw(nsresult rv, JSContext* cx);
+ static void Throw(nsresult rv, XPCCallContext& ccx);
+ static void ThrowBadResult(nsresult rv, nsresult result, XPCCallContext& ccx);
+ static void ThrowBadParam(nsresult rv, unsigned paramNum, XPCCallContext& ccx);
+ static bool SetVerbosity(bool state)
+ {bool old = sVerbose; sVerbose = state; return old;}
+
+ static bool CheckForPendingException(nsresult result, JSContext* cx);
+
+private:
+ static void Verbosify(XPCCallContext& ccx,
+ char** psz, bool own);
+
+private:
+ static bool sVerbose;
+};
+
+/***************************************************************************/
+
+class nsXPCException
+{
+public:
+ static bool NameAndFormatForNSResult(nsresult rv,
+ const char** name,
+ const char** format);
+
+ static const void* IterateNSResults(nsresult* rv,
+ const char** name,
+ const char** format,
+ const void** iterp);
+
+ static uint32_t GetNSResultCount();
+};
+
+/***************************************************************************/
+/*
+* nsJSID implements nsIJSID. It is also used by nsJSIID and nsJSCID as a
+* member (as a hidden implementaion detail) to which they delegate many calls.
+*/
+
+// Initialization is done on demand, and calling the destructor below is always
+// safe.
+extern void xpc_DestroyJSxIDClassObjects();
+
+class nsJSID final : public nsIJSID
+{
+public:
+ NS_DEFINE_STATIC_CID_ACCESSOR(NS_JS_ID_CID)
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIJSID
+
+ bool InitWithName(const nsID& id, const char* nameString);
+ bool SetName(const char* name);
+ void SetNameToNoString()
+ {MOZ_ASSERT(!mName, "name already set"); mName = const_cast<char*>(gNoString);}
+ bool NameIsSet() const {return nullptr != mName;}
+ const nsID& ID() const {return mID;}
+ bool IsValid() const {return !mID.Equals(GetInvalidIID());}
+
+ static already_AddRefed<nsJSID> NewID(const char* str);
+ static already_AddRefed<nsJSID> NewID(const nsID& id);
+
+ nsJSID();
+
+ void Reset();
+ const nsID& GetInvalidIID() const;
+
+protected:
+ virtual ~nsJSID();
+ static const char gNoString[];
+ nsID mID;
+ char* mNumber;
+ char* mName;
+};
+
+
+// nsJSIID
+
+class nsJSIID : public nsIJSIID,
+ public nsIXPCScriptable
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ // we manually delagate these to nsJSID
+ NS_DECL_NSIJSID
+
+ // we implement the rest...
+ NS_DECL_NSIJSIID
+ NS_DECL_NSIXPCSCRIPTABLE
+
+ static already_AddRefed<nsJSIID> NewID(nsIInterfaceInfo* aInfo);
+
+ explicit nsJSIID(nsIInterfaceInfo* aInfo);
+ nsJSIID() = delete;
+
+private:
+ virtual ~nsJSIID();
+
+ nsCOMPtr<nsIInterfaceInfo> mInfo;
+};
+
+// nsJSCID
+
+class nsJSCID : public nsIJSCID, public nsIXPCScriptable
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ // we manually delagate these to nsJSID
+ NS_DECL_NSIJSID
+
+ // we implement the rest...
+ NS_DECL_NSIJSCID
+ NS_DECL_NSIXPCSCRIPTABLE
+
+ static already_AddRefed<nsJSCID> NewID(const char* str);
+
+ nsJSCID();
+
+private:
+ virtual ~nsJSCID();
+
+ void ResolveName();
+
+private:
+ RefPtr<nsJSID> mDetails;
+};
+
+
+/***************************************************************************/
+// 'Components' object implementations. nsXPCComponentsBase has the
+// less-privileged stuff that we're willing to expose to XBL.
+
+class nsXPCComponentsBase : public nsIXPCComponentsBase
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIXPCCOMPONENTSBASE
+
+public:
+ void SystemIsBeingShutDown() { ClearMembers(); }
+
+ XPCWrappedNativeScope* GetScope() { return mScope; }
+
+protected:
+ virtual ~nsXPCComponentsBase();
+
+ explicit nsXPCComponentsBase(XPCWrappedNativeScope* aScope);
+ virtual void ClearMembers();
+
+ XPCWrappedNativeScope* mScope;
+
+ // Unprivileged members from nsIXPCComponentsBase.
+ RefPtr<nsXPCComponents_Interfaces> mInterfaces;
+ RefPtr<nsXPCComponents_InterfacesByID> mInterfacesByID;
+ RefPtr<nsXPCComponents_Results> mResults;
+
+ friend class XPCWrappedNativeScope;
+};
+
+class nsXPCComponents : public nsXPCComponentsBase,
+ public nsIXPCComponents
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_FORWARD_NSIXPCCOMPONENTSBASE(nsXPCComponentsBase::)
+ NS_DECL_NSIXPCCOMPONENTS
+
+protected:
+ explicit nsXPCComponents(XPCWrappedNativeScope* aScope);
+ virtual ~nsXPCComponents();
+ virtual void ClearMembers() override;
+
+ // Privileged members added by nsIXPCComponents.
+ RefPtr<nsXPCComponents_Classes> mClasses;
+ RefPtr<nsXPCComponents_ClassesByID> mClassesByID;
+ RefPtr<nsXPCComponents_ID> mID;
+ RefPtr<nsXPCComponents_Exception> mException;
+ RefPtr<nsXPCComponents_Constructor> mConstructor;
+ RefPtr<nsXPCComponents_Utils> mUtils;
+
+ friend class XPCWrappedNativeScope;
+};
+
+
+/***************************************************************************/
+
+extern JSObject*
+xpc_NewIDObject(JSContext* cx, JS::HandleObject jsobj, const nsID& aID);
+
+extern const nsID*
+xpc_JSObjectToID(JSContext* cx, JSObject* obj);
+
+extern bool
+xpc_JSObjectIsID(JSContext* cx, JSObject* obj);
+
+/***************************************************************************/
+// 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. It is the *caller's* responsibility to free this
+// string with JS_smprintf_free().
+extern char*
+xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals,
+ bool showThisProps);
+
+/***************************************************************************/
+
+// Definition of nsScriptError, defined here because we lack a place to put
+// XPCOM objects associated with the JavaScript engine.
+class nsScriptErrorBase : public nsIScriptError {
+public:
+ nsScriptErrorBase();
+
+ // TODO - do something reasonable on getting null from these babies.
+
+ NS_DECL_NSICONSOLEMESSAGE
+ NS_DECL_NSISCRIPTERROR
+
+protected:
+ virtual ~nsScriptErrorBase();
+
+ void
+ InitializeOnMainThread();
+
+ nsString mMessage;
+ nsString mMessageName;
+ nsString mSourceName;
+ uint32_t mLineNumber;
+ nsString mSourceLine;
+ uint32_t mColumnNumber;
+ uint32_t mFlags;
+ nsCString mCategory;
+ // mOuterWindowID is set on the main thread from InitializeOnMainThread().
+ uint64_t mOuterWindowID;
+ uint64_t mInnerWindowID;
+ int64_t mTimeStamp;
+ // mInitializedOnMainThread and mIsFromPrivateWindow are set on the main
+ // thread from InitializeOnMainThread().
+ mozilla::Atomic<bool> mInitializedOnMainThread;
+ bool mIsFromPrivateWindow;
+};
+
+class nsScriptError final : public nsScriptErrorBase {
+public:
+ nsScriptError() {}
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+private:
+ virtual ~nsScriptError() {}
+};
+
+class nsScriptErrorWithStack : public nsScriptErrorBase {
+public:
+ explicit nsScriptErrorWithStack(JS::HandleObject);
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsScriptErrorWithStack)
+
+ NS_IMETHOD Init(const nsAString& message,
+ const nsAString& sourceName,
+ const nsAString& sourceLine,
+ uint32_t lineNumber,
+ uint32_t columnNumber,
+ uint32_t flags,
+ const char* category) override;
+
+ NS_IMETHOD GetStack(JS::MutableHandleValue) override;
+ NS_IMETHOD ToString(nsACString& aResult) override;
+
+private:
+ virtual ~nsScriptErrorWithStack();
+ // Complete stackframe where the error happened.
+ // Must be SavedFrame object.
+ JS::Heap<JSObject*> mStack;
+};
+
+/******************************************************************************
+ * Handles pre/post script processing.
+ */
+class MOZ_RAII AutoScriptEvaluate
+{
+public:
+ /**
+ * Saves the JSContext as well as initializing our state
+ * @param cx The JSContext, this can be null, we don't do anything then
+ */
+ explicit AutoScriptEvaluate(JSContext * cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : mJSContext(cx), mEvaluated(false) {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ }
+
+ /**
+ * Does the pre script evaluation.
+ * This function should only be called once, and will assert if called
+ * more than once
+ */
+
+ bool StartEvaluating(JS::HandleObject scope);
+
+ /**
+ * Does the post script evaluation.
+ */
+ ~AutoScriptEvaluate();
+private:
+ JSContext* mJSContext;
+ mozilla::Maybe<JS::AutoSaveExceptionState> mState;
+ bool mEvaluated;
+ mozilla::Maybe<JSAutoCompartment> mAutoCompartment;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+
+ // No copying or assignment allowed
+ AutoScriptEvaluate(const AutoScriptEvaluate&) = delete;
+ AutoScriptEvaluate & operator =(const AutoScriptEvaluate&) = delete;
+};
+
+/***************************************************************************/
+class MOZ_RAII AutoResolveName
+{
+public:
+ AutoResolveName(XPCCallContext& ccx, JS::HandleId name
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
+ mOld(ccx, XPCJSContext::Get()->SetResolveName(name))
+#ifdef DEBUG
+ ,mCheck(ccx, name)
+#endif
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ }
+ ~AutoResolveName()
+ {
+#ifdef DEBUG
+ jsid old =
+#endif
+ XPCJSContext::Get()->SetResolveName(mOld);
+ MOZ_ASSERT(old == mCheck, "Bad Nesting!");
+ }
+
+private:
+ JS::RootedId mOld;
+#ifdef DEBUG
+ JS::RootedId mCheck;
+#endif
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+/***************************************************************************/
+// AutoMarkingPtr is the base class for the various AutoMarking pointer types
+// below. This system allows us to temporarily protect instances of our garbage
+// collected types after they are constructed but before they are safely
+// attached to other rooted objects.
+// This base class has pure virtual support for marking.
+
+class AutoMarkingPtr
+{
+ public:
+ explicit AutoMarkingPtr(JSContext* cx) {
+ mRoot = XPCJSContext::Get()->GetAutoRootsAdr();
+ mNext = *mRoot;
+ *mRoot = this;
+ }
+
+ virtual ~AutoMarkingPtr() {
+ if (mRoot) {
+ MOZ_ASSERT(*mRoot == this);
+ *mRoot = mNext;
+ }
+ }
+
+ void TraceJSAll(JSTracer* trc) {
+ for (AutoMarkingPtr* cur = this; cur; cur = cur->mNext)
+ cur->TraceJS(trc);
+ }
+
+ void MarkAfterJSFinalizeAll() {
+ for (AutoMarkingPtr* cur = this; cur; cur = cur->mNext)
+ cur->MarkAfterJSFinalize();
+ }
+
+ protected:
+ virtual void TraceJS(JSTracer* trc) = 0;
+ virtual void MarkAfterJSFinalize() = 0;
+
+ private:
+ AutoMarkingPtr** mRoot;
+ AutoMarkingPtr* mNext;
+};
+
+template<class T>
+class TypedAutoMarkingPtr : public AutoMarkingPtr
+{
+ public:
+ explicit TypedAutoMarkingPtr(JSContext* cx) : AutoMarkingPtr(cx), mPtr(nullptr) {}
+ TypedAutoMarkingPtr(JSContext* cx, T* ptr) : AutoMarkingPtr(cx), mPtr(ptr) {}
+
+ T* get() const { return mPtr; }
+ operator T*() const { return mPtr; }
+ T* operator->() const { return mPtr; }
+
+ TypedAutoMarkingPtr<T>& operator =(T* ptr) { mPtr = ptr; return *this; }
+
+ protected:
+ virtual void TraceJS(JSTracer* trc)
+ {
+ if (mPtr) {
+ mPtr->TraceJS(trc);
+ mPtr->AutoTrace(trc);
+ }
+ }
+
+ virtual void MarkAfterJSFinalize()
+ {
+ if (mPtr)
+ mPtr->Mark();
+ }
+
+ private:
+ T* mPtr;
+};
+
+typedef TypedAutoMarkingPtr<XPCWrappedNative> AutoMarkingWrappedNativePtr;
+typedef TypedAutoMarkingPtr<XPCWrappedNativeTearOff> AutoMarkingWrappedNativeTearOffPtr;
+typedef TypedAutoMarkingPtr<XPCWrappedNativeProto> AutoMarkingWrappedNativeProtoPtr;
+
+/***************************************************************************/
+namespace xpc {
+// Allocates a string that grants all access ("AllAccess")
+char*
+CloneAllAccess();
+
+// Returns access if wideName is in list
+char*
+CheckAccessList(const char16_t* wideName, const char* const list[]);
+} /* namespace xpc */
+
+/***************************************************************************/
+// in xpcvariant.cpp...
+
+// {1809FD50-91E8-11d5-90F9-0010A4E73D9A}
+#define XPCVARIANT_IID \
+ {0x1809fd50, 0x91e8, 0x11d5, \
+ { 0x90, 0xf9, 0x0, 0x10, 0xa4, 0xe7, 0x3d, 0x9a } }
+
+// {DC524540-487E-4501-9AC7-AAA784B17C1C}
+#define XPCVARIANT_CID \
+ {0xdc524540, 0x487e, 0x4501, \
+ { 0x9a, 0xc7, 0xaa, 0xa7, 0x84, 0xb1, 0x7c, 0x1c } }
+
+class XPCVariant : public nsIVariant
+{
+public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_NSIVARIANT
+ NS_DECL_CYCLE_COLLECTION_CLASS(XPCVariant)
+
+ // If this class ever implements nsIWritableVariant, take special care with
+ // the case when mJSVal is JSVAL_STRING, since we don't own the data in
+ // that case.
+
+ // We #define and iid so that out module local code can use QI to detect
+ // if a given nsIVariant is in fact an XPCVariant.
+ NS_DECLARE_STATIC_IID_ACCESSOR(XPCVARIANT_IID)
+
+ static already_AddRefed<XPCVariant> newVariant(JSContext* cx, const JS::Value& aJSVal);
+
+ /**
+ * This getter clears the gray bit before handing out the Value if the Value
+ * represents a JSObject. That means that the object is guaranteed to be
+ * kept alive past the next CC.
+ */
+ JS::Value GetJSVal() const {
+ return mJSVal;
+ }
+
+ /**
+ * This getter does not change the color of the Value (if it represents a
+ * JSObject) meaning that the value returned is not guaranteed to be kept
+ * alive past the next CC.
+ *
+ * This should only be called if you are certain that the return value won't
+ * be passed into a JS API function and that it won't be stored without
+ * being rooted (or otherwise signaling the stored value to the CC).
+ */
+ JS::Value GetJSValPreserveColor() const { return mJSVal.unbarrieredGet(); }
+
+ XPCVariant(JSContext* cx, const JS::Value& aJSVal);
+
+ /**
+ * Convert a variant into a JS::Value.
+ *
+ * @param ccx the context for the whole procedure
+ * @param variant the variant to convert
+ * @param scope the default scope to put on the new JSObject's parent chain
+ * @param pErr [out] relevant error code, if any.
+ * @param pJSVal [out] the resulting jsval.
+ */
+ static bool VariantDataToJS(nsIVariant* variant,
+ nsresult* pErr, JS::MutableHandleValue pJSVal);
+
+ bool IsPurple()
+ {
+ return mRefCnt.IsPurple();
+ }
+
+ void RemovePurple()
+ {
+ mRefCnt.RemovePurple();
+ }
+
+ void SetCCGeneration(uint32_t aGen)
+ {
+ mCCGeneration = aGen;
+ }
+
+ uint32_t CCGeneration() { return mCCGeneration; }
+protected:
+ virtual ~XPCVariant() { }
+
+ bool InitializeData(JSContext* cx);
+
+protected:
+ nsDiscriminatedUnion mData;
+ JS::Heap<JS::Value> mJSVal;
+ bool mReturnRawObject : 1;
+ uint32_t mCCGeneration : 31;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(XPCVariant, XPCVARIANT_IID)
+
+class XPCTraceableVariant: public XPCVariant,
+ public XPCRootSetElem
+{
+public:
+ XPCTraceableVariant(JSContext* cx, const JS::Value& aJSVal)
+ : XPCVariant(cx, aJSVal)
+ {
+ nsXPConnect::GetContextInstance()->AddVariantRoot(this);
+ }
+
+ virtual ~XPCTraceableVariant();
+
+ void TraceJS(JSTracer* trc);
+};
+
+/***************************************************************************/
+// Utilities
+
+inline void*
+xpc_GetJSPrivate(JSObject* obj)
+{
+ return js::GetObjectPrivate(obj);
+}
+
+inline JSContext*
+xpc_GetSafeJSContext()
+{
+ return XPCJSContext::Get()->Context();
+}
+
+namespace xpc {
+
+JSAddonId*
+NewAddonId(JSContext* cx, const nsACString& id);
+
+// JSNatives to expose atob and btoa in various non-DOM XPConnect scopes.
+bool
+Atob(JSContext* cx, unsigned argc, JS::Value* vp);
+
+bool
+Btoa(JSContext* cx, unsigned argc, JS::Value* vp);
+
+// Helper function that creates a JSFunction that wraps a native function that
+// forwards the call to the original 'callable'.
+class FunctionForwarderOptions;
+bool
+NewFunctionForwarder(JSContext* cx, JS::HandleId id, JS::HandleObject callable,
+ FunctionForwarderOptions& options, JS::MutableHandleValue vp);
+
+// Old fashioned xpc error reporter. Try to use JS_ReportError instead.
+nsresult
+ThrowAndFail(nsresult errNum, JSContext* cx, bool* retval);
+
+struct GlobalProperties {
+ GlobalProperties() {
+ mozilla::PodZero(this);
+
+ }
+ bool Parse(JSContext* cx, JS::HandleObject obj);
+ bool DefineInXPCComponents(JSContext* cx, JS::HandleObject obj);
+ bool DefineInSandbox(JSContext* cx, JS::HandleObject obj);
+ bool CSS : 1;
+ bool indexedDB : 1;
+ bool XMLHttpRequest : 1;
+ bool TextDecoder : 1;
+ bool TextEncoder : 1;
+ bool URL : 1;
+ bool URLSearchParams : 1;
+ bool atob : 1;
+ bool btoa : 1;
+ bool Blob : 1;
+ bool Directory : 1;
+ bool File : 1;
+ bool crypto : 1;
+ bool rtcIdentityProvider : 1;
+ bool fetch : 1;
+ bool caches : 1;
+ bool fileReader: 1;
+private:
+ bool Define(JSContext* cx, JS::HandleObject obj);
+};
+
+// Infallible.
+already_AddRefed<nsIXPCComponents_utils_Sandbox>
+NewSandboxConstructor();
+
+// Returns true if class of 'obj' is SandboxClass.
+bool
+IsSandbox(JSObject* obj);
+
+class MOZ_STACK_CLASS OptionsBase {
+public:
+ explicit OptionsBase(JSContext* cx = xpc_GetSafeJSContext(),
+ JSObject* options = nullptr)
+ : mCx(cx)
+ , mObject(cx, options)
+ { }
+
+ virtual bool Parse() = 0;
+
+protected:
+ bool ParseValue(const char* name, JS::MutableHandleValue prop, bool* found = nullptr);
+ bool ParseBoolean(const char* name, bool* prop);
+ bool ParseObject(const char* name, JS::MutableHandleObject prop);
+ bool ParseJSString(const char* name, JS::MutableHandleString prop);
+ bool ParseString(const char* name, nsCString& prop);
+ bool ParseString(const char* name, nsString& prop);
+ bool ParseId(const char* name, JS::MutableHandleId id);
+ bool ParseUInt32(const char* name, uint32_t* prop);
+
+ JSContext* mCx;
+ JS::RootedObject mObject;
+};
+
+class MOZ_STACK_CLASS SandboxOptions : public OptionsBase {
+public:
+ explicit SandboxOptions(JSContext* cx = xpc_GetSafeJSContext(),
+ JSObject* options = nullptr)
+ : OptionsBase(cx, options)
+ , wantXrays(true)
+ , allowWaivers(true)
+ , wantComponents(true)
+ , wantExportHelpers(false)
+ , isWebExtensionContentScript(false)
+ , waiveInterposition(false)
+ , proto(cx)
+ , addonId(cx)
+ , writeToGlobalPrototype(false)
+ , sameZoneAs(cx)
+ , freshZone(false)
+ , invisibleToDebugger(false)
+ , discardSource(false)
+ , metadata(cx)
+ , userContextId(0)
+ , originAttributes(cx)
+ { }
+
+ virtual bool Parse();
+
+ bool wantXrays;
+ bool allowWaivers;
+ bool wantComponents;
+ bool wantExportHelpers;
+ bool isWebExtensionContentScript;
+ bool waiveInterposition;
+ JS::RootedObject proto;
+ nsCString sandboxName;
+ JS::RootedString addonId;
+ bool writeToGlobalPrototype;
+ JS::RootedObject sameZoneAs;
+ bool freshZone;
+ bool invisibleToDebugger;
+ bool discardSource;
+ GlobalProperties globalProperties;
+ JS::RootedValue metadata;
+ uint32_t userContextId;
+ JS::RootedObject originAttributes;
+
+protected:
+ bool ParseGlobalProperties();
+};
+
+class MOZ_STACK_CLASS CreateObjectInOptions : public OptionsBase {
+public:
+ explicit CreateObjectInOptions(JSContext* cx = xpc_GetSafeJSContext(),
+ JSObject* options = nullptr)
+ : OptionsBase(cx, options)
+ , defineAs(cx, JSID_VOID)
+ { }
+
+ virtual bool Parse() { return ParseId("defineAs", &defineAs); }
+
+ JS::RootedId defineAs;
+};
+
+class MOZ_STACK_CLASS ExportFunctionOptions : public OptionsBase {
+public:
+ explicit ExportFunctionOptions(JSContext* cx = xpc_GetSafeJSContext(),
+ JSObject* options = nullptr)
+ : OptionsBase(cx, options)
+ , defineAs(cx, JSID_VOID)
+ , allowCrossOriginArguments(false)
+ { }
+
+ virtual bool Parse() {
+ return ParseId("defineAs", &defineAs) &&
+ ParseBoolean("allowCrossOriginArguments", &allowCrossOriginArguments);
+ }
+
+ JS::RootedId defineAs;
+ bool allowCrossOriginArguments;
+};
+
+class MOZ_STACK_CLASS FunctionForwarderOptions : public OptionsBase {
+public:
+ explicit FunctionForwarderOptions(JSContext* cx = xpc_GetSafeJSContext(),
+ JSObject* options = nullptr)
+ : OptionsBase(cx, options)
+ , allowCrossOriginArguments(false)
+ { }
+
+ JSObject* ToJSObject(JSContext* cx) {
+ JS::RootedObject obj(cx, JS_NewObjectWithGivenProto(cx, nullptr, nullptr));
+ if (!obj)
+ return nullptr;
+
+ JS::RootedValue val(cx);
+ unsigned attrs = JSPROP_READONLY | JSPROP_PERMANENT;
+ val = JS::BooleanValue(allowCrossOriginArguments);
+ if (!JS_DefineProperty(cx, obj, "allowCrossOriginArguments", val, attrs))
+ return nullptr;
+
+ return obj;
+ }
+
+ virtual bool Parse() {
+ return ParseBoolean("allowCrossOriginArguments", &allowCrossOriginArguments);
+ }
+
+ bool allowCrossOriginArguments;
+};
+
+class MOZ_STACK_CLASS StackScopedCloneOptions : public OptionsBase {
+public:
+ explicit StackScopedCloneOptions(JSContext* cx = xpc_GetSafeJSContext(),
+ JSObject* options = nullptr)
+ : OptionsBase(cx, options)
+ , wrapReflectors(false)
+ , cloneFunctions(false)
+ , deepFreeze(false)
+ { }
+
+ virtual bool Parse() {
+ return ParseBoolean("wrapReflectors", &wrapReflectors) &&
+ ParseBoolean("cloneFunctions", &cloneFunctions) &&
+ ParseBoolean("deepFreeze", &deepFreeze);
+ }
+
+ // When a reflector is encountered, wrap it rather than aborting the clone.
+ bool wrapReflectors;
+
+ // When a function is encountered, clone it (exportFunction-style) rather than
+ // aborting the clone.
+ bool cloneFunctions;
+
+ // If true, the resulting object is deep-frozen after being cloned.
+ bool deepFreeze;
+};
+
+JSObject*
+CreateGlobalObject(JSContext* cx, const JSClass* clasp, nsIPrincipal* principal,
+ JS::CompartmentOptions& aOptions);
+
+// Modify the provided compartment options, consistent with |aPrincipal| 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::CompartmentOptions& from an existing global
+// object.)
+void
+InitGlobalObjectOptions(JS::CompartmentOptions& aOptions,
+ nsIPrincipal* aPrincipal);
+
+// Finish initializing an already-created, not-yet-exposed-to-script global
+// object. This will attach a Components object (if necessary) and call
+// |JS_FireOnNewGlobalObject| (if necessary).
+//
+// If you must modify compartment options, see InitGlobalObjectOptions above.
+bool
+InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal,
+ uint32_t aFlags);
+
+// Helper for creating a sandbox object to use for evaluating
+// untrusted code completely separated from all other code in the
+// system using EvalInSandbox(). Takes the JSContext on which to
+// do setup etc on, puts the sandbox object in *vp (which must be
+// rooted by the caller), and uses the principal that's either
+// directly passed in prinOrSop or indirectly as an
+// nsIScriptObjectPrincipal holding the principal. If no principal is
+// reachable through prinOrSop, a new null principal will be created
+// and used.
+nsresult
+CreateSandboxObject(JSContext* cx, JS::MutableHandleValue vp, nsISupports* prinOrSop,
+ xpc::SandboxOptions& options);
+// Helper for evaluating scripts in a sandbox object created with
+// CreateSandboxObject(). The caller is responsible of ensuring
+// that *rval doesn't get collected during the call or usage after the
+// call. This helper will use filename and lineNo for error reporting,
+// and if no filename is provided it will use the codebase from the
+// principal and line number 1 as a fallback.
+nsresult
+EvalInSandbox(JSContext* cx, JS::HandleObject sandbox, const nsAString& source,
+ const nsACString& filename, int32_t lineNo,
+ JSVersion jsVersion, JS::MutableHandleValue rval);
+
+nsresult
+GetSandboxAddonId(JSContext* cx, JS::HandleObject sandboxArg,
+ JS::MutableHandleValue rval);
+
+// Helper for retrieving metadata stored in a reserved slot. The metadata
+// is set during the sandbox creation using the "metadata" option.
+nsresult
+GetSandboxMetadata(JSContext* cx, JS::HandleObject sandboxArg,
+ JS::MutableHandleValue rval);
+
+nsresult
+SetSandboxMetadata(JSContext* cx, JS::HandleObject sandboxArg,
+ JS::HandleValue metadata);
+
+bool
+CreateObjectIn(JSContext* cx, JS::HandleValue vobj, CreateObjectInOptions& options,
+ JS::MutableHandleValue rval);
+
+bool
+EvalInWindow(JSContext* cx, const nsAString& source, JS::HandleObject scope,
+ JS::MutableHandleValue rval);
+
+bool
+ExportFunction(JSContext* cx, JS::HandleValue vscope, JS::HandleValue vfunction,
+ JS::HandleValue voptions, JS::MutableHandleValue rval);
+
+bool
+CloneInto(JSContext* cx, JS::HandleValue vobj, JS::HandleValue vscope,
+ JS::HandleValue voptions, JS::MutableHandleValue rval);
+
+bool
+StackScopedClone(JSContext* cx, StackScopedCloneOptions& options, JS::MutableHandleValue val);
+
+} /* namespace xpc */
+
+
+/***************************************************************************/
+// Inlined utilities.
+
+inline bool
+xpc_ForcePropertyResolve(JSContext* cx, JS::HandleObject obj, jsid id);
+
+inline jsid
+GetJSIDByIndex(JSContext* cx, unsigned index);
+
+namespace xpc {
+
+enum WrapperDenialType {
+ WrapperDenialForXray = 0,
+ WrapperDenialForCOW,
+ WrapperDenialTypeCount
+};
+bool ReportWrapperDenial(JSContext* cx, JS::HandleId id, WrapperDenialType type, const char* reason);
+
+class CompartmentPrivate
+{
+public:
+ enum LocationHint {
+ LocationHintRegular,
+ LocationHintAddon
+ };
+
+ explicit CompartmentPrivate(JSCompartment* c);
+
+ ~CompartmentPrivate();
+
+ static CompartmentPrivate* Get(JSCompartment* compartment)
+ {
+ MOZ_ASSERT(compartment);
+ void* priv = JS_GetCompartmentPrivate(compartment);
+ return static_cast<CompartmentPrivate*>(priv);
+ }
+
+ static CompartmentPrivate* Get(JSObject* object)
+ {
+ JSCompartment* compartment = js::GetObjectCompartment(object);
+ return Get(compartment);
+ }
+
+ // Controls whether this compartment gets Xrays to same-origin. This behavior
+ // is deprecated, but is still the default for sandboxes for compatibity
+ // reasons.
+ bool wantXrays;
+
+ // Controls whether this compartment is allowed to waive Xrays to content
+ // that it subsumes. This should generally be true, except in cases where we
+ // want to prevent code from depending on Xray Waivers (which might make it
+ // more portable to other browser architectures).
+ bool allowWaivers;
+
+ // This flag is intended for a very specific use, internal to Gecko. It may
+ // go away or change behavior at any time. It should not be added to any
+ // documentation and it should not be used without consulting the XPConnect
+ // module owner.
+ bool writeToGlobalPrototype;
+
+ // When writeToGlobalPrototype is true, we use this flag to temporarily
+ // disable the writeToGlobalPrototype behavior (when resolving standard
+ // classes, for example).
+ bool skipWriteToGlobalPrototype;
+
+ // This scope corresponds to a WebExtension content script, and receives
+ // various bits of special compatibility behavior.
+ bool isWebExtensionContentScript;
+
+ // Even if an add-on needs interposition, it does not necessary need it
+ // for every scope. If this flag is set we waive interposition for this
+ // scope.
+ bool waiveInterposition;
+
+ // If CPOWs are disabled for browser code via the
+ // dom.ipc.cpows.forbid-unsafe-from-browser preferences, then only
+ // add-ons can use CPOWs. This flag allows a non-addon scope
+ // to opt into CPOWs. It's necessary for the implementation of
+ // RemoteAddonsParent.jsm.
+ bool allowCPOWs;
+
+ // This is only ever set during mochitest runs when enablePrivilege is called.
+ // It's intended as a temporary stopgap measure until we can finish ripping out
+ // enablePrivilege. Once set, this value is never unset (i.e., it doesn't follow
+ // the old scoping rules of enablePrivilege).
+ //
+ // Using it in production is inherently unsafe.
+ bool universalXPConnectEnabled;
+
+ // This is only ever set during mochitest runs when enablePrivilege is called.
+ // It allows the SpecialPowers scope to waive the normal chrome security
+ // wrappers and expose properties directly to content. This lets us avoid a
+ // bunch of overhead and complexity in our SpecialPowers automation glue.
+ //
+ // Using it in production is inherently unsafe.
+ bool forcePermissiveCOWs;
+
+ // Whether we've emitted a warning about a property that was filtered out
+ // by a security wrapper. See XrayWrapper.cpp.
+ bool wrapperDenialWarnings[WrapperDenialTypeCount];
+
+ // The scriptability of this compartment.
+ Scriptability scriptability;
+
+ // Our XPCWrappedNativeScope. This is non-null if and only if this is an
+ // XPConnect compartment.
+ XPCWrappedNativeScope* scope;
+
+ const nsACString& GetLocation() {
+ if (location.IsEmpty() && locationURI) {
+
+ nsCOMPtr<nsIXPConnectWrappedJS> jsLocationURI =
+ do_QueryInterface(locationURI);
+ if (jsLocationURI) {
+ // We cannot call into JS-implemented nsIURI objects, because
+ // we are iterating over the JS heap at this point.
+ location =
+ NS_LITERAL_CSTRING("<JS-implemented nsIURI location>");
+ } else if (NS_FAILED(locationURI->GetSpec(location))) {
+ location = NS_LITERAL_CSTRING("<unknown location>");
+ }
+ }
+ return location;
+ }
+ bool GetLocationURI(nsIURI** aURI) {
+ return GetLocationURI(LocationHintRegular, aURI);
+ }
+ bool GetLocationURI(LocationHint aLocationHint, nsIURI** aURI) {
+ if (locationURI) {
+ nsCOMPtr<nsIURI> rval = locationURI;
+ rval.forget(aURI);
+ return true;
+ }
+ return TryParseLocationURI(aLocationHint, aURI);
+ }
+ void SetLocation(const nsACString& aLocation) {
+ if (aLocation.IsEmpty())
+ return;
+ if (!location.IsEmpty() || locationURI)
+ return;
+ location = aLocation;
+ }
+ void SetLocationURI(nsIURI* aLocationURI) {
+ if (!aLocationURI)
+ return;
+ if (locationURI)
+ return;
+ locationURI = aLocationURI;
+ }
+
+ JSObject2WrappedJSMap* GetWrappedJSMap() const { return mWrappedJSMap; }
+ void UpdateWeakPointersAfterGC(XPCJSContext* context);
+
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
+
+private:
+ nsCString location;
+ nsCOMPtr<nsIURI> locationURI;
+ JSObject2WrappedJSMap* mWrappedJSMap;
+
+ bool TryParseLocationURI(LocationHint aType, nsIURI** aURI);
+};
+
+bool IsUniversalXPConnectEnabled(JSCompartment* compartment);
+bool IsUniversalXPConnectEnabled(JSContext* cx);
+bool EnableUniversalXPConnect(JSContext* cx);
+
+inline void
+CrashIfNotInAutomation()
+{
+ MOZ_RELEASE_ASSERT(IsInAutomation());
+}
+
+inline XPCWrappedNativeScope*
+ObjectScope(JSObject* obj)
+{
+ return CompartmentPrivate::Get(obj)->scope;
+}
+
+JSObject* NewOutObject(JSContext* cx);
+bool IsOutObject(JSContext* cx, JSObject* obj);
+
+nsresult HasInstance(JSContext* cx, JS::HandleObject objArg, const nsID* iid, bool* bp);
+
+nsIPrincipal* GetObjectPrincipal(JSObject* obj);
+
+} // namespace xpc
+
+namespace mozilla {
+namespace dom {
+extern bool
+DefineStaticJSVals(JSContext* cx);
+} // namespace dom
+} // namespace mozilla
+
+bool
+xpc_LocalizeContext(JSContext* cx);
+void
+xpc_DelocalizeContext(JSContext* cx);
+
+/***************************************************************************/
+// Inlines use the above - include last.
+
+#include "XPCInlines.h"
+
+/***************************************************************************/
+// Maps have inlines that use the above - include last.
+
+#include "XPCMaps.h"
+
+/***************************************************************************/
+
+#endif /* xpcprivate_h___ */