Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  xpcprivate.h   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


/*
 * 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 compartments. The
 * XPCWrappedNativeScope has a pointer to the JS compartment. The global of a
 * flattened JS object is one of the globals in this compartment (the exception
 * to this rule is when a PreCreate hook asks for a different global; 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 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/BasePrincipal.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/DefineEnum.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/mozalloc.h"
#include "mozilla/Preferences.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Vector.h"

#include "mozilla/dom/ScriptSettings.h"

#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "xpcpublic.h"
#include "js/HashTable.h"
#include "js/GCHashTable.h"
#include "js/Object.h"              // JS::GetClass, JS::GetCompartment
#include "js/PropertyAndElement.h"  // JS_DefineProperty
#include "js/TracingAPI.h"
#include "js/WeakMapPtr.h"
#include "nscore.h"
#include "nsXPCOM.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 "nsISimpleEnumerator.h"
#include "nsIXPConnect.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 "prenv.h"
#include "prcvar.h"
#include "nsString.h"
#include "nsReadableUtils.h"

#include "MainThreadUtils.h"

#include "nsIConsoleService.h"

#include "nsVariant.h"
#include "nsCOMArray.h"
#include "nsTArray.h"
#include "nsBaseHashtable.h"
#include "nsHashKeys.h"
#include "nsWrapperCache.h"
#include "nsDeque.h"

#include "nsIScriptSecurityManager.h"

#include "nsIPrincipal.h"
#include "nsJSPrincipals.h"
#include "nsIScriptObjectPrincipal.h"
#include "xpcObjectHelper.h"

#include "SandboxPrivate.h"
#include "SystemGlobal.h"

#ifdef XP_WIN
// Nasty MS defines
#  ifdef GetClassInfo
#    undef GetClassInfo
#  endif
#  ifdef GetClassName
#    undef GetClassName
#  endif
#endif /* XP_WIN */

namespace mozilla {
namespace dom {
class AutoEntryScript;
class Exception;
}  // namespace dom
}  // namespace mozilla

/***************************************************************************/
// data declarations...
extern const char XPC_EXCEPTION_CONTRACTID[];
extern const char XPC_CONSOLE_CONTRACTID[];
extern const char XPC_SCRIPT_ERROR_CONTRACTID[];
extern const char XPC_XPCONNECT_CONTRACTID[];

/***************************************************************************/
// Helper function.

namespace xpc {

inline bool IsWrappedNativeReflector(JSObject* obj) {
  return JS::GetClass(obj)->isWrappedNative();
}

}  // namespace xpc

/***************************************************************************
****************************************************************************
*
* 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

  // non-interface implementation
 public:
  static XPCJSRuntime* GetRuntimeInstance();
  XPCJSContext* GetContext() { return mContext; }

  static nsIScriptSecurityManager* SecurityManager() {
    MOZ_ASSERT(NS_IsMainThread());
    MOZ_ASSERT(gScriptSecurityManager);
    return gScriptSecurityManager;
  }

  static nsIPrincipal* SystemPrincipal() {
    MOZ_ASSERT(NS_IsMainThread());
    MOZ_ASSERT(gSystemPrincipal);
    return gSystemPrincipal;
  }

  // Called by module code in dll startup
  static void InitStatics();
  // Called by module code on dll shutdown.
  static void ReleaseXPConnectSingleton();

  static void InitJSContext();

  void RecordTraversal(void* p, nsISupports* s);

 protected:
  virtual ~nsXPConnect();

  nsXPConnect();

 private:
  // Singleton instance
  static nsXPConnect* gSelf;
  static bool gOnceAliveNowDead;

  XPCJSContext* mContext = nullptr;
  XPCJSRuntime* mRuntime = nullptr;

  friend class nsIXPConnect;

 public:
  static nsIScriptSecurityManager* gScriptSecurityManager;
  static nsIPrincipal* gSystemPrincipal;
};

/***************************************************************************/

// 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;

// clang-format off
MOZ_DEFINE_ENUM(WatchdogTimestampCategory, (
    TimestampWatchdogWakeup,
    TimestampWatchdogHibernateStart,
    TimestampWatchdogHibernateStop,
    TimestampContextStateChange
));
// clang-format on

class AsyncFreeSnowWhite;
class XPCWrappedNativeScope;

using XPCWrappedNativeScopeList = mozilla::LinkedList<XPCWrappedNativeScope>;

class XPCJSContext final : public mozilla::CycleCollectedJSContext,
                           public mozilla::LinkedListElement<XPCJSContext> {
 public:
  static XPCJSContext* NewXPCJSContext();
  static XPCJSContext* Get();

  XPCJSRuntime* Runtime() const;

  virtual mozilla::CycleCollectedJSRuntime* CreateRuntime(
      JSContext* aCx) override;

  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;
  }

  bool JSContextInitialized(JSContext* cx);

  virtual void BeforeProcessTask(bool aMightBlock) override;
  virtual void AfterProcessTask(uint32_t aNewRecursionDepth) override;

  // Relay to the CCGCScheduler instead of queuing up an idle runnable
  // (as is done for workers in CycleCollectedJSContext).
  virtual void MaybePokeGC() override;

  ~XPCJSContext();

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);

  bool IsSystemCaller() const override;

  AutoMarkingPtr** GetAutoRootsAdr() { return &mAutoRoots; }

  nsresult GetPendingResult() { return mPendingResult; }
  void SetPendingResult(nsresult rv) { mPendingResult = rv; }

  PRTime GetWatchdogTimestamp(WatchdogTimestampCategory aCategory);

  static bool RecordScriptActivity(bool aActive);

  bool SetHasScriptActivity(bool aActive) {
    bool oldValue = mHasScriptActivity;
    mHasScriptActivity = aActive;
    return oldValue;
  }

  static bool InterruptCallback(JSContext* cx);

  // Mapping of often used strings to jsid atoms that live 'forever'.
  //
  // To add a new string: add to this list and to XPCJSRuntime::mStrings
  // at the top of XPCJSRuntime.cpp
  enum {
    IDX_CONSTRUCTOR = 0,
    IDX_TO_STRING,
    IDX_TO_SOURCE,
    IDX_VALUE,
    IDX_QUERY_INTERFACE,
    IDX_COMPONENTS,
    IDX_CC,
    IDX_CI,
    IDX_CR,
    IDX_CU,
    IDX_SERVICES,
    IDX_WRAPPED_JSOBJECT,
    IDX_PROTOTYPE,
    IDX_EVAL,
    IDX_CONTROLLERS,
    IDX_CONTROLLERS_CLASS,
    IDX_LENGTH,
    IDX_NAME,
    IDX_UNDEFINED,
    IDX_EMPTYSTRING,
    IDX_FILENAME,
    IDX_LINENUMBER,
    IDX_COLUMNNUMBER,
    IDX_STACK,
    IDX_MESSAGE,
    IDX_CAUSE,
    IDX_ERRORS,
    IDX_LASTINDEX,
    IDX_THEN,
    IDX_ISINSTANCE,
    IDX_INFINITY,
    IDX_NAN,
    IDX_CLASS_ID,
    IDX_INTERFACE_ID,
    IDX_INITIALIZER,
    IDX_PRINT,
    IDX_FETCH,
    IDX_CRYPTO,
    IDX_INDEXEDDB,
    IDX_STRUCTUREDCLONE,
    IDX_LOCKS,
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    IDX_SUPPRESSED,
    IDX_ERROR,
#endif
    IDX_TOTAL_COUNT  // just a count of the above
  };

  inline JS::HandleId GetStringID(unsigned index) const;
  inline const char* GetStringName(unsigned index) const;

 private:
  XPCJSContext();

  MOZ_IS_CLASS_INIT
  nsresult Initialize();

  XPCCallContext* mCallContext;
  AutoMarkingPtr* mAutoRoots;
  jsid mResolveName;
  XPCWrappedNative* mResolvingWrapper;
  WatchdogManager* mWatchdogManager;

  // Number of XPCJSContexts currently alive.
  static uint32_t sInstanceCount;
  static mozilla::StaticAutoPtr<WatchdogManager> sWatchdogInstance;
  static WatchdogManager* GetWatchdogManager();

  // 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;
  bool mExecutedChromeScript;

  bool mHasScriptActivity;

  // mPendingResult is used to implement Components.returnCode.  Only really
  // meaningful while calling through XPCWrappedJS.
  nsresult mPendingResult;

  // These members must be accessed via WatchdogManager.
  enum { CONTEXT_ACTIVE, CONTEXT_INACTIVE } mActive;
  PRTime mLastStateChange;

  friend class XPCJSRuntime;
  friend class Watchdog;
  friend class WatchdogManager;
  friend class AutoLockWatchdog;
};

class XPCJSRuntime final : public mozilla::CycleCollectedJSRuntime {
 public:
  static XPCJSRuntime* Get();

  void RemoveWrappedJS(nsXPCWrappedJS* wrapper);
  void AssertInvalidWrappedJSNotInTable(nsXPCWrappedJS* wrapper) const;

  JSObject2WrappedJSMap* GetMultiCompartmentWrappedJSMap() const {
    return mWrappedJSMap.get();
  }

  IID2NativeInterfaceMap* GetIID2NativeInterfaceMap() const {
    return mIID2NativeInterfaceMap.get();
  }

  ClassInfo2NativeSetMap* GetClassInfo2NativeSetMap() const {
    return mClassInfo2NativeSetMap.get();
  }

  NativeSetMap* GetNativeSetMap() const { return mNativeSetMap.get(); }

  using WrappedNativeProtoVector =
      mozilla::Vector<mozilla::UniquePtr<XPCWrappedNativeProto>, 0,
                      InfallibleAllocPolicy>;
  WrappedNativeProtoVector& GetDyingWrappedNativeProtos() {
    return mDyingWrappedNativeProtos;
  }

  XPCWrappedNativeScopeList& GetWrappedNativeScopes() {
    return mWrappedNativeScopes;
  }

  bool InitializeStrings(JSContext* cx);

  virtual bool DescribeCustomObjects(JSObject* aObject, const JSClass* aClasp,
                                     char (&aName)[72]) const override;
  virtual bool NoteCustomGCThingXPCOMChildren(
      const JSClass* aClasp, JSObject* aObj,
      nsCycleCollectionTraversalCallback& aCb) const 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; }

  JS::HandleId GetStringID(unsigned index) const {
    MOZ_ASSERT(index < XPCJSContext::IDX_TOTAL_COUNT, "index out of range");
    // fromMarkedLocation() is safe because the string is interned.
    return JS::HandleId::fromMarkedLocation(&mStrIDs[index]);
  }
  const char* GetStringName(unsigned index) const {
    MOZ_ASSERT(index < XPCJSContext::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(mozilla::CCReason aReason) override;
  void EndCycleCollectionCallback(
      mozilla::CycleCollectorResults& aResults) override;
  void DispatchDeferredDeletion(bool aContinuation,
                                bool aPurge = false) override;

  void CustomGCCallback(JSGCStatus status) override;
  void CustomOutOfMemoryCallback() override;
  void OnLargeAllocationFailure();
  static void GCSliceCallback(JSContext* cx, JS::GCProgress progress,
                              const JS::GCDescription& desc);
  static void DoCycleCollectionCallback(JSContext* cx);
  static void FinalizeCallback(JS::GCContext* gcx, JSFinalizeStatus status,
                               void* data);
  static void WeakPointerZonesCallback(JSTracer* trc, void* data);
  static void WeakPointerCompartmentCallback(JSTracer* trc,
                                             JS::Compartment* comp, void* data);

  inline void AddSubjectToFinalizationWJS(nsXPCWrappedJS* wrappedJS);

  void DebugDump(int16_t depth);

  bool GCIsRunning() const { return mGCIsRunning; }

  ~XPCJSRuntime();

  void AddGCCallback(xpcGCCallback cb);
  void RemoveGCCallback(xpcGCCallback cb);

  JSObject* GetUAWidgetScope(JSContext* cx, nsIPrincipal* principal);

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);

  /**
   * The unprivileged junk scope is an unprivileged sandbox global used for
   * convenience by certain operations which need an unprivileged global but
   * don't have one immediately handy. It should generally be avoided when
   * possible.
   *
   * The scope is created lazily when it is needed, and held weakly so that it
   * is destroyed when there are no longer any remaining external references to
   * it. This means that under low memory conditions, when the scope does not
   * already exist, we may not be able to create one. In these circumstances,
   * the infallible version of this API will abort, and the fallible version
   * will return null. Callers should therefore prefer the fallible version when
   * on a codepath which can already return failure, but may use the infallible
   * one otherwise.
   */

  JSObject* UnprivilegedJunkScope();
  JSObject* UnprivilegedJunkScope(const mozilla::fallible_t&);

  bool IsUnprivilegedJunkScope(JSObject*);

  void DeleteSingletonScopes();

 private:
  explicit XPCJSRuntime(JSContext* aCx);

  MOZ_IS_CLASS_INIT
  void Initialize(JSContext* cx);
  void Shutdown(JSContext* cx) override;

  static const charconst mStrings[XPCJSContext::IDX_TOTAL_COUNT];
  jsid mStrIDs[XPCJSContext::IDX_TOTAL_COUNT];

  struct Hasher {
    using Key = RefPtr<mozilla::BasePrincipal>;
    using Lookup = Key;
    static uint32_t hash(const Lookup& l) { return l->GetOriginNoSuffixHash(); }
    static bool match(const Key& k, const Lookup& l) {
      return k->FastEquals(l);
    }
  };

  struct MapEntryGCPolicy {
    static bool traceWeak(JSTracer* trc,
                          RefPtr<mozilla::BasePrincipal>* /* unused */,
                          JS::Heap<JSObject*>* value) {
      return JS::GCPolicy<JS::Heap<JSObject*>>::traceWeak(trc, value);
    }
  };

  typedef JS::GCHashMap<RefPtr<mozilla::BasePrincipal>, JS::Heap<JSObject*>,
                        Hasher, js::SystemAllocPolicy, MapEntryGCPolicy>
      Principal2JSObjectMap;

  mozilla::UniquePtr<JSObject2WrappedJSMap> mWrappedJSMap;
  mozilla::UniquePtr<IID2NativeInterfaceMap> mIID2NativeInterfaceMap;
  mozilla::UniquePtr<ClassInfo2NativeSetMap> mClassInfo2NativeSetMap;
  mozilla::UniquePtr<NativeSetMap> mNativeSetMap;
  Principal2JSObjectMap mUAWidgetScopeMap;
  XPCWrappedNativeScopeList mWrappedNativeScopes;
  WrappedNativeProtoVector mDyingWrappedNativeProtos;
  bool mGCIsRunning;
  nsTArray<nsISupports*> mNativesToReleaseArray;
  bool mDoingFinalization;
  mozilla::LinkedList<nsXPCWrappedJS> mSubjectToFinalizationWJS;
  nsTArray<xpcGCCallback> extraGCCallbacks;
  JS::GCSliceCallback mPrevGCSliceCallback;
  JS::DoCycleCollectionCallback mPrevDoCycleCollectionCallback;
  mozilla::WeakPtr<SandboxPrivate> mUnprivilegedJunkScope;
  RefPtr<AsyncFreeSnowWhite> mAsyncSnowWhiteFreer;

  friend class XPCJSContext;
  friend class XPCIncrementalReleaseRunnable;
};

inline JS::HandleId XPCJSContext::GetStringID(unsigned index) const {
  return Runtime()->GetStringID(index);
}

inline const char* XPCJSContext::GetStringName(unsigned index) const {
  return Runtime()->GetStringName(index);
}

/***************************************************************************/

// 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:
  enum : unsigned { NO_ARGS = (unsigned)-1 };

  explicit XPCCallContext(JSContext* cx, JS::HandleObject obj = nullptr,
                          JS::HandleObject funobj = nullptr,
                          JS::HandleId id = JS::VoidHandlePropertyKey,
                          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 XPCWrappedNative* GetWrapper() const;

  inline bool CanGetTearOff() const;
  inline XPCWrappedNativeTearOff* GetTearOff() const;

  inline nsIXPCScriptable* GetScriptable() const;
  inline XPCNativeSet* GetSet() const;
  inline bool CanGetInterface() const;
  inline XPCNativeInterface* GetInterface() const;
  inline XPCNativeMember* GetMember() const;
  inline bool HasInterfaceAndMember() const;
  inline bool GetStaticMemberIsLocal() const;
  inline unsigned GetArgc() const;
  inline JS::Value* GetArgv() const;

  inline uint16_t GetMethodIndex() const;

  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:
  State mState;

  nsCOMPtr<nsIXPConnect> mXPC;

  XPCJSContext* mXPCJSContext;
  JSContext* mJSContext;

  // ctor does not necessarily init the following. BEWARE!

  XPCCallContext* mPrevCallContext;

  XPCWrappedNative* mWrapper;
  XPCWrappedNativeTearOff* mTearOff;

  nsCOMPtr<nsIXPCScriptable> mScriptable;

  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 JSClass XPC_WN_NoHelper_JSClass;
extern const JSClass XPC_WN_Proto_JSClass;
extern const JSClass XPC_WN_Tearoff_JSClass;
extern const JSClass 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);

/***************************************************************************/
// XPCWrappedNativeScope is one-to-one with a JS compartment.

class XPCWrappedNativeScope final
    : public mozilla::LinkedListElement<XPCWrappedNativeScope> {
 public:
  XPCJSRuntime* GetRuntime() const { return XPCJSRuntime::Get(); }

  Native2WrappedNativeMap* GetWrappedNativeMap() const {
    return mWrappedNativeMap.get();
  }

  ClassInfo2WrappedNativeProtoMap* GetWrappedNativeProtoMap() const {
    return mWrappedNativeProtoMap.get();
  }

  nsXPCComponents* GetComponents() const { return mComponents; }

  bool AttachComponentsObject(JSContext* aCx);

  bool AttachJSServices(JSContext* aCx);

  // Returns the JS object reflection of the Components object.
  bool GetComponentsJSObject(JSContext* cx, JS::MutableHandleObject obj);

  JSObject* GetExpandoChain(JS::HandleObject target);

  JSObject* DetachExpandoChain(JS::HandleObject target);

  bool SetExpandoChain(JSContext* cx, JS::HandleObject target,
                       JS::HandleObject chain);

  static void SystemIsBeingShutDown();

  static void TraceWrappedNativesInAllScopes(XPCJSRuntime* xpcrt,
                                             JSTracer* trc);

  void TraceInside(JSTracer* trc) {
    if (mXrayExpandos.initialized()) {
      mXrayExpandos.trace(trc);
    }
    JS::TraceEdge(trc, &mIDProto, "XPCWrappedNativeScope::mIDProto");
    JS::TraceEdge(trc, &mIIDProto, "XPCWrappedNativeScope::mIIDProto");
    JS::TraceEdge(trc, &mCIDProto, "XPCWrappedNativeScope::mCIDProto");
  }

  static void SuspectAllWrappers(nsCycleCollectionNoteRootCallback& cb);

  static void SweepAllWrappedNativeTearOffs();

  void UpdateWeakPointersAfterGC(JSTracer* trc);

  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(JSContext* cx,
                                              ScopeSizeInfo* scopeSizeInfo);

  void AddSizeOfIncludingThis(JSContext* cx, ScopeSizeInfo* scopeSizeInfo);

  // Check whether our mAllowContentXBLScope state matches the given
  // principal.  This is used to avoid sharing compartments on
  // mismatch.
  bool XBLScopeStateMatches(nsIPrincipal* aPrincipal);

  XPCWrappedNativeScope(JS::Compartment* aCompartment,
                        JS::HandleObject aFirstGlobal);
  virtual ~XPCWrappedNativeScope();

  mozilla::UniquePtr<JSObject2JSObjectMap> mWaiverWrapperMap;

  JS::Compartment* Compartment() const { return mCompartment; }

  // Returns the global to use for new WrappedNative objects allocated in this
  // compartment. This is better than using arbitrary globals we happen to be in
  // because it prevents leaks (objects keep their globals alive).
  JSObject* GetGlobalForWrappedNatives() {
    return js::GetFirstGlobalInCompartment(Compartment());
  }

  bool AllowContentXBLScope(JS::Realm* aRealm);

  // ID Object prototype caches.
  JS::Heap<JSObject*> mIDProto;
  JS::Heap<JSObject*> mIIDProto;
  JS::Heap<JSObject*> mCIDProto;

 protected:
  XPCWrappedNativeScope() = delete;

 private:
  mozilla::UniquePtr<Native2WrappedNativeMap> mWrappedNativeMap;
  mozilla::UniquePtr<ClassInfo2WrappedNativeProtoMap> mWrappedNativeProtoMap;
  RefPtr<nsXPCComponents> mComponents;
  JS::Compartment* mCompartment;

  JS::WeakMapPtr<JSObject*, JSObject*> mXrayExpandos;

  // For remote XUL domains, we run all XBL in the content scope for compat
  // reasons (though we sometimes pref this off for automation). We
  // track the result of this decision (mAllowContentXBLScope) for now.
  bool mAllowContentXBLScope;
};

/***************************************************************************/
// 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 */
  MOZ_COUNTED_DEFAULT_CTOR(XPCNativeMember)
  MOZ_COUNTED_DTOR(XPCNativeMember)

  XPCNativeMember(const XPCNativeMember& other)
      : mName(other.mName),
        mIndex(other.mIndex),
        mFlags(other.mFlags),
        mIndexInInterface(other.mIndexInInterface) {
    MOZ_COUNT_CTOR(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 enough 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;
};

/***************************************************************************/
// 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(JSContext* cx,
                                                           const nsIID* iid);
  static already_AddRefed<XPCNativeInterface> GetNewOrUsed(
      JSContext* cx, const nsXPTInterfaceInfo* info);
  static already_AddRefed<XPCNativeInterface> GetNewOrUsed(JSContext* cx,
                                                           const char* name);
  static already_AddRefed<XPCNativeInterface> GetISupports(JSContext* cx);

  inline const nsXPTInterfaceInfo* GetInterfaceInfo() const { return mInfo; }
  inline jsid GetName() const { return mName; }

  inline const nsIID* GetIID() const;
  inline const char* GetNameString() const;
  inline XPCNativeMember* FindMember(jsid name) 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);

  void Trace(JSTracer* trc);

 protected:
  static already_AddRefed<XPCNativeInterface> NewInstance(
      JSContext* cx, IID2NativeInterfaceMap* aMap,
      const nsXPTInterfaceInfo* aInfo);

  XPCNativeInterface() = delete;
  XPCNativeInterface(const nsXPTInterfaceInfo* aInfo, jsid aName)
      : mInfo(aInfo), mName(aName), mMemberCount(0) {}
  ~XPCNativeInterface();

  voidoperator new(size_t, void* p) noexcept(true) { return p; }

  XPCNativeInterface(const XPCNativeInterface& r) = delete;
  XPCNativeInterface& operator=(const XPCNativeInterface& r) = delete;

  static void DestroyInstance(XPCNativeInterface* inst);

 private:
  const nsXPTInterfaceInfo* 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)
      : mCx(nullptr), mBaseSet(baseSet), mAddition(nullptr) {
    MOZ_ASSERT(baseSet);
  }

  // This represents a new set containing only nsISupports and
  // |addition|.  This needs a JSContext because it may need to
  // construct some data structures that need one to construct them.
  explicit XPCNativeSetKey(JSContext* cx, XPCNativeInterface* addition)
      : mCx(cx), mBaseSet(nullptr), mAddition(addition) {
    MOZ_ASSERT(cx);
    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() = default;

  XPCNativeSet* GetBaseSet() const { return mBaseSet; }
  XPCNativeInterface* GetAddition() const { return mAddition; }

  mozilla::HashNumber Hash() const;

  // Allow shallow copy

 private:
  JSContext* mCx;
  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(JSContext* cx,
                                                     const nsIID* iid);
  static already_AddRefed<XPCNativeSet> GetNewOrUsed(JSContext* cx,
                                                     nsIClassInfo* classInfo);
  static already_AddRefed<XPCNativeSet> GetNewOrUsed(JSContext* cx,
                                                     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(
      JSContext* cx, 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;

  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(
      JSContext* cx, nsTArray<RefPtr<XPCNativeInterface>>&& array);
  static already_AddRefed<XPCNativeSet> NewInstanceMutate(XPCNativeSetKey* key);

  XPCNativeSet() : mInterfaceCount(0) {}
  ~XPCNativeSet();
  voidoperator new(size_t, void* p) noexcept(true) { return p; }

  static void DestroyInstance(XPCNativeSet* inst);

 private:
  uint16_t mInterfaceCount;
  // Always last - object sized for array.
  // These are strong references.
  XPCNativeInterface* mInterfaces[1];
};

/***********************************************/
// XPCWrappedNativeProtos hold the additional shared wrapper data for
// XPCWrappedNative whose native objects expose nsIClassInfo.
//
// The XPCWrappedNativeProto is owned by its mJSProtoObject, until that object
// is finalized. After that, it is owned by XPCJSRuntime's
// mDyingWrappedNativeProtos. See XPCWrappedNativeProto::JSProtoObjectFinalized
// and XPCJSRuntime::FinalizeCallback.

class XPCWrappedNativeProto final {
 public:
  enum Slots { ProtoSlot, SlotCount };

  static XPCWrappedNativeProto* GetNewOrUsed(JSContext* cx,
                                             XPCWrappedNativeScope* scope,
                                             nsIClassInfo* classInfo,
                                             nsIXPCScriptable* scriptable);

  XPCWrappedNativeScope* GetScope() const { return mScope; }

  XPCJSRuntime* GetRuntime() const { return mScope->GetRuntime(); }

  JSObject* GetJSProtoObject() const { return mJSProtoObject; }

  JSObject* GetJSProtoObjectPreserveColor() const {
    return mJSProtoObject.unbarrieredGet();
  }

  nsIClassInfo* GetClassInfo() const { return mClassInfo; }

  XPCNativeSet* GetSet() const { return mSet; }

  nsIXPCScriptable* GetScriptable() const { return mScriptable; }

  void JSProtoObjectFinalized(JS::GCContext* gcx, JSObject* obj);
  void JSProtoObjectMoved(JSObject* obj, const JSObject* old);

  static XPCWrappedNativeProto* Get(JSObject* obj);

  void SystemIsBeingShutDown();

  void DebugDump(int16_t depth);

  void TraceSelf(JSTracer* trc) {
    if (mJSProtoObject) {
      TraceEdge(trc, &mJSProtoObject, "XPCWrappedNativeProto::mJSProtoObject");
    }
  }

  void TraceJS(JSTracer* trc) { TraceSelf(trc); }

  // 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,
                        RefPtr<XPCNativeSet>&& Set);

  bool Init(JSContext* cx, nsIXPCScriptable* scriptable);

 private:
#ifdef DEBUG
  static int32_t gDEBUG_LiveProtoCount;
#endif

 private:
  XPCWrappedNativeScope* mScope;
  JS::Heap<JSObject*> mJSProtoObject;
  nsCOMPtr<nsIClassInfo> mClassInfo;
  RefPtr<XPCNativeSet> mSet;
  nsCOMPtr<nsIXPCScriptable> mScriptable;
};

/***********************************************/
// XPCWrappedNativeTearOff represents the info needed to make calls to one
// interface on the underlying native object of a XPCWrappedNative.

class XPCWrappedNativeTearOff final {
 public:
  enum Slots { FlatObjectSlot, TearOffSlot, SlotCount };

  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);

  static XPCWrappedNativeTearOff* Get(JSObject* obj);

  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_CYCLE_COLLECTION_CLASS(XPCWrappedNative)

  JSObject* GetJSObject() override;

  bool IsValid() const { return mFlatJSObject.hasFlag(FLAT_JS_OBJECT_VALID); }

  nsresult DebugDump(int16_t depth);

#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;
  }

  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(xpc::IsWrappedNativeReflector(obj));
    return JS::GetObjectISupports<XPCWrappedNative>(obj);
  }

 private:
  void SetFlatJSObject(JSObject* object);
  void UnsetFlatJSObject();

  inline void ExpireWrapper() {
    mMaybeScope = (XPCWrappedNativeScope*)(XPC_SCOPE_WORD(mMaybeScope) |
                                           XPC_WRAPPER_EXPIRED);
  }

 public:
  nsIXPCScriptable* GetScriptable() const { return mScriptable; }

  nsIClassInfo* GetClassInfo() const {
    return IsValid() && HasProto() ? GetProto()->GetClassInfo() : nullptr;
  }

  bool HasMutatedSet() const {
    return IsValid() && (!HasProto() || GetSet() != GetProto()->GetSet());
  }

  XPCJSRuntime* GetRuntime() const {
    XPCWrappedNativeScope* scope = GetScope();
    return scope ? scope->GetRuntime() : nullptr;
  }

  static nsresult WrapNewGlobal(JSContext* cx, xpcObjectHelper& nativeHelper,
                                nsIPrincipal* principal,
                                JS::RealmOptions& aOptions,
                                XPCWrappedNative** wrappedGlobal);

  static nsresult GetNewOrUsed(JSContext* cx, xpcObjectHelper& helper,
                               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);
  }

  XPCWrappedNativeTearOff* FindTearOff(JSContext* cx,
                                       XPCNativeInterface* aInterface,
                                       bool needJSObject = false,
                                       nsresult* pError = nullptr);
  XPCWrappedNativeTearOff* FindTearOff(JSContext* cx, const nsIID& iid);

  void Mark() const {}

  inline void TraceInside(JSTracer* trc) {
    if (HasProto()) {
      GetProto()->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 should be freed with js_free, or nullptr on
  // failure.
  char* ToString(XPCWrappedNativeTearOff* to = nullptr) const;

  static nsIXPCScriptable* GatherProtoScriptable(nsIClassInfo* classInfo);

  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(nsCOMPtr<nsISupports>&& aIdentity,
                   XPCWrappedNativeProto* aProto);

  // This ctor is used if this object will NOT have a proto.
  XPCWrappedNative(nsCOMPtr<nsISupports>&& aIdentity,
                   XPCWrappedNativeScope* aScope, RefPtr<XPCNativeSet>&& aSet);

  virtual ~XPCWrappedNative();
  void Destroy();

 private:
  enum {
    // Flags bits for mFlatJSObject:
    FLAT_JS_OBJECT_VALID = js::Bit(0)
  };

  bool Init(JSContext* cx, nsIXPCScriptable* scriptable);
  bool FinishInit(JSContext* cx);

  bool ExtendSet(JSContext* aCx, XPCNativeInterface* aInterface);

  nsresult InitTearOff(JSContext* cx, XPCWrappedNativeTearOff* aTearOff,
                       XPCNativeInterface* aInterface, bool needJSObject);

  bool InitTearOffJSObject(JSContext* cx, XPCWrappedNativeTearOff* to);

 public:
  static void GatherScriptable(nsISupports* obj, nsIClassInfo* classInfo,
                               nsIXPCScriptable** scrProto,
                               nsIXPCScriptable** scrWrapper);

 private:
  union {
    XPCWrappedNativeScope* mMaybeScope;
    XPCWrappedNativeProto* mMaybeProto;
  };
  RefPtr<XPCNativeSet> mSet;
  JS::TenuredHeap<JSObject*> mFlatJSObject;
  nsCOMPtr<nsIXPCScriptable> mScriptable;
  XPCWrappedNativeTearOff mFirstTearOff;
};

/***************************************************************************
****************************************************************************
*
* Core classes for wrapped JSObject for use from native code...
*
****************************************************************************
***************************************************************************/


/*************************/
// 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 mozilla::LinkedListElement<nsXPCWrappedJS> {
 public:
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_NSISUPPORTSWEAKREFERENCE

  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(
      nsXPCWrappedJS, nsIXPConnectWrappedJS)

  JSObject* GetJSObject() override;

  // This method is defined in XPCWrappedJSClass.cpp to preserve VCS blame.
  NS_IMETHOD CallMethod(uint16_t methodIndex, const nsXPTMethodInfo* info,
                        nsXPTCMiniVariant* nativeParams) 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(JSContext* cx, JS::HandleObject aJSObj,
                               REFNSIID aIID, nsXPCWrappedJS** wrapper);

  nsISomeInterface* GetXPTCStub() { return mXPTCStub; }

  nsresult DebugDump(int16_t depth);

  /**
   * 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;

  const nsXPTInterfaceInfo* GetInfo() const { return mInfo; }
  REFNSIID GetIID() const { return mInfo->IID(); }
  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(JSTracer* trc) {
    MOZ_ASSERT(IsRootWrapper());
    JS_UpdateWeakPointerAfterGC(trc, &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;
  }

  // This method is defined in XPCWrappedJSClass.cpp to preserve VCS blame.
  static void DebugDumpInterfaceInfo(const nsXPTInterfaceInfo* aInfo,
                                     int16_t depth);

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;

  virtual ~nsXPCWrappedJS();

 protected:
  nsXPCWrappedJS() = delete;
  nsXPCWrappedJS(JSContext* cx, JSObject* aJSObj,
                 const nsXPTInterfaceInfo* aInfo, nsXPCWrappedJS* root,
                 nsresult* rv);

  bool CanSkip();
  void Destroy();
  void Unlink();

 private:
  friend class nsIXPConnectWrappedJS;

  JS::Compartment* Compartment() const {
    return JS::GetCompartment(mJSObj.unbarrieredGet());
  }

  // These methods are defined in XPCWrappedJSClass.cpp to preserve VCS blame.
  static const nsXPTInterfaceInfo* GetInterfaceInfo(REFNSIID aIID);

  nsresult DelegatedQueryInterface(REFNSIID aIID, void** aInstancePtr);

  static JSObject* GetRootJSObject(JSContext* cx, JSObject* aJSObj);

  static JSObject* CallQueryInterfaceOnJSObject(JSContext* cx, JSObject* jsobj,
                                                JS::HandleObject scope,
                                                REFNSIID aIID);

  // aObj is the nsXPCWrappedJS's object. We used this as the callee (or |this|
  // if getter or setter).
  // 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,
      JS::HandleObject aObj, const char* aPropertyName,
      const char* anInterfaceName,
      mozilla::dom::Exception* aSyntheticException = nullptr);

  static bool GetArraySizeFromParam(const nsXPTMethodInfo* method,
                                    const nsXPTType& type,
                                    nsXPTCMiniVariant* params,
                                    uint32_t* result);

  static bool GetInterfaceTypeFromParam(const nsXPTMethodInfo* method,
                                        const nsXPTType& type,
                                        nsXPTCMiniVariant* params,
                                        nsID* result);

  static void CleanupOutparams(const nsXPTMethodInfo* info,
                               nsXPTCMiniVariant* nativeParams, bool inOutOnly,
                               uint8_t count);

  JS::Heap<JSObject*> mJSObj;
  const nsXPTInterfaceInfo* const mInfo;
  nsXPCWrappedJS* mRoot;  // If mRoot != this, it is an owning pointer.
  nsXPCWrappedJS* mNext;
  nsCOMPtr<nsISupports> mOuter;  // only set in root
};

/***************************************************************************
****************************************************************************
*
* All manner of utility classes follow...
*
****************************************************************************
***************************************************************************/


namespace xpc {

// A wrapper around JS iterators which presents an equivalent
// nsISimpleEnumerator interface for their contents.
class XPCWrappedJSIterator final : public nsISimpleEnumerator {
 public:
  NS_DECL_CYCLE_COLLECTION_CLASS(XPCWrappedJSIterator)
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_NSISIMPLEENUMERATOR
  NS_DECL_NSISIMPLEENUMERATORBASE

  explicit XPCWrappedJSIterator(nsIJSEnumerator* aEnum);

 private:
  ~XPCWrappedJSIterator() = default;

  nsCOMPtr<nsIJSEnumerator> mEnum;
  nsCOMPtr<nsIGlobalObject> mGlobal;
  nsCOMPtr<nsISupports> mNext;
  mozilla::Maybe<bool> mHasNext;
};

}  // namespace xpc

/***************************************************************************/
// class here just for static methods
class XPCConvert {
 public:
  /**
   * Convert a native object into a JS::Value.
   *
   * @param cx the JSContext representing the global we want the value in
   * @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(JSContext* cx, JS::MutableHandleValue d,
                            const void* s, const nsXPTType& type,
                            const nsID* iid, uint32_t arrlen, nsresult* pErr);

  static bool JSData2Native(JSContext* cx, void* d, JS::HandleValue s,
                            const nsXPTType& type, const nsID* iid,
                            uint32_t arrlen, nsresult* pErr);

  /**
   * Convert a native nsISupports into a JSObject.
   *
   * @param cx the JSContext representing the global we want the object in.
   * @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(JSContext* cx,
                                       JS::MutableHandleValue 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(JSContext* cx, 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);

  static nsresult JSValToXPCException(JSContext* cx, JS::MutableHandleValue s,
                                      const char* ifaceName,
                                      const char* methodName,
                                      mozilla::dom::Exception** exception);

  static nsresult ConstructException(nsresult rv, const char* message,
                                     const char* ifaceName,
                                     const char* methodName, nsISupports* data,
                                     mozilla::dom::Exception** exception,
                                     JSContext* cx, JS::Value* jsExceptionPtr);

 private:
  /**
   * Convert a native array into a JS::Value.
   *
   * @param cx the JSContext we're working with and in whose global the array
   *           should be created.
   * @param d [out] the resulting JS::Value
   * @param buf the native buffer containing input values
   * @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(JSContext* cx, JS::MutableHandleValue d,
                             const void* buf, const nsXPTType& type,
                             const nsID* iid, uint32_t count, nsresult* pErr);

  using ArrayAllocFixupLen = std::function<void*(uint32_t*)>;

  /**
   * Convert a JS::Value into a native array.
   *
   * @param cx the JSContext we're working with
   * @param aJSVal the JS::Value to convert
   * @param aEltType the type of objects in the array
   * @param aIID the interface of each object in the array
   * @param pErr [out] relevant error code, if any
   * @param aAllocFixupLen function called with the JS Array's length to
   *                       allocate the backing buffer. This function may
   *                       modify the length of array to be converted.
   */

  static bool JSArray2Native(JSContext* cx, JS::HandleValue aJSVal,
                             const nsXPTType& aEltType, const nsIID* aIID,
                             nsresult* pErr,
                             const ArrayAllocFixupLen& aAllocFixupLen);

  XPCConvert() = delete;
};

/***************************************************************************/
// code for throwing exceptions into JS

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=89 H=95 G=91

¤ Dauer der Verarbeitung: 0.27 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge