LCOV - code coverage report
Current view: top level - dom/bindings - BindingUtils.h (source / functions) Hit Total Coverage
Test: output.info Lines: 45 186 24.2 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef mozilla_dom_BindingUtils_h__
       8             : #define mozilla_dom_BindingUtils_h__
       9             : 
      10             : #include "jsfriendapi.h"
      11             : #include "js/Wrapper.h"
      12             : #include "js/Conversions.h"
      13             : #include "mozilla/ArrayUtils.h"
      14             : #include "mozilla/Alignment.h"
      15             : #include "mozilla/Array.h"
      16             : #include "mozilla/Assertions.h"
      17             : #include "mozilla/DeferredFinalize.h"
      18             : #include "mozilla/dom/BindingDeclarations.h"
      19             : #include "mozilla/dom/CallbackObject.h"
      20             : #include "mozilla/dom/DOMJSClass.h"
      21             : #include "mozilla/dom/DOMJSProxyHandler.h"
      22             : #include "mozilla/dom/Exceptions.h"
      23             : #include "mozilla/dom/NonRefcountedDOMObject.h"
      24             : #include "mozilla/dom/Nullable.h"
      25             : #include "mozilla/dom/PrototypeList.h"
      26             : #include "mozilla/dom/RootedDictionary.h"
      27             : #include "mozilla/SegmentedVector.h"
      28             : #include "mozilla/ErrorResult.h"
      29             : #include "mozilla/Likely.h"
      30             : #include "mozilla/MemoryReporting.h"
      31             : #include "nsAutoPtr.h"
      32             : #include "nsIDocument.h"
      33             : #include "nsIGlobalObject.h"
      34             : #include "nsIXPConnect.h"
      35             : #include "nsJSUtils.h"
      36             : #include "nsISupportsImpl.h"
      37             : #include "xpcObjectHelper.h"
      38             : #include "xpcpublic.h"
      39             : #include "nsIVariant.h"
      40             : #include "mozilla/dom/FakeString.h"
      41             : 
      42             : #include "nsWrapperCacheInlines.h"
      43             : 
      44             : class nsGenericHTMLElement;
      45             : class nsIJSID;
      46             : 
      47             : namespace mozilla {
      48             : 
      49             : enum UseCounter : int16_t;
      50             : 
      51             : namespace dom {
      52             : class CustomElementReactionsStack;
      53             : class MessageManagerGlobal;
      54             : template<typename KeyType, typename ValueType> class Record;
      55             : 
      56             : nsresult
      57             : UnwrapArgImpl(JSContext* cx, JS::Handle<JSObject*> src, const nsIID& iid,
      58             :               void** ppArg);
      59             : 
      60             : nsresult
      61             : UnwrapWindowProxyImpl(JSContext* cx, JS::Handle<JSObject*> src,
      62             :                       nsPIDOMWindowOuter** ppArg);
      63             : 
      64             : /** Convert a jsval to an XPCOM pointer. Caller must not assume that src will
      65             :     keep the XPCOM pointer rooted. */
      66             : template <class Interface>
      67             : inline nsresult
      68           0 : UnwrapArg(JSContext* cx, JS::Handle<JSObject*> src, Interface** ppArg)
      69             : {
      70             :   return UnwrapArgImpl(cx, src, NS_GET_TEMPLATE_IID(Interface),
      71           0 :                        reinterpret_cast<void**>(ppArg));
      72             : }
      73             : 
      74             : template <>
      75             : inline nsresult
      76             : UnwrapArg<nsPIDOMWindowOuter>(JSContext* cx, JS::Handle<JSObject*> src,
      77             :                               nsPIDOMWindowOuter** ppArg)
      78             : {
      79             :   return UnwrapWindowProxyImpl(cx, src, ppArg);
      80             : }
      81             : 
      82             : bool
      83             : ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
      84             :                  bool aSecurityError, const char* aInterfaceName);
      85             : 
      86             : bool
      87             : ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
      88             :                  bool aSecurityError, prototypes::ID aProtoId);
      89             : 
      90             : // Returns true if the JSClass is used for DOM objects.
      91             : inline bool
      92             : IsDOMClass(const JSClass* clasp)
      93             : {
      94           0 :   return clasp->flags & JSCLASS_IS_DOMJSCLASS;
      95             : }
      96             : 
      97             : inline bool
      98             : IsDOMClass(const js::Class* clasp)
      99             : {
     100           0 :   return IsDOMClass(Jsvalify(clasp));
     101             : }
     102             : 
     103             : // Return true if the JSClass is used for non-proxy DOM objects.
     104             : inline bool
     105             : IsNonProxyDOMClass(const js::Class* clasp)
     106             : {
     107             :   return IsDOMClass(clasp) && !clasp->isProxy();
     108             : }
     109             : 
     110             : inline bool
     111             : IsNonProxyDOMClass(const JSClass* clasp)
     112             : {
     113             :   return IsNonProxyDOMClass(js::Valueify(clasp));
     114             : }
     115             : 
     116             : // Returns true if the JSClass is used for DOM interface and interface
     117             : // prototype objects.
     118             : inline bool
     119             : IsDOMIfaceAndProtoClass(const JSClass* clasp)
     120             : {
     121           0 :   return clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS;
     122             : }
     123             : 
     124             : inline bool
     125             : IsDOMIfaceAndProtoClass(const js::Class* clasp)
     126             : {
     127           0 :   return IsDOMIfaceAndProtoClass(Jsvalify(clasp));
     128             : }
     129             : 
     130             : static_assert(DOM_OBJECT_SLOT == 0,
     131             :               "DOM_OBJECT_SLOT doesn't match the proxy private slot.  "
     132             :               "Expect bad things");
     133             : template <class T>
     134             : inline T*
     135           0 : UnwrapDOMObject(JSObject* obj)
     136             : {
     137           0 :   MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
     138             :              "Don't pass non-DOM objects to this function");
     139             : 
     140           0 :   JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
     141           2 :   return static_cast<T*>(val.toPrivate());
     142             : }
     143             : 
     144             : template <class T>
     145             : inline T*
     146           0 : UnwrapPossiblyNotInitializedDOMObject(JSObject* obj)
     147             : {
     148             :   // This is used by the OjectMoved JSClass hook which can be called before
     149             :   // JS_NewObject has returned and so before we have a chance to set
     150             :   // DOM_OBJECT_SLOT to anything useful.
     151             : 
     152           0 :   MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
     153             :              "Don't pass non-DOM objects to this function");
     154             : 
     155           0 :   JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
     156           0 :   if (val.isUndefined()) {
     157             :     return nullptr;
     158             :   }
     159           0 :   return static_cast<T*>(val.toPrivate());
     160             : }
     161             : 
     162             : inline const DOMJSClass*
     163           0 : GetDOMClass(const js::Class* clasp)
     164             : {
     165           0 :   return IsDOMClass(clasp) ? DOMJSClass::FromJSClass(clasp) : nullptr;
     166             : }
     167             : 
     168             : inline const DOMJSClass*
     169           0 : GetDOMClass(JSObject* obj)
     170             : {
     171           0 :   return GetDOMClass(js::GetObjectClass(obj));
     172             : }
     173             : 
     174             : inline nsISupports*
     175           0 : UnwrapDOMObjectToISupports(JSObject* aObject)
     176             : {
     177           0 :   const DOMJSClass* clasp = GetDOMClass(aObject);
     178           0 :   if (!clasp || !clasp->mDOMObjectIsISupports) {
     179             :     return nullptr;
     180             :   }
     181             : 
     182           0 :   return UnwrapPossiblyNotInitializedDOMObject<nsISupports>(aObject);
     183             : }
     184             : 
     185             : inline bool
     186           0 : IsDOMObject(JSObject* obj)
     187             : {
     188           0 :   return IsDOMClass(js::GetObjectClass(obj));
     189             : }
     190             : 
     191             : // There are two valid ways to use UNWRAP_OBJECT: Either obj needs to
     192             : // be a MutableHandle<JSObject*>, or value needs to be a strong-reference
     193             : // smart pointer type (OwningNonNull or RefPtr or nsCOMPtr), in which case obj
     194             : // can be anything that converts to JSObject*.
     195             : #define UNWRAP_OBJECT(Interface, obj, value)                                 \
     196             :   mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface,        \
     197             :     mozilla::dom::Interface##Binding::NativeType>(obj, value)
     198             : 
     199             : // Test whether the given object is an instance of the given interface.
     200             : #define IS_INSTANCE_OF(Interface, obj)                                  \
     201             :   mozilla::dom::IsInstanceOf<mozilla::dom::prototypes::id::Interface,   \
     202             :                              mozilla::dom::Interface##Binding::NativeType>(obj)
     203             : 
     204             : // Unwrap the given non-wrapper object.  This can be used with any obj that
     205             : // converts to JSObject*; as long as that JSObject* is live the return value
     206             : // will be valid.
     207             : #define UNWRAP_NON_WRAPPER_OBJECT(Interface, obj, value)                        \
     208             :   mozilla::dom::UnwrapNonWrapperObject<mozilla::dom::prototypes::id::Interface, \
     209             :     mozilla::dom::Interface##Binding::NativeType>(obj, value)
     210             : 
     211             : // Some callers don't want to set an exception when unwrapping fails
     212             : // (for example, overload resolution uses unwrapping to tell what sort
     213             : // of thing it's looking at).
     214             : // U must be something that a T* can be assigned to (e.g. T* or an RefPtr<T>).
     215             : //
     216             : // The obj argument will be mutated to point to CheckedUnwrap of itself if the
     217             : // passed-in value is not a DOM object and CheckedUnwrap succeeds.
     218             : //
     219             : // If mayBeWrapper is true, there are three valid ways to invoke
     220             : // UnwrapObjectInternal: Either obj needs to be a class wrapping a
     221             : // MutableHandle<JSObject*>, with an assignment operator that sets the handle to
     222             : // the given object, or U needs to be a strong-reference smart pointer type
     223             : // (OwningNonNull or RefPtr or nsCOMPtr), or the value being stored in "value"
     224             : // must not escape past being tested for falsiness immediately after the
     225             : // UnwrapObjectInternal call.
     226             : //
     227             : // If mayBeWrapper is false, obj can just be a JSObject*, and U anything that a
     228             : // T* can be assigned to.
     229             : namespace binding_detail {
     230             : template <class T, bool mayBeWrapper, typename U, typename V>
     231             : MOZ_ALWAYS_INLINE nsresult
     232           0 : UnwrapObjectInternal(V& obj, U& value, prototypes::ID protoID,
     233             :                      uint32_t protoDepth)
     234             : {
     235             :   /* First check to see whether we have a DOM object */
     236           0 :   const DOMJSClass* domClass = GetDOMClass(obj);
     237           2 :   if (domClass) {
     238             :     /* This object is a DOM object.  Double-check that it is safely
     239             :        castable to T by checking whether it claims to inherit from the
     240             :        class identified by protoID. */
     241           0 :     if (domClass->mInterfaceChain[protoDepth] == protoID) {
     242           2 :       value = UnwrapDOMObject<T>(obj);
     243           2 :       return NS_OK;
     244             :     }
     245             :   }
     246             : 
     247             :   /* Maybe we have a security wrapper or outer window? */
     248           0 :   if (!mayBeWrapper || !js::IsWrapper(obj)) {
     249             :     /* Not a DOM object, not a wrapper, just bail */
     250             :     return NS_ERROR_XPC_BAD_CONVERT_JS;
     251             :   }
     252             : 
     253             :   JSObject* unwrappedObj =
     254           0 :     js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
     255           2 :   if (!unwrappedObj) {
     256             :     return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
     257             :   }
     258           0 :   MOZ_ASSERT(!js::IsWrapper(unwrappedObj));
     259             :   // Recursive call is OK, because now we're using false for mayBeWrapper and
     260             :   // we never reach this code if that boolean is false, so can't keep calling
     261             :   // ourselves.
     262             :   //
     263             :   // Unwrap into a temporary pointer, because in general unwrapping into
     264             :   // something of type U might trigger GC (e.g. release the value currently
     265             :   // stored in there, with arbitrary consequences) and invalidate the
     266             :   // "unwrappedObj" pointer.
     267           0 :   T* tempValue = nullptr;
     268           2 :   nsresult rv = UnwrapObjectInternal<T, false>(unwrappedObj, tempValue,
     269           2 :                                                protoID, protoDepth);
     270           2 :   if (NS_SUCCEEDED(rv)) {
     271             :     // It's very important to not update "obj" with the "unwrappedObj" value
     272             :     // until we know the unwrap has succeeded.  Otherwise, in a situation in
     273             :     // which we have an overload of object and primitive we could end up
     274             :     // converting to the primitive from the unwrappedObj, whereas we want to do
     275             :     // it from the original object.
     276           0 :     obj = unwrappedObj;
     277             :     // And now assign to "value"; at this point we don't care if a GC happens
     278             :     // and invalidates unwrappedObj.
     279           0 :     value = tempValue;
     280           2 :     return NS_OK;
     281             :   }
     282             : 
     283             :   /* It's the wrong sort of DOM object */
     284             :   return NS_ERROR_XPC_BAD_CONVERT_JS;
     285             : }
     286             : 
     287             : struct MutableObjectHandleWrapper {
     288             :   explicit MutableObjectHandleWrapper(JS::MutableHandle<JSObject*> aHandle)
     289           0 :     : mHandle(aHandle)
     290             :   {
     291             :   }
     292             : 
     293           0 :   void operator=(JSObject* aObject)
     294             :   {
     295           0 :     MOZ_ASSERT(aObject);
     296           0 :     mHandle.set(aObject);
     297           0 :   }
     298             : 
     299             :   operator JSObject*() const
     300             :   {
     301           0 :     return mHandle;
     302             :   }
     303             : 
     304             : private:
     305             :   JS::MutableHandle<JSObject*> mHandle;
     306             : };
     307             : 
     308             : struct MutableValueHandleWrapper {
     309             :   explicit MutableValueHandleWrapper(JS::MutableHandle<JS::Value> aHandle)
     310             :     : mHandle(aHandle)
     311             :   {
     312             :   }
     313             : 
     314             :   void operator=(JSObject* aObject)
     315             :   {
     316             :     MOZ_ASSERT(aObject);
     317             :     mHandle.setObject(*aObject);
     318             :   }
     319             : 
     320             :   operator JSObject*() const
     321             :   {
     322             :     return &mHandle.toObject();
     323             :   }
     324             : 
     325             : private:
     326             :   JS::MutableHandle<JS::Value> mHandle;
     327             : };
     328             : 
     329             : } // namespace binding_detail
     330             : 
     331             : // UnwrapObject overloads that ensure we have a MutableHandle to keep it alive.
     332             : template<prototypes::ID PrototypeID, class T, typename U>
     333             : MOZ_ALWAYS_INLINE nsresult
     334           0 : UnwrapObject(JS::MutableHandle<JSObject*> obj, U& value)
     335             : {
     336           0 :   binding_detail::MutableObjectHandleWrapper wrapper(obj);
     337             :   return binding_detail::UnwrapObjectInternal<T, true>(
     338           0 :     wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
     339             : }
     340             : 
     341             : template<prototypes::ID PrototypeID, class T, typename U>
     342             : MOZ_ALWAYS_INLINE nsresult
     343             : UnwrapObject(JS::MutableHandle<JS::Value> obj, U& value)
     344             : {
     345             :   MOZ_ASSERT(obj.isObject());
     346             :   binding_detail::MutableValueHandleWrapper wrapper(obj);
     347             :   return binding_detail::UnwrapObjectInternal<T, true>(
     348             :     wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
     349             : }
     350             : 
     351             : // UnwrapObject overloads that ensure we have a strong ref to keep it alive.
     352             : template<prototypes::ID PrototypeID, class T, typename U>
     353             : MOZ_ALWAYS_INLINE nsresult
     354           0 : UnwrapObject(JSObject* obj, RefPtr<U>& value)
     355             : {
     356             :   return binding_detail::UnwrapObjectInternal<T, true>(
     357           0 :     obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
     358             : }
     359             : 
     360             : template<prototypes::ID PrototypeID, class T, typename U>
     361             : MOZ_ALWAYS_INLINE nsresult
     362             : UnwrapObject(JSObject* obj, nsCOMPtr<U>& value)
     363             : {
     364             :   return binding_detail::UnwrapObjectInternal<T, true>(
     365             :     obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
     366             : }
     367             : 
     368             : template<prototypes::ID PrototypeID, class T, typename U>
     369             : MOZ_ALWAYS_INLINE nsresult
     370             : UnwrapObject(JSObject* obj, OwningNonNull<U>& value)
     371             : {
     372             :   return binding_detail::UnwrapObjectInternal<T, true>(
     373             :     obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
     374             : }
     375             : 
     376             : // An UnwrapObject overload that just calls one of the JSObject* ones.
     377             : template<prototypes::ID PrototypeID, class T, typename U>
     378             : MOZ_ALWAYS_INLINE nsresult
     379             : UnwrapObject(JS::Handle<JS::Value> obj, U& value)
     380             : {
     381             :   MOZ_ASSERT(obj.isObject());
     382             :   return UnwrapObject<PrototypeID, T>(&obj.toObject(), value);
     383             : }
     384             : 
     385             : template<prototypes::ID PrototypeID, class T>
     386             : MOZ_ALWAYS_INLINE bool
     387             : IsInstanceOf(JSObject* obj)
     388             : {
     389             :   void* ignored;
     390             :   nsresult unwrapped = binding_detail::UnwrapObjectInternal<T, true>(
     391             :     obj, ignored, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
     392             :   return NS_SUCCEEDED(unwrapped);
     393             : }
     394             : 
     395             : template<prototypes::ID PrototypeID, class T, typename U>
     396             : MOZ_ALWAYS_INLINE nsresult
     397             : UnwrapNonWrapperObject(JSObject* obj, U& value)
     398             : {
     399             :   MOZ_ASSERT(!js::IsWrapper(obj));
     400             :   return binding_detail::UnwrapObjectInternal<T, false>(
     401             :     obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
     402             : }
     403             : 
     404             : MOZ_ALWAYS_INLINE bool
     405             : IsConvertibleToDictionary(JS::Handle<JS::Value> val)
     406             : {
     407             :   return val.isNullOrUndefined() || val.isObject();
     408             : }
     409             : 
     410             : // The items in the protoAndIfaceCache are indexed by the prototypes::id::ID,
     411             : // constructors::id::ID and namedpropertiesobjects::id::ID enums, in that order.
     412             : // The end of the prototype objects should be the start of the interface
     413             : // objects, and the end of the interface objects should be the start of the
     414             : // named properties objects.
     415             : static_assert((size_t)constructors::id::_ID_Start ==
     416             :               (size_t)prototypes::id::_ID_Count &&
     417             :               (size_t)namedpropertiesobjects::id::_ID_Start ==
     418             :               (size_t)constructors::id::_ID_Count,
     419             :               "Overlapping or discontiguous indexes.");
     420             : const size_t kProtoAndIfaceCacheCount = namedpropertiesobjects::id::_ID_Count;
     421             : 
     422             : class ProtoAndIfaceCache
     423             : {
     424             :   // The caching strategy we use depends on what sort of global we're dealing
     425             :   // with.  For a window-like global, we want everything to be as fast as
     426             :   // possible, so we use a flat array, indexed by prototype/constructor ID.
     427             :   // For everything else (e.g. globals for JSMs), space is more important than
     428             :   // speed, so we use a two-level lookup table.
     429             : 
     430           0 :   class ArrayCache : public Array<JS::Heap<JSObject*>, kProtoAndIfaceCacheCount>
     431             :   {
     432             :   public:
     433        2254 :     bool HasEntryInSlot(size_t i) {
     434        4508 :       return (*this)[i];
     435             :     }
     436             : 
     437             :     JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
     438             :       return (*this)[i];
     439             :     }
     440             : 
     441             :     JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
     442        2262 :       return (*this)[i];
     443             :     }
     444             : 
     445             :     void Trace(JSTracer* aTracer) {
     446             :       for (size_t i = 0; i < ArrayLength(*this); ++i) {
     447             :         JS::TraceEdge(aTracer, &(*this)[i], "protoAndIfaceCache[i]");
     448             :       }
     449             :     }
     450             : 
     451             :     size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
     452             :       return aMallocSizeOf(this);
     453             :     }
     454             :   };
     455             : 
     456             :   class PageTableCache
     457             :   {
     458             :   public:
     459             :     PageTableCache() {
     460             :       memset(mPages.begin(), 0, sizeof(mPages));
     461             :     }
     462             : 
     463           0 :     ~PageTableCache() {
     464           0 :       for (size_t i = 0; i < ArrayLength(mPages); ++i) {
     465           0 :         delete mPages[i];
     466             :       }
     467           0 :     }
     468             : 
     469       16726 :     bool HasEntryInSlot(size_t i) {
     470       16726 :       MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
     471       16726 :       size_t pageIndex = i / kPageSize;
     472       16726 :       size_t leafIndex = i % kPageSize;
     473       16726 :       Page* p = mPages[pageIndex];
     474       16726 :       if (!p) {
     475             :         return false;
     476             :       }
     477       32792 :       return (*p)[leafIndex];
     478             :     }
     479             : 
     480             :     JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
     481             :       MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
     482             :       size_t pageIndex = i / kPageSize;
     483             :       size_t leafIndex = i % kPageSize;
     484             :       Page* p = mPages[pageIndex];
     485             :       if (!p) {
     486             :         p = new Page;
     487             :         mPages[pageIndex] = p;
     488             :       }
     489             :       return (*p)[leafIndex];
     490             :     }
     491             : 
     492       17148 :     JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
     493       17148 :       MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
     494       17148 :       size_t pageIndex = i / kPageSize;
     495       17148 :       size_t leafIndex = i % kPageSize;
     496       17148 :       Page* p = mPages[pageIndex];
     497       17148 :       MOZ_ASSERT(p);
     498       17148 :       return (*p)[leafIndex];
     499             :     }
     500             : 
     501             :     void Trace(JSTracer* trc) {
     502             :       for (size_t i = 0; i < ArrayLength(mPages); ++i) {
     503             :         Page* p = mPages[i];
     504             :         if (p) {
     505             :           for (size_t j = 0; j < ArrayLength(*p); ++j) {
     506             :             JS::TraceEdge(trc, &(*p)[j], "protoAndIfaceCache[i]");
     507             :           }
     508             :         }
     509             :       }
     510             :     }
     511             : 
     512             :     size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
     513             :       size_t n = aMallocSizeOf(this);
     514             :       for (size_t i = 0; i < ArrayLength(mPages); ++i) {
     515             :         n += aMallocSizeOf(mPages[i]);
     516             :       }
     517             :       return n;
     518             :     }
     519             : 
     520             :   private:
     521             :     static const size_t kPageSize = 16;
     522             :     typedef Array<JS::Heap<JSObject*>, kPageSize> Page;
     523             :     static const size_t kNPages = kProtoAndIfaceCacheCount / kPageSize +
     524             :       size_t(bool(kProtoAndIfaceCacheCount % kPageSize));
     525             :     Array<Page*, kNPages> mPages;
     526             :   };
     527             : 
     528             : public:
     529             :   enum Kind {
     530             :     WindowLike,
     531             :     NonWindowLike
     532             :   };
     533             : 
     534             :   explicit ProtoAndIfaceCache(Kind aKind) : mKind(aKind) {
     535             :     MOZ_COUNT_CTOR(ProtoAndIfaceCache);
     536             :     if (aKind == WindowLike) {
     537             :       mArrayCache = new ArrayCache();
     538             :     } else {
     539             :       mPageTableCache = new PageTableCache();
     540             :     }
     541             :   }
     542             : 
     543           0 :   ~ProtoAndIfaceCache() {
     544           0 :     if (mKind == WindowLike) {
     545           0 :       delete mArrayCache;
     546             :     } else {
     547           0 :       delete mPageTableCache;
     548             :     }
     549           0 :     MOZ_COUNT_DTOR(ProtoAndIfaceCache);
     550           0 :   }
     551             : 
     552             : #define FORWARD_OPERATION(opName, args)              \
     553             :   do {                                               \
     554             :     if (mKind == WindowLike) {                       \
     555             :       return mArrayCache->opName args;               \
     556             :     } else {                                         \
     557             :       return mPageTableCache->opName args;           \
     558             :     }                                                \
     559             :   } while(0)
     560             : 
     561             :   // Return whether slot i contains an object.  This doesn't return the object
     562             :   // itself because in practice consumers just want to know whether it's there
     563             :   // or not, and that doesn't require barriering, which returning the object
     564             :   // pointer does.
     565       18980 :   bool HasEntryInSlot(size_t i) {
     566       18980 :     FORWARD_OPERATION(HasEntryInSlot, (i));
     567             :   }
     568             : 
     569             :   // Return a reference to slot i, creating it if necessary.  There
     570             :   // may not be an object in the returned slot.
     571             :   JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
     572             :     FORWARD_OPERATION(EntrySlotOrCreate, (i));
     573             :   }
     574             : 
     575             :   // Return a reference to slot i, which is guaranteed to already
     576             :   // exist.  There may not be an object in the slot, if prototype and
     577             :   // constructor initialization for one of our bindings failed.
     578       19410 :   JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
     579       21672 :     FORWARD_OPERATION(EntrySlotMustExist, (i));
     580             :   }
     581             : 
     582             :   void Trace(JSTracer *aTracer) {
     583             :     FORWARD_OPERATION(Trace, (aTracer));
     584             :   }
     585             : 
     586             :   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
     587             :     size_t n = aMallocSizeOf(this);
     588             :     n += (mKind == WindowLike
     589             :           ? mArrayCache->SizeOfIncludingThis(aMallocSizeOf)
     590             :           : mPageTableCache->SizeOfIncludingThis(aMallocSizeOf));
     591             :     return n;
     592             :   }
     593             : #undef FORWARD_OPERATION
     594             : 
     595             : private:
     596             :   union {
     597             :     ArrayCache *mArrayCache;
     598             :     PageTableCache *mPageTableCache;
     599             :   };
     600             :   Kind mKind;
     601             : };
     602             : 
     603             : inline void
     604             : AllocateProtoAndIfaceCache(JSObject* obj, ProtoAndIfaceCache::Kind aKind)
     605             : {
     606             :   MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
     607             :   MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
     608             : 
     609             :   ProtoAndIfaceCache* protoAndIfaceCache = new ProtoAndIfaceCache(aKind);
     610             : 
     611             :   js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
     612             :                       JS::PrivateValue(protoAndIfaceCache));
     613             : }
     614             : 
     615             : #ifdef DEBUG
     616             : struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JS::CallbackTracer
     617             : {
     618             :   bool ok;
     619             : 
     620             :   explicit VerifyTraceProtoAndIfaceCacheCalledTracer(JSContext* cx)
     621             :     : JS::CallbackTracer(cx), ok(false)
     622             :   {}
     623             : 
     624             :   void onChild(const JS::GCCellPtr&) override {
     625             :     // We don't do anything here, we only want to verify that
     626             :     // TraceProtoAndIfaceCache was called.
     627             :   }
     628             : 
     629             :   TracerKind getTracerKind() const override { return TracerKind::VerifyTraceProtoAndIface; }
     630             : };
     631             : #endif
     632             : 
     633             : inline void
     634             : TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
     635             : {
     636             :   MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
     637             : 
     638             : #ifdef DEBUG
     639             :   if (trc->isCallbackTracer() &&
     640             :       (trc->asCallbackTracer()->getTracerKind() ==
     641             :        JS::CallbackTracer::TracerKind::VerifyTraceProtoAndIface)) {
     642             :     // We don't do anything here, we only want to verify that
     643             :     // TraceProtoAndIfaceCache was called.
     644             :     static_cast<VerifyTraceProtoAndIfaceCacheCalledTracer*>(trc)->ok = true;
     645             :     return;
     646             :   }
     647             : #endif
     648             : 
     649             :   if (!DOMGlobalHasProtoAndIFaceCache(obj))
     650             :     return;
     651             :   ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
     652             :   protoAndIfaceCache->Trace(trc);
     653             : }
     654             : 
     655             : inline void
     656           0 : DestroyProtoAndIfaceCache(JSObject* obj)
     657             : {
     658           0 :   MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
     659             : 
     660           0 :   if (!DOMGlobalHasProtoAndIFaceCache(obj)) {
     661             :     return;
     662             :   }
     663             : 
     664           0 :   ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
     665             : 
     666           0 :   delete protoAndIfaceCache;
     667             : }
     668             : 
     669             : /**
     670             :  * Add constants to an object.
     671             :  */
     672             : bool
     673             : DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
     674             :                 const ConstantSpec* cs);
     675             : 
     676             : struct JSNativeHolder
     677             : {
     678             :   JSNative mNative;
     679             :   const NativePropertyHooks* mPropertyHooks;
     680             : };
     681             : 
     682             : struct NamedConstructor
     683             : {
     684             :   const char* mName;
     685             :   const JSNativeHolder mHolder;
     686             :   unsigned mNargs;
     687             : };
     688             : 
     689             : /*
     690             :  * Create a DOM interface object (if constructorClass is non-null) and/or a
     691             :  * DOM interface prototype object (if protoClass is non-null).
     692             :  *
     693             :  * global is used as the parent of the interface object and the interface
     694             :  *        prototype object
     695             :  * protoProto is the prototype to use for the interface prototype object.
     696             :  * interfaceProto is the prototype to use for the interface object.  This can be
     697             :  *                null if both constructorClass and constructor are null (as in,
     698             :  *                if we're not creating an interface object at all).
     699             :  * protoClass is the JSClass to use for the interface prototype object.
     700             :  *            This is null if we should not create an interface prototype
     701             :  *            object.
     702             :  * protoCache a pointer to a JSObject pointer where we should cache the
     703             :  *            interface prototype object. This must be null if protoClass is and
     704             :  *            vice versa.
     705             :  * toStringTag if not null, a string to define as @@toStringTag on the prototype.
     706             :  *             Must be null if protoClass is.
     707             :  * constructorClass is the JSClass to use for the interface object.
     708             :  *                  This is null if we should not create an interface object or
     709             :  *                  if it should be a function object.
     710             :  * constructor holds the JSNative to back the interface object which should be a
     711             :  *             Function, unless constructorClass is non-null in which case it is
     712             :  *             ignored. If this is null and constructorClass is also null then
     713             :  *             we should not create an interface object at all.
     714             :  * ctorNargs is the length of the constructor function; 0 if no constructor
     715             :  * constructorCache a pointer to a JSObject pointer where we should cache the
     716             :  *                  interface object. This must be null if both constructorClass
     717             :  *                  and constructor are null, and non-null otherwise.
     718             :  * properties contains the methods, attributes and constants to be defined on
     719             :  *            objects in any compartment.
     720             :  * chromeProperties contains the methods, attributes and constants to be defined
     721             :  *                  on objects in chrome compartments. This must be null if the
     722             :  *                  interface doesn't have any ChromeOnly properties or if the
     723             :  *                  object is being created in non-chrome compartment.
     724             :  * defineOnGlobal controls whether properties should be defined on the given
     725             :  *                global for the interface object (if any) and named
     726             :  *                constructors (if any) for this interface.  This can be
     727             :  *                false in situations where we want the properties to only
     728             :  *                appear on privileged Xrays but not on the unprivileged
     729             :  *                underlying global.
     730             :  * unscopableNames if not null it points to a null-terminated list of const
     731             :  *                 char* names of the unscopable properties for this interface.
     732             :  * isGlobal if true, we're creating interface objects for a [Global] or
     733             :  *        [PrimaryGlobal] interface, and hence shouldn't define properties on
     734             :  *        the prototype object.
     735             :  *
     736             :  * At least one of protoClass, constructorClass or constructor should be
     737             :  * non-null. If constructorClass or constructor are non-null, the resulting
     738             :  * interface object will be defined on the given global with property name
     739             :  * |name|, which must also be non-null.
     740             :  */
     741             : void
     742             : CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
     743             :                        JS::Handle<JSObject*> protoProto,
     744             :                        const js::Class* protoClass, JS::Heap<JSObject*>* protoCache,
     745             :                        const char* toStringTag,
     746             :                        JS::Handle<JSObject*> interfaceProto,
     747             :                        const js::Class* constructorClass,
     748             :                        unsigned ctorNargs, const NamedConstructor* namedConstructors,
     749             :                        JS::Heap<JSObject*>* constructorCache,
     750             :                        const NativeProperties* regularProperties,
     751             :                        const NativeProperties* chromeOnlyProperties,
     752             :                        const char* name, bool defineOnGlobal,
     753             :                        const char* const* unscopableNames,
     754             :                        bool isGlobal);
     755             : 
     756             : /**
     757             :  * Define the properties (regular and chrome-only) on obj.
     758             :  *
     759             :  * obj the object to instal the properties on. This should be the interface
     760             :  *     prototype object for regular interfaces and the instance object for
     761             :  *     interfaces marked with Global.
     762             :  * properties contains the methods, attributes and constants to be defined on
     763             :  *            objects in any compartment.
     764             :  * chromeProperties contains the methods, attributes and constants to be defined
     765             :  *                  on objects in chrome compartments. This must be null if the
     766             :  *                  interface doesn't have any ChromeOnly properties or if the
     767             :  *                  object is being created in non-chrome compartment.
     768             :  */
     769             : bool
     770             : DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
     771             :                  const NativeProperties* properties,
     772             :                  const NativeProperties* chromeOnlyProperties);
     773             : 
     774             : /*
     775             :  * Define the unforgeable methods on an object.
     776             :  */
     777             : bool
     778             : DefineUnforgeableMethods(JSContext* cx, JS::Handle<JSObject*> obj,
     779             :                          const Prefable<const JSFunctionSpec>* props);
     780             : 
     781             : /*
     782             :  * Define the unforgeable attributes on an object.
     783             :  */
     784             : bool
     785             : DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
     786             :                             const Prefable<const JSPropertySpec>* props);
     787             : 
     788             : #define HAS_MEMBER_TYPEDEFS                                               \
     789             : private:                                                                  \
     790             :   typedef char yes[1];                                                    \
     791             :   typedef char no[2]
     792             : 
     793             : #ifdef _MSC_VER
     794             : #define HAS_MEMBER_CHECK(_name)                                           \
     795             :   template<typename V> static yes& Check##_name(char (*)[(&V::_name == 0) + 1])
     796             : #else
     797             : #define HAS_MEMBER_CHECK(_name)                                           \
     798             :   template<typename V> static yes& Check##_name(char (*)[sizeof(&V::_name) + 1])
     799             : #endif
     800             : 
     801             : #define HAS_MEMBER(_memberName, _valueName)                               \
     802             : private:                                                                  \
     803             :   HAS_MEMBER_CHECK(_memberName);                                          \
     804             :   template<typename V> static no& Check##_memberName(...);                \
     805             :                                                                           \
     806             : public:                                                                   \
     807             :   static bool const _valueName =                                          \
     808             :     sizeof(Check##_memberName<T>(nullptr)) == sizeof(yes)
     809             : 
     810             : template<class T>
     811             : struct NativeHasMember
     812             : {
     813             :   HAS_MEMBER_TYPEDEFS;
     814             : 
     815             :   HAS_MEMBER(GetParentObject, GetParentObject);
     816             :   HAS_MEMBER(WrapObject, WrapObject);
     817             : };
     818             : 
     819             : template<class T>
     820             : struct IsSmartPtr
     821             : {
     822             :   HAS_MEMBER_TYPEDEFS;
     823             : 
     824             :   HAS_MEMBER(get, value);
     825             : };
     826             : 
     827             : template<class T>
     828             : struct IsRefcounted
     829             : {
     830             :   HAS_MEMBER_TYPEDEFS;
     831             : 
     832             :   HAS_MEMBER(AddRef, HasAddref);
     833             :   HAS_MEMBER(Release, HasRelease);
     834             : 
     835             : public:
     836             :   static bool const value = HasAddref && HasRelease;
     837             : 
     838             : private:
     839             :   // This struct only works if T is fully declared (not just forward declared).
     840             :   // The IsBaseOf check will ensure that, we don't really need it for any other
     841             :   // reason (the static assert will of course always be true).
     842             :   static_assert(!IsBaseOf<nsISupports, T>::value || IsRefcounted::value,
     843             :                 "Classes derived from nsISupports are refcounted!");
     844             : 
     845             : };
     846             : 
     847             : #undef HAS_MEMBER
     848             : #undef HAS_MEMBER_CHECK
     849             : #undef HAS_MEMBER_TYPEDEFS
     850             : 
     851             : #ifdef DEBUG
     852             : template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
     853             : struct
     854             : CheckWrapperCacheCast
     855             : {
     856             :   static bool Check()
     857             :   {
     858             :     return reinterpret_cast<uintptr_t>(
     859             :       static_cast<nsWrapperCache*>(
     860             :         reinterpret_cast<T*>(1))) == 1;
     861             :   }
     862             : };
     863             : template <class T>
     864             : struct
     865             : CheckWrapperCacheCast<T, true>
     866             : {
     867             :   static bool Check()
     868             :   {
     869             :     return true;
     870             :   }
     871             : };
     872             : #endif
     873             : 
     874             : inline bool
     875           0 : TryToOuterize(JS::MutableHandle<JS::Value> rval)
     876             : {
     877           0 :   if (js::IsWindow(&rval.toObject())) {
     878           0 :     JSObject* obj = js::ToWindowProxyIfWindow(&rval.toObject());
     879           0 :     MOZ_ASSERT(obj);
     880           0 :     rval.set(JS::ObjectValue(*obj));
     881             :   }
     882             : 
     883           0 :   return true;
     884             : }
     885             : 
     886             : // Make sure to wrap the given string value into the right compartment, as
     887             : // needed.
     888             : MOZ_ALWAYS_INLINE
     889             : bool
     890             : MaybeWrapStringValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
     891             : {
     892             :   MOZ_ASSERT(rval.isString());
     893             :   JSString* str = rval.toString();
     894             :   if (JS::GetStringZone(str) != js::GetContextZone(cx)) {
     895             :     return JS_WrapValue(cx, rval);
     896             :   }
     897             :   return true;
     898             : }
     899             : 
     900             : // Make sure to wrap the given object value into the right compartment as
     901             : // needed.  This will work correctly, but possibly slowly, on all objects.
     902             : MOZ_ALWAYS_INLINE
     903             : bool
     904           0 : MaybeWrapObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
     905             : {
     906           0 :   MOZ_ASSERT(rval.isObject());
     907             : 
     908             :   // Cross-compartment always requires wrapping.
     909           0 :   JSObject* obj = &rval.toObject();
     910           0 :   if (js::GetObjectCompartment(obj) != js::GetContextCompartment(cx)) {
     911           0 :     return JS_WrapValue(cx, rval);
     912             :   }
     913             : 
     914             :   // We're same-compartment, but even then we might need to wrap
     915             :   // objects specially.  Check for that.
     916           0 :   if (IsDOMObject(obj)) {
     917           0 :     return TryToOuterize(rval);
     918             :   }
     919             : 
     920             :   // It's not a WebIDL object, so it's OK to just leave it as-is: only WebIDL
     921             :   // objects (specifically only windows) require outerization.
     922             :   return true;
     923             : }
     924             : 
     925             : // Like MaybeWrapObjectValue, but also allows null
     926             : MOZ_ALWAYS_INLINE
     927             : bool
     928             : MaybeWrapObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
     929             : {
     930             :   MOZ_ASSERT(rval.isObjectOrNull());
     931             :   if (rval.isNull()) {
     932             :     return true;
     933             :   }
     934             :   return MaybeWrapObjectValue(cx, rval);
     935             : }
     936             : 
     937             : // Wrapping for objects that are known to not be DOM or XPConnect objects
     938             : MOZ_ALWAYS_INLINE
     939             : bool
     940           0 : MaybeWrapNonDOMObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
     941             : {
     942           0 :   MOZ_ASSERT(rval.isObject());
     943           0 :   MOZ_ASSERT(!GetDOMClass(&rval.toObject()));
     944           0 :   MOZ_ASSERT(!(js::GetObjectClass(&rval.toObject())->flags &
     945             :                JSCLASS_PRIVATE_IS_NSISUPPORTS));
     946             : 
     947           0 :   JSObject* obj = &rval.toObject();
     948           0 :   if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) {
     949             :     return true;
     950             :   }
     951           0 :   return JS_WrapValue(cx, rval);
     952             : }
     953             : 
     954             : // Like MaybeWrapNonDOMObjectValue but allows null
     955             : MOZ_ALWAYS_INLINE
     956             : bool
     957             : MaybeWrapNonDOMObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
     958             : {
     959             :   MOZ_ASSERT(rval.isObjectOrNull());
     960             :   if (rval.isNull()) {
     961             :     return true;
     962             :   }
     963             :   return MaybeWrapNonDOMObjectValue(cx, rval);
     964             : }
     965             : 
     966             : // If rval is a gcthing and is not in the compartment of cx, wrap rval
     967             : // into the compartment of cx (typically by replacing it with an Xray or
     968             : // cross-compartment wrapper around the original object).
     969             : MOZ_ALWAYS_INLINE bool
     970             : MaybeWrapValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
     971             : {
     972             :   if (rval.isGCThing()) {
     973             :     if (rval.isString()) {
     974             :       return MaybeWrapStringValue(cx, rval);
     975             :     }
     976             :     if (rval.isObject()) {
     977             :       return MaybeWrapObjectValue(cx, rval);
     978             :     }
     979             :     MOZ_ASSERT(rval.isSymbol());
     980             :     JS_MarkCrossZoneId(cx, SYMBOL_TO_JSID(rval.toSymbol()));
     981             :   }
     982             :   return true;
     983             : }
     984             : 
     985             : namespace binding_detail {
     986             : enum GetOrCreateReflectorWrapBehavior {
     987             :   eWrapIntoContextCompartment,
     988             :   eDontWrapIntoContextCompartment
     989             : };
     990             : 
     991             : template <class T>
     992             : struct TypeNeedsOuterization
     993             : {
     994             :   // We only need to outerize Window objects, so anything inheriting from
     995             :   // nsGlobalWindow (which inherits from EventTarget itself).
     996             :   static const bool value =
     997             :     IsBaseOf<nsGlobalWindowInner, T>::value ||
     998             :     IsBaseOf<nsGlobalWindowOuter, T>::value ||
     999             :     IsSame<EventTarget, T>::value;
    1000             : };
    1001             : 
    1002             : #ifdef DEBUG
    1003             : template<typename T, bool isISupports=IsBaseOf<nsISupports, T>::value>
    1004             : struct CheckWrapperCacheTracing
    1005             : {
    1006             :   static inline void Check(T* aObject)
    1007             :   {
    1008             :   }
    1009             : };
    1010             : 
    1011             : template<typename T>
    1012             : struct CheckWrapperCacheTracing<T, true>
    1013             : {
    1014           0 :   static void Check(T* aObject)
    1015             :   {
    1016             :     // Rooting analysis thinks QueryInterface may GC, but we're dealing with
    1017             :     // a subset of QueryInterface, C++ only types here.
    1018           0 :     JS::AutoSuppressGCAnalysis nogc;
    1019             : 
    1020           0 :     nsWrapperCache* wrapperCacheFromQI = nullptr;
    1021           2 :     aObject->QueryInterface(NS_GET_IID(nsWrapperCache),
    1022             :                             reinterpret_cast<void**>(&wrapperCacheFromQI));
    1023             : 
    1024           0 :     MOZ_ASSERT(wrapperCacheFromQI,
    1025             :                "Missing nsWrapperCache from QueryInterface implementation?");
    1026             : 
    1027           0 :     if (!wrapperCacheFromQI->GetWrapperPreserveColor()) {
    1028             :       // Can't assert that we trace the wrapper, since we don't have any
    1029             :       // wrapper to trace.
    1030           0 :       return;
    1031             :     }
    1032             : 
    1033           0 :     nsISupports* ccISupports = nullptr;
    1034           2 :     aObject->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
    1035             :                             reinterpret_cast<void**>(&ccISupports));
    1036           0 :     MOZ_ASSERT(ccISupports,
    1037             :                "nsWrapperCache object which isn't cycle collectable?");
    1038             : 
    1039           0 :     nsXPCOMCycleCollectionParticipant* participant = nullptr;
    1040           2 :     CallQueryInterface(ccISupports, &participant);
    1041           2 :     MOZ_ASSERT(participant, "Can't QI to CycleCollectionParticipant?");
    1042             : 
    1043           0 :     bool wasPreservingWrapper = wrapperCacheFromQI->PreservingWrapper();
    1044           2 :     wrapperCacheFromQI->SetPreservingWrapper(true);
    1045           2 :     wrapperCacheFromQI->CheckCCWrapperTraversal(ccISupports, participant);
    1046           2 :     wrapperCacheFromQI->SetPreservingWrapper(wasPreservingWrapper);
    1047             :   }
    1048             : };
    1049             : 
    1050             : void
    1051             : AssertReflectorHasGivenProto(JSContext* aCx, JSObject* aReflector,
    1052             :                              JS::Handle<JSObject*> aGivenProto);
    1053             : #endif // DEBUG
    1054             : 
    1055             : template <class T, GetOrCreateReflectorWrapBehavior wrapBehavior>
    1056             : MOZ_ALWAYS_INLINE bool
    1057           0 : DoGetOrCreateDOMReflector(JSContext* cx, T* value,
    1058             :                           JS::Handle<JSObject*> givenProto,
    1059             :                           JS::MutableHandle<JS::Value> rval)
    1060             : {
    1061           0 :   MOZ_ASSERT(value);
    1062           2 :   MOZ_ASSERT_IF(givenProto, js::IsObjectInContextCompartment(givenProto, cx));
    1063           2 :   JSObject* obj = value->GetWrapper();
    1064           2 :   if (obj) {
    1065             : #ifdef DEBUG
    1066           0 :     AssertReflectorHasGivenProto(cx, obj, givenProto);
    1067             :     // Have to reget obj because AssertReflectorHasGivenProto can
    1068             :     // trigger gc so the pointer may now be invalid.
    1069           0 :     obj = value->GetWrapper();
    1070             : #endif
    1071             :   } else {
    1072           0 :     obj = value->WrapObject(cx, givenProto);
    1073           2 :     if (!obj) {
    1074             :       // At this point, obj is null, so just return false.
    1075             :       // Callers seem to be testing JS_IsExceptionPending(cx) to
    1076             :       // figure out whether WrapObject() threw.
    1077             :       return false;
    1078             :     }
    1079             : 
    1080             : #ifdef DEBUG
    1081             :     if (IsBaseOf<nsWrapperCache, T>::value) {
    1082           0 :       CheckWrapperCacheTracing<T>::Check(value);
    1083             :     }
    1084             : #endif
    1085             :   }
    1086             : 
    1087             : #ifdef DEBUG
    1088           0 :   const DOMJSClass* clasp = GetDOMClass(obj);
    1089             :   // clasp can be null if the cache contained a non-DOM object.
    1090             :   if (clasp) {
    1091             :     // Some sanity asserts about our object.  Specifically:
    1092             :     // 1)  If our class claims we're nsISupports, we better be nsISupports
    1093             :     //     XXXbz ideally, we could assert that reinterpret_cast to nsISupports
    1094             :     //     does the right thing, but I don't see a way to do it.  :(
    1095             :     // 2)  If our class doesn't claim we're nsISupports we better be
    1096             :     //     reinterpret_castable to nsWrapperCache.
    1097             :     MOZ_ASSERT(clasp, "What happened here?");
    1098             :     MOZ_ASSERT_IF(clasp->mDOMObjectIsISupports, (IsBaseOf<nsISupports, T>::value));
    1099             :     MOZ_ASSERT(CheckWrapperCacheCast<T>::Check());
    1100             :   }
    1101             : #endif
    1102             : 
    1103           0 :   rval.set(JS::ObjectValue(*obj));
    1104             : 
    1105           0 :   if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) {
    1106             :     return TypeNeedsOuterization<T>::value ? TryToOuterize(rval) : true;
    1107             :   }
    1108             : 
    1109             :   if (wrapBehavior == eDontWrapIntoContextCompartment) {
    1110             :     if (TypeNeedsOuterization<T>::value) {
    1111             :       JSAutoRealm ar(cx, obj);
    1112             :       return TryToOuterize(rval);
    1113             :     }
    1114             : 
    1115             :     return true;
    1116             :   }
    1117             : 
    1118           0 :   return JS_WrapValue(cx, rval);
    1119             : }
    1120             : 
    1121             : } // namespace binding_detail
    1122             : 
    1123             : // Create a JSObject wrapping "value", if there isn't one already, and store it
    1124             : // in rval.  "value" must be a concrete class that implements a
    1125             : // GetWrapperPreserveColor() which can return its existing wrapper, if any, and
    1126             : // a WrapObject() which will try to create a wrapper. Typically, this is done by
    1127             : // having "value" inherit from nsWrapperCache.
    1128             : //
    1129             : // The value stored in rval will be ready to be exposed to whatever JS
    1130             : // is running on cx right now.  In particular, it will be in the
    1131             : // compartment of cx, and outerized as needed.
    1132             : template <class T>
    1133             : MOZ_ALWAYS_INLINE bool
    1134             : GetOrCreateDOMReflector(JSContext* cx, T* value,
    1135             :                         JS::MutableHandle<JS::Value> rval,
    1136             :                         JS::Handle<JSObject*> givenProto = nullptr)
    1137             : {
    1138             :   using namespace binding_detail;
    1139             :   return DoGetOrCreateDOMReflector<T, eWrapIntoContextCompartment>(cx, value,
    1140             :                                                                    givenProto,
    1141           0 :                                                                    rval);
    1142             : }
    1143             : 
    1144             : // Like GetOrCreateDOMReflector but doesn't wrap into the context compartment,
    1145             : // and hence does not actually require cx to be in a compartment.
    1146             : template <class T>
    1147             : MOZ_ALWAYS_INLINE bool
    1148             : GetOrCreateDOMReflectorNoWrap(JSContext* cx, T* value,
    1149             :                               JS::MutableHandle<JS::Value> rval)
    1150             : {
    1151             :   using namespace binding_detail;
    1152             :   return DoGetOrCreateDOMReflector<T, eDontWrapIntoContextCompartment>(cx,
    1153             :                                                                        value,
    1154             :                                                                        nullptr,
    1155             :                                                                        rval);
    1156             : }
    1157             : 
    1158             : // Create a JSObject wrapping "value", for cases when "value" is a
    1159             : // non-wrapper-cached object using WebIDL bindings.  "value" must implement a
    1160             : // WrapObject() method taking a JSContext and a prototype (possibly null) and
    1161             : // returning the resulting object via a MutableHandle<JSObject*> outparam.
    1162             : template <class T>
    1163             : inline bool
    1164             : WrapNewBindingNonWrapperCachedObject(JSContext* cx,
    1165             :                                      JS::Handle<JSObject*> scopeArg,
    1166             :                                      T* value,
    1167             :                                      JS::MutableHandle<JS::Value> rval,
    1168             :                                      JS::Handle<JSObject*> givenProto = nullptr)
    1169             : {
    1170             :   static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
    1171             :   MOZ_ASSERT(value);
    1172             :   // We try to wrap in the realm of the underlying object of "scope"
    1173             :   JS::Rooted<JSObject*> obj(cx);
    1174             :   {
    1175             :     // scope for the JSAutoRealm so that we restore the realm
    1176             :     // before we call JS_WrapValue.
    1177             :     Maybe<JSAutoRealm> ar;
    1178             :     // Maybe<Handle> doesn't so much work, and in any case, adding
    1179             :     // more Maybe (one for a Rooted and one for a Handle) adds more
    1180             :     // code (and branches!) than just adding a single rooted.
    1181             :     JS::Rooted<JSObject*> scope(cx, scopeArg);
    1182             :     JS::Rooted<JSObject*> proto(cx, givenProto);
    1183             :     if (js::IsWrapper(scope)) {
    1184             :       scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
    1185             :       if (!scope)
    1186             :         return false;
    1187             :       ar.emplace(cx, scope);
    1188             :       if (!JS_WrapObject(cx, &proto)) {
    1189             :         return false;
    1190             :       }
    1191             :     }
    1192             : 
    1193             :     MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
    1194             :     if (!value->WrapObject(cx, proto, &obj)) {
    1195             :       return false;
    1196             :     }
    1197             :   }
    1198             : 
    1199             :   // We can end up here in all sorts of compartments, per above.  Make
    1200             :   // sure to JS_WrapValue!
    1201             :   rval.set(JS::ObjectValue(*obj));
    1202             :   return MaybeWrapObjectValue(cx, rval);
    1203             : }
    1204             : 
    1205             : // Create a JSObject wrapping "value", for cases when "value" is a
    1206             : // non-wrapper-cached owned object using WebIDL bindings.  "value" must
    1207             : // implement a WrapObject() method taking a taking a JSContext and a prototype
    1208             : // (possibly null) and returning two pieces of information: the resulting object
    1209             : // via a MutableHandle<JSObject*> outparam and a boolean return value that is
    1210             : // true if the JSObject took ownership
    1211             : template <class T>
    1212             : inline bool
    1213             : WrapNewBindingNonWrapperCachedObject(JSContext* cx,
    1214             :                                      JS::Handle<JSObject*> scopeArg,
    1215             :                                      nsAutoPtr<T>& value,
    1216             :                                      JS::MutableHandle<JS::Value> rval,
    1217             :                                      JS::Handle<JSObject*> givenProto = nullptr)
    1218             : {
    1219             :   static_assert(!IsRefcounted<T>::value, "Only pass owned classes in here.");
    1220             :   // We do a runtime check on value, because otherwise we might in
    1221             :   // fact end up wrapping a null and invoking methods on it later.
    1222             :   if (!value) {
    1223             :     MOZ_CRASH("Don't try to wrap null objects");
    1224             :   }
    1225             :   // We try to wrap in the realm of the underlying object of "scope"
    1226             :   JS::Rooted<JSObject*> obj(cx);
    1227             :   {
    1228             :     // scope for the JSAutoRealm so that we restore the realm
    1229             :     // before we call JS_WrapValue.
    1230             :     Maybe<JSAutoRealm> ar;
    1231             :     // Maybe<Handle> doesn't so much work, and in any case, adding
    1232             :     // more Maybe (one for a Rooted and one for a Handle) adds more
    1233             :     // code (and branches!) than just adding a single rooted.
    1234             :     JS::Rooted<JSObject*> scope(cx, scopeArg);
    1235             :     JS::Rooted<JSObject*> proto(cx, givenProto);
    1236             :     if (js::IsWrapper(scope)) {
    1237             :       scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
    1238             :       if (!scope)
    1239             :         return false;
    1240             :       ar.emplace(cx, scope);
    1241             :       if (!JS_WrapObject(cx, &proto)) {
    1242             :         return false;
    1243             :       }
    1244             :     }
    1245             : 
    1246             :     MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
    1247             :     if (!value->WrapObject(cx, proto, &obj)) {
    1248             :       return false;
    1249             :     }
    1250             : 
    1251             :     value.forget();
    1252             :   }
    1253             : 
    1254             :   // We can end up here in all sorts of compartments, per above.  Make
    1255             :   // sure to JS_WrapValue!
    1256             :   rval.set(JS::ObjectValue(*obj));
    1257             :   return MaybeWrapObjectValue(cx, rval);
    1258             : }
    1259             : 
    1260             : // Helper for smart pointers (nsRefPtr/nsCOMPtr).
    1261             : template <template <typename> class SmartPtr, typename T,
    1262             :           typename U=typename EnableIf<IsRefcounted<T>::value, T>::Type,
    1263             :           typename V=typename EnableIf<IsSmartPtr<SmartPtr<T>>::value, T>::Type>
    1264             : inline bool
    1265             : WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
    1266             :                                      const SmartPtr<T>& value,
    1267             :                                      JS::MutableHandle<JS::Value> rval,
    1268             :                                      JS::Handle<JSObject*> givenProto = nullptr)
    1269             : {
    1270             :   return WrapNewBindingNonWrapperCachedObject(cx, scope, value.get(), rval,
    1271             :                                               givenProto);
    1272             : }
    1273             : 
    1274             : // Helper for object references (as opposed to pointers).
    1275             : template <typename T,
    1276             :           typename U=typename EnableIf<!IsSmartPtr<T>::value, T>::Type>
    1277             : inline bool
    1278             : WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
    1279             :                                      T& value,
    1280             :                                      JS::MutableHandle<JS::Value> rval,
    1281             :                                      JS::Handle<JSObject*> givenProto = nullptr)
    1282             : {
    1283             :   return WrapNewBindingNonWrapperCachedObject(cx, scope, &value, rval,
    1284             :                                               givenProto);
    1285             : }
    1286             : 
    1287             : template<bool Fatal>
    1288             : inline bool
    1289             : EnumValueNotFound(JSContext* cx, JS::HandleString str, const char* type,
    1290             :                   const char* sourceDescription);
    1291             : 
    1292             : template<>
    1293             : inline bool
    1294             : EnumValueNotFound<false>(JSContext* cx, JS::HandleString str, const char* type,
    1295             :                          const char* sourceDescription)
    1296             : {
    1297             :   // TODO: Log a warning to the console.
    1298             :   return true;
    1299             : }
    1300             : 
    1301             : template<>
    1302             : inline bool
    1303             : EnumValueNotFound<true>(JSContext* cx, JS::HandleString str, const char* type,
    1304             :                         const char* sourceDescription)
    1305             : {
    1306             :   JSAutoByteString deflated;
    1307             :   if (!deflated.encodeUtf8(cx, str)) {
    1308             :     return false;
    1309             :   }
    1310             :   return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
    1311             :                            deflated.ptr(), type);
    1312             : }
    1313             : 
    1314             : template<typename CharT>
    1315             : inline int
    1316             : FindEnumStringIndexImpl(const CharT* chars, size_t length, const EnumEntry* values)
    1317             : {
    1318             :   int i = 0;
    1319             :   for (const EnumEntry* value = values; value->value; ++value, ++i) {
    1320             :     if (length != value->length) {
    1321             :       continue;
    1322             :     }
    1323             : 
    1324             :     bool equal = true;
    1325             :     const char* val = value->value;
    1326             :     for (size_t j = 0; j != length; ++j) {
    1327             :       if (unsigned(val[j]) != unsigned(chars[j])) {
    1328             :         equal = false;
    1329             :         break;
    1330             :       }
    1331             :     }
    1332             : 
    1333             :     if (equal) {
    1334             :       return i;
    1335             :     }
    1336             :   }
    1337             : 
    1338             :   return -1;
    1339             : }
    1340             : 
    1341             : template<bool InvalidValueFatal>
    1342             : inline bool
    1343             : FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* values,
    1344             :                     const char* type, const char* sourceDescription, int* index)
    1345             : {
    1346             :   // JS_StringEqualsAscii is slow as molasses, so don't use it here.
    1347             :   JS::RootedString str(cx, JS::ToString(cx, v));
    1348             :   if (!str) {
    1349             :     return false;
    1350             :   }
    1351             : 
    1352             :   {
    1353             :     size_t length;
    1354             :     JS::AutoCheckCannotGC nogc;
    1355             :     if (js::StringHasLatin1Chars(str)) {
    1356             :       const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str,
    1357             :                                                                      &length);
    1358             :       if (!chars) {
    1359             :         return false;
    1360             :       }
    1361             :       *index = FindEnumStringIndexImpl(chars, length, values);
    1362             :     } else {
    1363             :       const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, str,
    1364             :                                                                 &length);
    1365             :       if (!chars) {
    1366             :         return false;
    1367             :       }
    1368             :       *index = FindEnumStringIndexImpl(chars, length, values);
    1369             :     }
    1370             :     if (*index >= 0) {
    1371             :       return true;
    1372             :     }
    1373             :   }
    1374             : 
    1375             :   return EnumValueNotFound<InvalidValueFatal>(cx, str, type, sourceDescription);
    1376             : }
    1377             : 
    1378             : inline nsWrapperCache*
    1379             : GetWrapperCache(const ParentObject& aParentObject)
    1380             : {
    1381             :   return aParentObject.mWrapperCache;
    1382             : }
    1383             : 
    1384             : template<class T>
    1385             : inline T*
    1386             : GetParentPointer(T* aObject)
    1387             : {
    1388             :   return aObject;
    1389             : }
    1390             : 
    1391             : inline nsISupports*
    1392             : GetParentPointer(const ParentObject& aObject)
    1393             : {
    1394             :   return aObject.mObject;
    1395             : }
    1396             : 
    1397             : template <typename T>
    1398             : inline bool
    1399             : GetUseXBLScope(T* aParentObject)
    1400             : {
    1401             :   return false;
    1402             : }
    1403             : 
    1404             : inline bool
    1405             : GetUseXBLScope(const ParentObject& aParentObject)
    1406             : {
    1407             :   return aParentObject.mUseXBLScope;
    1408             : }
    1409             : 
    1410             : template<class T>
    1411             : inline void
    1412             : ClearWrapper(T* p, nsWrapperCache* cache, JSObject* obj)
    1413             : {
    1414             :   JS::AutoAssertGCCallback inCallback;
    1415             :   cache->ClearWrapper(obj);
    1416             : }
    1417             : 
    1418             : template<class T>
    1419             : inline void
    1420             : ClearWrapper(T* p, void*, JSObject* obj)
    1421             : {
    1422             :   JS::AutoAssertGCCallback inCallback;
    1423             :   nsWrapperCache* cache;
    1424             :   CallQueryInterface(p, &cache);
    1425             :   ClearWrapper(p, cache, obj);
    1426             : }
    1427             : 
    1428             : template<class T>
    1429             : inline void
    1430             : UpdateWrapper(T* p, nsWrapperCache* cache, JSObject* obj, const JSObject* old)
    1431             : {
    1432             :   JS::AutoAssertGCCallback inCallback;
    1433             :   cache->UpdateWrapper(obj, old);
    1434             : }
    1435             : 
    1436             : template<class T>
    1437             : inline void
    1438             : UpdateWrapper(T* p, void*, JSObject* obj, const JSObject* old)
    1439             : {
    1440             :   JS::AutoAssertGCCallback inCallback;
    1441             :   nsWrapperCache* cache;
    1442             :   CallQueryInterface(p, &cache);
    1443             :   UpdateWrapper(p, cache, obj, old);
    1444             : }
    1445             : 
    1446             : // Attempt to preserve the wrapper, if any, for a Paris DOM bindings object.
    1447             : // Return true if we successfully preserved the wrapper, or there is no wrapper
    1448             : // to preserve. In the latter case we don't need to preserve the wrapper, because
    1449             : // the object can only be obtained by JS once, or they cannot be meaningfully
    1450             : // owned from the native side.
    1451             : //
    1452             : // This operation will return false only for non-nsISupports cycle-collected
    1453             : // objects, because we cannot determine if they are wrappercached or not.
    1454             : bool
    1455             : TryPreserveWrapper(JSObject* obj);
    1456             : 
    1457             : // Can only be called with a DOM JSClass.
    1458             : bool
    1459             : InstanceClassHasProtoAtDepth(const js::Class* clasp,
    1460             :                              uint32_t protoID, uint32_t depth);
    1461             : 
    1462             : // Only set allowNativeWrapper to false if you really know you need it; if in
    1463             : // doubt use true. Setting it to false disables security wrappers.
    1464             : bool
    1465             : XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
    1466             :                    xpcObjectHelper& helper, const nsIID* iid,
    1467             :                    bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval);
    1468             : 
    1469             : // Special-cased wrapping for variants
    1470             : bool
    1471             : VariantToJsval(JSContext* aCx, nsIVariant* aVariant,
    1472             :                JS::MutableHandle<JS::Value> aRetval);
    1473             : 
    1474             : // Wrap an object "p" which is not using WebIDL bindings yet.  This _will_
    1475             : // actually work on WebIDL binding objects that are wrappercached, but will be
    1476             : // much slower than GetOrCreateDOMReflector.  "cache" must either be null or be
    1477             : // the nsWrapperCache for "p".
    1478             : template<class T>
    1479             : inline bool
    1480           0 : WrapObject(JSContext* cx, T* p, nsWrapperCache* cache, const nsIID* iid,
    1481             :            JS::MutableHandle<JS::Value> rval)
    1482             : {
    1483           0 :   if (xpc_FastGetCachedWrapper(cx, cache, rval))
    1484             :     return true;
    1485           0 :   xpcObjectHelper helper(ToSupports(p), cache);
    1486           0 :   JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
    1487           0 :   return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval);
    1488             : }
    1489             : 
    1490             : // A specialization of the above for nsIVariant, because that needs to
    1491             : // do something different.
    1492             : template<>
    1493             : inline bool
    1494             : WrapObject<nsIVariant>(JSContext* cx, nsIVariant* p,
    1495             :                        nsWrapperCache* cache, const nsIID* iid,
    1496             :                        JS::MutableHandle<JS::Value> rval)
    1497             : {
    1498             :   MOZ_ASSERT(iid);
    1499             :   MOZ_ASSERT(iid->Equals(NS_GET_IID(nsIVariant)));
    1500             :   return VariantToJsval(cx, p, rval);
    1501             : }
    1502             : 
    1503             : // Wrap an object "p" which is not using WebIDL bindings yet.  Just like the
    1504             : // variant that takes an nsWrapperCache above, but will try to auto-derive the
    1505             : // nsWrapperCache* from "p".
    1506             : template<class T>
    1507             : inline bool
    1508           0 : WrapObject(JSContext* cx, T* p, const nsIID* iid,
    1509             :            JS::MutableHandle<JS::Value> rval)
    1510             : {
    1511           0 :   return WrapObject(cx, p, GetWrapperCache(p), iid, rval);
    1512             : }
    1513             : 
    1514             : // Just like the WrapObject above, but without requiring you to pick which
    1515             : // interface you're wrapping as.  This should only be used for objects that have
    1516             : // classinfo, for which it doesn't matter what IID is used to wrap.
    1517             : template<class T>
    1518             : inline bool
    1519             : WrapObject(JSContext* cx, T* p, JS::MutableHandle<JS::Value> rval)
    1520             : {
    1521             :   return WrapObject(cx, p, nullptr, rval);
    1522             : }
    1523             : 
    1524             : // Helper to make it possible to wrap directly out of an nsCOMPtr
    1525             : template<class T>
    1526             : inline bool
    1527           0 : WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
    1528             :            const nsIID* iid, JS::MutableHandle<JS::Value> rval)
    1529             : {
    1530           0 :   return WrapObject(cx, p.get(), iid, rval);
    1531             : }
    1532             : 
    1533             : // Helper to make it possible to wrap directly out of an nsCOMPtr
    1534             : template<class T>
    1535             : inline bool
    1536             : WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
    1537             :            JS::MutableHandle<JS::Value> rval)
    1538             : {
    1539             :   return WrapObject(cx, p, nullptr, rval);
    1540             : }
    1541             : 
    1542             : // Helper to make it possible to wrap directly out of an nsRefPtr
    1543             : template<class T>
    1544             : inline bool
    1545           0 : WrapObject(JSContext* cx, const RefPtr<T>& p,
    1546             :            const nsIID* iid, JS::MutableHandle<JS::Value> rval)
    1547             : {
    1548           0 :   return WrapObject(cx, p.get(), iid, rval);
    1549             : }
    1550             : 
    1551             : // Helper to make it possible to wrap directly out of an nsRefPtr
    1552             : template<class T>
    1553             : inline bool
    1554             : WrapObject(JSContext* cx, const RefPtr<T>& p,
    1555             :            JS::MutableHandle<JS::Value> rval)
    1556             : {
    1557             :   return WrapObject(cx, p, nullptr, rval);
    1558             : }
    1559             : 
    1560             : // Specialization to make it easy to use WrapObject in codegen.
    1561             : template<>
    1562             : inline bool
    1563             : WrapObject<JSObject>(JSContext* cx, JSObject* p,
    1564             :                      JS::MutableHandle<JS::Value> rval)
    1565             : {
    1566             :   rval.set(JS::ObjectOrNullValue(p));
    1567             :   return true;
    1568             : }
    1569             : 
    1570             : inline bool
    1571             : WrapObject(JSContext* cx, JSObject& p, JS::MutableHandle<JS::Value> rval)
    1572             : {
    1573             :   rval.set(JS::ObjectValue(p));
    1574             :   return true;
    1575             : }
    1576             : 
    1577             : // Given an object "p" that inherits from nsISupports, wrap it and return the
    1578             : // result.  Null is returned on wrapping failure.  This is somewhat similar to
    1579             : // WrapObject() above, but does NOT allow Xrays around the result, since we
    1580             : // don't want those for our parent object.
    1581             : template<typename T>
    1582             : static inline JSObject*
    1583             : WrapNativeISupports(JSContext* cx, T* p, nsWrapperCache* cache)
    1584             : {
    1585             :   xpcObjectHelper helper(ToSupports(p), cache);
    1586             :   JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
    1587             :   JS::Rooted<JS::Value> v(cx);
    1588             :   return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
    1589             :          v.toObjectOrNull() :
    1590             :          nullptr;
    1591             : }
    1592             : 
    1593             : 
    1594             : // Wrapping of our native parent, for cases when it's a WebIDL object.
    1595             : template<typename T, bool hasWrapObject=NativeHasMember<T>::WrapObject>
    1596             : struct WrapNativeHelper
    1597             : {
    1598             :   static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
    1599             :   {
    1600             :     MOZ_ASSERT(cache);
    1601             : 
    1602             :     JSObject* obj;
    1603             :     if ((obj = cache->GetWrapper())) {
    1604             :       // GetWrapper always unmarks gray.
    1605             :       MOZ_ASSERT(JS::ObjectIsNotGray(obj));
    1606             :       return obj;
    1607             :     }
    1608             : 
    1609             :     // WrapObject never returns a gray thing.
    1610             :     obj = parent->WrapObject(cx, nullptr);
    1611             :     MOZ_ASSERT(JS::ObjectIsNotGray(obj));
    1612             : 
    1613             :     return obj;
    1614             :   }
    1615             : };
    1616             : 
    1617             : // Wrapping of our native parent, for cases when it's not a WebIDL object.  In
    1618             : // this case it must be nsISupports.
    1619             : template<typename T>
    1620             : struct WrapNativeHelper<T, false>
    1621             : {
    1622             :   static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
    1623             :   {
    1624             :     JSObject* obj;
    1625             :     if (cache && (obj = cache->GetWrapper())) {
    1626             : #ifdef DEBUG
    1627             :       JS::Rooted<JSObject*> rootedObj(cx, obj);
    1628             :       NS_ASSERTION(WrapNativeISupports(cx, parent, cache) == rootedObj,
    1629             :                    "Unexpected object in nsWrapperCache");
    1630             :       obj = rootedObj;
    1631             : #endif
    1632             :       MOZ_ASSERT(JS::ObjectIsNotGray(obj));
    1633             :       return obj;
    1634             :     }
    1635             : 
    1636             :     obj = WrapNativeISupports(cx, parent, cache);
    1637             :     MOZ_ASSERT(JS::ObjectIsNotGray(obj));
    1638             :     return obj;
    1639             :   }
    1640             : };
    1641             : 
    1642             : // Finding the associated global for an object.
    1643             : template<typename T>
    1644             : static inline JSObject*
    1645             : FindAssociatedGlobal(JSContext* cx, T* p, nsWrapperCache* cache,
    1646             :                      bool useXBLScope = false)
    1647             : {
    1648             :   if (!p) {
    1649             :     return JS::CurrentGlobalOrNull(cx);
    1650             :   }
    1651             : 
    1652             :   JSObject* obj = WrapNativeHelper<T>::Wrap(cx, p, cache);
    1653             :   if (!obj) {
    1654             :     return nullptr;
    1655             :   }
    1656             :   MOZ_ASSERT(JS::ObjectIsNotGray(obj));
    1657             : 
    1658             :   obj = js::GetGlobalForObjectCrossCompartment(obj);
    1659             : 
    1660             :   if (!useXBLScope) {
    1661             :     return obj;
    1662             :   }
    1663             : 
    1664             :   // If useXBLScope is true, it means that the canonical reflector for this
    1665             :   // native object should live in the content XBL scope. Note that we never put
    1666             :   // anonymous content inside an add-on scope.
    1667             :   if (xpc::IsInContentXBLScope(obj)) {
    1668             :     return obj;
    1669             :   }
    1670             :   JS::Rooted<JSObject*> rootedObj(cx, obj);
    1671             :   JSObject* xblScope = xpc::GetXBLScope(cx, rootedObj);
    1672             :   MOZ_ASSERT_IF(xblScope, JS_IsGlobalObject(xblScope));
    1673             :   MOZ_ASSERT(JS::ObjectIsNotGray(xblScope));
    1674             :   return xblScope;
    1675             : }
    1676             : 
    1677             : // Finding of the associated global for an object, when we don't want to
    1678             : // explicitly pass in things like the nsWrapperCache for it.
    1679             : template<typename T>
    1680             : static inline JSObject*
    1681             : FindAssociatedGlobal(JSContext* cx, const T& p)
    1682             : {
    1683             :   return FindAssociatedGlobal(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
    1684             : }
    1685             : 
    1686             : // Specialization for the case of nsIGlobalObject, since in that case
    1687             : // we can just get the JSObject* directly.
    1688             : template<>
    1689             : inline JSObject*
    1690             : FindAssociatedGlobal(JSContext* cx, nsIGlobalObject* const& p)
    1691             : {
    1692             :   if (!p) {
    1693             :     return JS::CurrentGlobalOrNull(cx);
    1694             :   }
    1695             : 
    1696             :   JSObject* global = p->GetGlobalJSObject();
    1697             :   if (!global) {
    1698             :     return nullptr;
    1699             :   }
    1700             : 
    1701             :   MOZ_ASSERT(JS_IsGlobalObject(global));
    1702             :   // This object could be gray if the nsIGlobalObject is the only thing keeping
    1703             :   // it alive.
    1704             :   JS::ExposeObjectToActiveJS(global);
    1705             :   return global;
    1706             : }
    1707             : 
    1708             : template<typename T,
    1709             :          bool hasAssociatedGlobal=NativeHasMember<T>::GetParentObject>
    1710             : struct FindAssociatedGlobalForNative
    1711             : {
    1712             :   static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
    1713             :   {
    1714             :     MOZ_ASSERT(js::IsObjectInContextCompartment(obj, cx));
    1715             :     T* native = UnwrapDOMObject<T>(obj);
    1716             :     return FindAssociatedGlobal(cx, native->GetParentObject());
    1717             :   }
    1718             : };
    1719             : 
    1720             : template<typename T>
    1721             : struct FindAssociatedGlobalForNative<T, false>
    1722             : {
    1723             :   static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
    1724             :   {
    1725             :     MOZ_CRASH();
    1726             :     return nullptr;
    1727             :   }
    1728             : };
    1729             : 
    1730             : // Helper for calling GetOrCreateDOMReflector with smart pointers
    1731             : // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
    1732             : template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
    1733             : struct GetOrCreateDOMReflectorHelper
    1734             : {
    1735           0 :   static inline bool GetOrCreate(JSContext* cx, const T& value,
    1736             :                                  JS::Handle<JSObject*> givenProto,
    1737             :                                  JS::MutableHandle<JS::Value> rval)
    1738             :   {
    1739           0 :     return GetOrCreateDOMReflector(cx, value.get(), rval, givenProto);
    1740             :   }
    1741             : };
    1742             : 
    1743             : template <class T>
    1744             : struct GetOrCreateDOMReflectorHelper<T, false>
    1745             : {
    1746           0 :   static inline bool GetOrCreate(JSContext* cx, T& value,
    1747             :                                  JS::Handle<JSObject*> givenProto,
    1748             :                                  JS::MutableHandle<JS::Value> rval)
    1749             :   {
    1750             :     static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
    1751           0 :     return GetOrCreateDOMReflector(cx, &value, rval, givenProto);
    1752             :   }
    1753             : };
    1754             : 
    1755             : template<class T>
    1756             : inline bool
    1757             : GetOrCreateDOMReflector(JSContext* cx, T& value,
    1758             :                         JS::MutableHandle<JS::Value> rval,
    1759             :                         JS::Handle<JSObject*> givenProto = nullptr)
    1760             : {
    1761             :   return GetOrCreateDOMReflectorHelper<T>::GetOrCreate(cx, value, givenProto,
    1762           0 :                                                        rval);
    1763             : }
    1764             : 
    1765             : // Helper for calling GetOrCreateDOMReflectorNoWrap with smart pointers
    1766             : // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
    1767             : template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
    1768             : struct GetOrCreateDOMReflectorNoWrapHelper
    1769             : {
    1770             :   static inline bool GetOrCreate(JSContext* cx, const T& value,
    1771             :                                  JS::MutableHandle<JS::Value> rval)
    1772             :   {
    1773             :     return GetOrCreateDOMReflectorNoWrap(cx, value.get(), rval);
    1774             :   }
    1775             : };
    1776             : 
    1777             : template <class T>
    1778             : struct GetOrCreateDOMReflectorNoWrapHelper<T, false>
    1779             : {
    1780             :   static inline bool GetOrCreate(JSContext* cx, T& value,
    1781             :                                  JS::MutableHandle<JS::Value> rval)
    1782             :   {
    1783             :     return GetOrCreateDOMReflectorNoWrap(cx, &value, rval);
    1784             :   }
    1785             : };
    1786             : 
    1787             : template<class T>
    1788             : inline bool
    1789             : GetOrCreateDOMReflectorNoWrap(JSContext* cx, T& value,
    1790             :                               JS::MutableHandle<JS::Value> rval)
    1791             : {
    1792             :   return
    1793             :     GetOrCreateDOMReflectorNoWrapHelper<T>::GetOrCreate(cx, value, rval);
    1794             : }
    1795             : 
    1796             : template <class T>
    1797             : inline JSObject*
    1798             : GetCallbackFromCallbackObject(JSContext* aCx, T* aObj)
    1799             : {
    1800             :   return aObj->Callback(aCx);
    1801             : }
    1802             : 
    1803             : // Helper for getting the callback JSObject* of a smart ptr around a
    1804             : // CallbackObject or a reference to a CallbackObject or something like
    1805             : // that.
    1806             : template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
    1807             : struct GetCallbackFromCallbackObjectHelper
    1808             : {
    1809             :   static inline JSObject* Get(JSContext* aCx, const T& aObj)
    1810             :   {
    1811             :     return GetCallbackFromCallbackObject(aCx, aObj.get());
    1812             :   }
    1813             : };
    1814             : 
    1815             : template <class T>
    1816             : struct GetCallbackFromCallbackObjectHelper<T, false>
    1817             : {
    1818             :   static inline JSObject* Get(JSContext* aCx, T& aObj)
    1819             :   {
    1820             :     return GetCallbackFromCallbackObject(aCx, &aObj);
    1821             :   }
    1822             : };
    1823             : 
    1824             : template<class T>
    1825             : inline JSObject*
    1826             : GetCallbackFromCallbackObject(JSContext* aCx, T& aObj)
    1827             : {
    1828             :   return GetCallbackFromCallbackObjectHelper<T>::Get(aCx, aObj);
    1829             : }
    1830             : 
    1831             : static inline bool
    1832           2 : AtomizeAndPinJSString(JSContext* cx, jsid& id, const char* chars)
    1833             : {
    1834           2 :   if (JSString *str = ::JS_AtomizeAndPinString(cx, chars)) {
    1835           2 :     id = INTERNED_STRING_TO_JSID(cx, str);
    1836           2 :     return true;
    1837             :   }
    1838             :   return false;
    1839             : }
    1840             : 
    1841             : bool
    1842             : InitIds(JSContext* cx, const NativeProperties* properties);
    1843             : 
    1844             : bool
    1845             : QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
    1846             : 
    1847             : template <class T>
    1848             : struct
    1849             : WantsQueryInterface
    1850             : {
    1851             :   static_assert(IsBaseOf<nsISupports, T>::value,
    1852             :                 "QueryInterface can't work without an nsISupports.");
    1853             :   static bool Enabled(JSContext* aCx, JSObject* aGlobal)
    1854             :   {
    1855             :     return NS_IsMainThread() && IsChromeOrXBL(aCx, aGlobal);
    1856             :   }
    1857             : };
    1858             : 
    1859             : void
    1860             : GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
    1861             :                  nsWrapperCache* aCache, nsIJSID* aIID,
    1862             :                  JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError);
    1863             : 
    1864             : template<class T>
    1865             : void
    1866             : GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID,
    1867             :              JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
    1868             : {
    1869             :   GetInterfaceImpl(aCx, aThis, aThis, aIID, aRetval, aError);
    1870             : }
    1871             : 
    1872             : bool
    1873             : ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
    1874             : 
    1875             : bool
    1876             : ThrowConstructorWithoutNew(JSContext* cx, const char* name);
    1877             : 
    1878             : bool
    1879             : GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
    1880             :                        JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
    1881             :                        bool* found, JS::MutableHandle<JS::Value> vp);
    1882             : 
    1883             : //
    1884             : bool
    1885             : HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
    1886             :                        JS::Handle<jsid> id, bool* has);
    1887             : 
    1888             : 
    1889             : // Append the property names in "names" to "props". If
    1890             : // shadowPrototypeProperties is false then skip properties that are also
    1891             : // present on the proto chain of proxy.  If shadowPrototypeProperties is true,
    1892             : // then the "proxy" argument is ignored.
    1893             : bool
    1894             : AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
    1895             :                        nsTArray<nsString>& names,
    1896             :                        bool shadowPrototypeProperties, JS::AutoIdVector& props);
    1897             : 
    1898             : enum StringificationBehavior {
    1899             :   eStringify,
    1900             :   eEmpty,
    1901             :   eNull
    1902             : };
    1903             : 
    1904             : template<typename T>
    1905             : static inline bool
    1906             : ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
    1907             :                        StringificationBehavior nullBehavior,
    1908             :                        StringificationBehavior undefinedBehavior,
    1909             :                        T& result)
    1910             : {
    1911             :   JSString *s;
    1912             :   if (v.isString()) {
    1913             :     s = v.toString();
    1914             :   } else {
    1915             :     StringificationBehavior behavior;
    1916             :     if (v.isNull()) {
    1917             :       behavior = nullBehavior;
    1918             :     } else if (v.isUndefined()) {
    1919             :       behavior = undefinedBehavior;
    1920             :     } else {
    1921             :       behavior = eStringify;
    1922             :     }
    1923             : 
    1924             :     if (behavior != eStringify) {
    1925             :       if (behavior == eEmpty) {
    1926             :         result.Truncate();
    1927             :       } else {
    1928             :         result.SetIsVoid(true);
    1929             :       }
    1930             :       return true;
    1931             :     }
    1932             : 
    1933             :     s = JS::ToString(cx, v);
    1934             :     if (!s) {
    1935             :       return false;
    1936             :     }
    1937             :   }
    1938             : 
    1939             :   return AssignJSString(cx, result, s);
    1940             : }
    1941             : 
    1942             : template<typename T>
    1943             : static inline bool
    1944             : ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
    1945             : {
    1946             :   return ConvertJSValueToString(cx, v, eStringify, eStringify, result);
    1947             : }
    1948             : 
    1949             : void
    1950             : NormalizeUSVString(nsAString& aString);
    1951             : 
    1952             : void
    1953             : NormalizeUSVString(binding_detail::FakeString& aString);
    1954             : 
    1955             : template<typename T>
    1956             : static inline bool
    1957             : ConvertJSValueToUSVString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
    1958             : {
    1959             :   if (!ConvertJSValueToString(cx, v, eStringify, eStringify, result)) {
    1960             :     return false;
    1961             :   }
    1962             : 
    1963             :   NormalizeUSVString(result);
    1964             :   return true;
    1965             : }
    1966             : 
    1967             : template<typename T>
    1968             : inline bool
    1969             : ConvertIdToString(JSContext* cx, JS::HandleId id, T& result, bool& isSymbol)
    1970             : {
    1971             :   if (MOZ_LIKELY(JSID_IS_STRING(id))) {
    1972             :     if (!AssignJSString(cx, result, JSID_TO_STRING(id))) {
    1973             :       return false;
    1974             :     }
    1975             :   } else if (JSID_IS_SYMBOL(id)) {
    1976             :     isSymbol = true;
    1977             :     return true;
    1978             :   } else {
    1979             :     JS::RootedValue nameVal(cx, js::IdToValue(id));
    1980             :     if (!ConvertJSValueToString(cx, nameVal, eStringify, eStringify, result)) {
    1981             :       return false;
    1982             :     }
    1983             :   }
    1984             :   isSymbol = false;
    1985             :   return true;
    1986             : }
    1987             : 
    1988             : bool
    1989             : ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
    1990             :                            bool nullable, nsACString& result);
    1991             : 
    1992             : inline bool
    1993             : ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
    1994             :                            nsACString& result)
    1995             : {
    1996             :   return ConvertJSValueToByteString(cx, v, false, result);
    1997             : }
    1998             : 
    1999             : template<typename T>
    2000             : void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
    2001             : template<typename T>
    2002             : void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
    2003             : 
    2004             : // Class used to trace sequences, with specializations for various
    2005             : // sequence types.
    2006             : template<typename T,
    2007             :          bool isDictionary=IsBaseOf<DictionaryBase, T>::value,
    2008             :          bool isTypedArray=IsBaseOf<AllTypedArraysBase, T>::value,
    2009             :          bool isOwningUnion=IsBaseOf<AllOwningUnionBase, T>::value>
    2010             : class SequenceTracer
    2011             : {
    2012             :   explicit SequenceTracer() = delete; // Should never be instantiated
    2013             : };
    2014             : 
    2015             : // sequence<object> or sequence<object?>
    2016             : template<>
    2017             : class SequenceTracer<JSObject*, false, false, false>
    2018             : {
    2019             :   explicit SequenceTracer() = delete; // Should never be instantiated
    2020             : 
    2021             : public:
    2022             :   static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
    2023             :     for (; objp != end; ++objp) {
    2024             :       JS::UnsafeTraceRoot(trc, objp, "sequence<object>");
    2025             :     }
    2026             :   }
    2027             : };
    2028             : 
    2029             : // sequence<any>
    2030             : template<>
    2031             : class SequenceTracer<JS::Value, false, false, false>
    2032             : {
    2033             :   explicit SequenceTracer() = delete; // Should never be instantiated
    2034             : 
    2035             : public:
    2036             :   static void TraceSequence(JSTracer* trc, JS::Value* valp, JS::Value* end) {
    2037             :     for (; valp != end; ++valp) {
    2038             :       JS::UnsafeTraceRoot(trc, valp, "sequence<any>");
    2039             :     }
    2040             :   }
    2041             : };
    2042             : 
    2043             : // sequence<sequence<T>>
    2044             : template<typename T>
    2045             : class SequenceTracer<Sequence<T>, false, false, false>
    2046             : {
    2047             :   explicit SequenceTracer() = delete; // Should never be instantiated
    2048             : 
    2049             : public:
    2050             :   static void TraceSequence(JSTracer* trc, Sequence<T>* seqp, Sequence<T>* end) {
    2051             :     for (; seqp != end; ++seqp) {
    2052             :       DoTraceSequence(trc, *seqp);
    2053             :     }
    2054             :   }
    2055             : };
    2056             : 
    2057             : // sequence<sequence<T>> as return value
    2058             : template<typename T>
    2059             : class SequenceTracer<nsTArray<T>, false, false, false>
    2060             : {
    2061             :   explicit SequenceTracer() = delete; // Should never be instantiated
    2062             : 
    2063             : public:
    2064             :   static void TraceSequence(JSTracer* trc, nsTArray<T>* seqp, nsTArray<T>* end) {
    2065             :     for (; seqp != end; ++seqp) {
    2066             :       DoTraceSequence(trc, *seqp);
    2067             :     }
    2068             :   }
    2069             : };
    2070             : 
    2071             : // sequence<someDictionary>
    2072             : template<typename T>
    2073             : class SequenceTracer<T, true, false, false>
    2074             : {
    2075             :   explicit SequenceTracer() = delete; // Should never be instantiated
    2076             : 
    2077             : public:
    2078             :   static void TraceSequence(JSTracer* trc, T* dictp, T* end) {
    2079             :     for (; dictp != end; ++dictp) {
    2080             :       dictp->TraceDictionary(trc);
    2081             :     }
    2082             :   }
    2083             : };
    2084             : 
    2085             : // sequence<SomeTypedArray>
    2086             : template<typename T>
    2087             : class SequenceTracer<T, false, true, false>
    2088             : {
    2089             :   explicit SequenceTracer() = delete; // Should never be instantiated
    2090             : 
    2091             : public:
    2092             :   static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
    2093             :     for (; arrayp != end; ++arrayp) {
    2094             :       arrayp->TraceSelf(trc);
    2095             :     }
    2096             :   }
    2097             : };
    2098             : 
    2099             : // sequence<SomeOwningUnion>
    2100             : template<typename T>
    2101             : class SequenceTracer<T, false, false, true>
    2102             : {
    2103             :   explicit SequenceTracer() = delete; // Should never be instantiated
    2104             : 
    2105             : public:
    2106             :   static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
    2107             :     for (; arrayp != end; ++arrayp) {
    2108             :       arrayp->TraceUnion(trc);
    2109             :     }
    2110             :   }
    2111             : };
    2112             : 
    2113             : // sequence<T?> with T? being a Nullable<T>
    2114             : template<typename T>
    2115             : class SequenceTracer<Nullable<T>, false, false, false>
    2116             : {
    2117             :   explicit SequenceTracer() = delete; // Should never be instantiated
    2118             : 
    2119             : public:
    2120             :   static void TraceSequence(JSTracer* trc, Nullable<T>* seqp,
    2121             :                             Nullable<T>* end) {
    2122             :     for (; seqp != end; ++seqp) {
    2123             :       if (!seqp->IsNull()) {
    2124             :         // Pretend like we actually have a length-one sequence here so
    2125             :         // we can do template instantiation correctly for T.
    2126             :         T& val = seqp->Value();
    2127             :         T* ptr = &val;
    2128             :         SequenceTracer<T>::TraceSequence(trc, ptr, ptr+1);
    2129             :       }
    2130             :     }
    2131             :   }
    2132             : };
    2133             : 
    2134             : template<typename K, typename V>
    2135             : void TraceRecord(JSTracer* trc, Record<K, V>& record)
    2136             : {
    2137             :   for (auto& entry : record.Entries()) {
    2138             :     // Act like it's a one-element sequence to leverage all that infrastructure.
    2139             :     SequenceTracer<V>::TraceSequence(trc, &entry.mValue, &entry.mValue + 1);
    2140             :   }
    2141             : }
    2142             : 
    2143             : // sequence<record>
    2144             : template<typename K, typename V>
    2145             : class SequenceTracer<Record<K, V>, false, false, false>
    2146             : {
    2147             :   explicit SequenceTracer() = delete; // Should never be instantiated
    2148             : 
    2149             : public:
    2150             :   static void TraceSequence(JSTracer* trc, Record<K, V>* seqp,
    2151             :                             Record<K, V>* end) {
    2152             :     for (; seqp != end; ++seqp) {
    2153             :       TraceRecord(trc, *seqp);
    2154             :     }
    2155             :   }
    2156             : };
    2157             : 
    2158             : template<typename T>
    2159             : void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq)
    2160             : {
    2161             :   SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
    2162             :                                    seq.Elements() + seq.Length());
    2163             : }
    2164             : 
    2165             : template<typename T>
    2166             : void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq)
    2167             : {
    2168             :   SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
    2169             :                                    seq.Elements() + seq.Length());
    2170             : }
    2171             : 
    2172             : // Rooter class for sequences; this is what we mostly use in the codegen
    2173             : template<typename T>
    2174             : class MOZ_RAII SequenceRooter final : private JS::CustomAutoRooter
    2175             : {
    2176             : public:
    2177             :   SequenceRooter(JSContext *aCx, FallibleTArray<T>* aSequence
    2178             :                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    2179             :     : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
    2180             :       mFallibleArray(aSequence),
    2181             :       mSequenceType(eFallibleArray)
    2182             :   {
    2183             :   }
    2184             : 
    2185             :   SequenceRooter(JSContext *aCx, InfallibleTArray<T>* aSequence
    2186             :                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    2187             :     : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
    2188             :       mInfallibleArray(aSequence),
    2189             :       mSequenceType(eInfallibleArray)
    2190             :   {
    2191             :   }
    2192             : 
    2193             :   SequenceRooter(JSContext *aCx, Nullable<nsTArray<T> >* aSequence
    2194             :                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    2195             :     : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
    2196             :       mNullableArray(aSequence),
    2197             :       mSequenceType(eNullableArray)
    2198             :   {
    2199             :   }
    2200             : 
    2201             :  private:
    2202             :   enum SequenceType {
    2203             :     eInfallibleArray,
    2204             :     eFallibleArray,
    2205             :     eNullableArray
    2206             :   };
    2207             : 
    2208             :   virtual void trace(JSTracer *trc) override
    2209             :   {
    2210             :     if (mSequenceType == eFallibleArray) {
    2211             :       DoTraceSequence(trc, *mFallibleArray);
    2212             :     } else if (mSequenceType == eInfallibleArray) {
    2213             :       DoTraceSequence(trc, *mInfallibleArray);
    2214             :     } else {
    2215             :       MOZ_ASSERT(mSequenceType == eNullableArray);
    2216             :       if (!mNullableArray->IsNull()) {
    2217             :         DoTraceSequence(trc, mNullableArray->Value());
    2218             :       }
    2219             :     }
    2220             :   }
    2221             : 
    2222             :   union {
    2223             :     InfallibleTArray<T>* mInfallibleArray;
    2224             :     FallibleTArray<T>* mFallibleArray;
    2225             :     Nullable<nsTArray<T> >* mNullableArray;
    2226             :   };
    2227             : 
    2228             :   SequenceType mSequenceType;
    2229             : };
    2230             : 
    2231             : // Rooter class for Record; this is what we mostly use in the codegen.
    2232             : template<typename K, typename V>
    2233             : class MOZ_RAII RecordRooter final : private JS::CustomAutoRooter
    2234             : {
    2235             : public:
    2236             :   RecordRooter(JSContext *aCx, Record<K, V>* aRecord
    2237             :                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    2238             :     : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
    2239             :       mRecord(aRecord),
    2240             :       mRecordType(eRecord)
    2241             :   {
    2242             :   }
    2243             : 
    2244             :   RecordRooter(JSContext *aCx, Nullable<Record<K, V>>* aRecord
    2245             :                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    2246             :     : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
    2247             :       mNullableRecord(aRecord),
    2248             :       mRecordType(eNullableRecord)
    2249             :   {
    2250             :   }
    2251             : 
    2252             : private:
    2253             :   enum RecordType {
    2254             :     eRecord,
    2255             :     eNullableRecord
    2256             :   };
    2257             : 
    2258             :   virtual void trace(JSTracer *trc) override
    2259             :   {
    2260             :     if (mRecordType == eRecord) {
    2261             :       TraceRecord(trc, *mRecord);
    2262             :     } else {
    2263             :       MOZ_ASSERT(mRecordType == eNullableRecord);
    2264             :       if (!mNullableRecord->IsNull()) {
    2265             :         TraceRecord(trc, mNullableRecord->Value());
    2266             :       }
    2267             :     }
    2268             :   }
    2269             : 
    2270             :   union {
    2271             :     Record<K, V>* mRecord;
    2272             :     Nullable<Record<K, V>>* mNullableRecord;
    2273             :   };
    2274             : 
    2275             :   RecordType mRecordType;
    2276             : };
    2277             : 
    2278             : template<typename T>
    2279             : class MOZ_RAII RootedUnion : public T,
    2280             :                              private JS::CustomAutoRooter
    2281             : {
    2282             : public:
    2283             :   explicit RootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
    2284             :     T(),
    2285             :     JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
    2286             :   {
    2287             :   }
    2288             : 
    2289             :   virtual void trace(JSTracer *trc) override
    2290             :   {
    2291             :     this->TraceUnion(trc);
    2292             :   }
    2293             : };
    2294             : 
    2295             : template<typename T>
    2296             : class MOZ_STACK_CLASS NullableRootedUnion : public Nullable<T>,
    2297             :                                             private JS::CustomAutoRooter
    2298             : {
    2299             : public:
    2300             :   explicit NullableRootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
    2301             :     Nullable<T>(),
    2302             :     JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
    2303             :   {
    2304             :   }
    2305             : 
    2306             :   virtual void trace(JSTracer *trc) override
    2307             :   {
    2308             :     if (!this->IsNull()) {
    2309             :       this->Value().TraceUnion(trc);
    2310             :     }
    2311             :   }
    2312             : };
    2313             : 
    2314             : inline bool
    2315             : IdEquals(jsid id, const char* string)
    2316             : {
    2317             :   return JSID_IS_STRING(id) &&
    2318             :          JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
    2319             : }
    2320             : 
    2321             : inline bool
    2322           0 : AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector, const char* name)
    2323             : {
    2324           0 :   return vector.growBy(1) &&
    2325           0 :          AtomizeAndPinJSString(cx, *(vector[vector.length() - 1]).address(), name);
    2326             : }
    2327             : 
    2328             : // We use one constructor JSNative to represent all DOM interface objects (so
    2329             : // we can easily detect when we need to wrap them in an Xray wrapper). We store
    2330             : // the real JSNative in the mNative member of a JSNativeHolder in the
    2331             : // CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction object for a
    2332             : // specific interface object. We also store the NativeProperties in the
    2333             : // JSNativeHolder.
    2334             : // Note that some interface objects are not yet a JSFunction but a normal
    2335             : // JSObject with a DOMJSClass, those do not use these slots.
    2336             : 
    2337             : enum {
    2338             :   CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT = 0
    2339             : };
    2340             : 
    2341             : bool
    2342             : Constructor(JSContext* cx, unsigned argc, JS::Value* vp);
    2343             : 
    2344             : // Implementation of the bits that XrayWrapper needs
    2345             : 
    2346             : /**
    2347             :  * This resolves operations, attributes and constants of the interfaces for obj.
    2348             :  *
    2349             :  * wrapper is the Xray JS object.
    2350             :  * obj is the target object of the Xray, a binding's instance object or a
    2351             :  *     interface or interface prototype object.
    2352             :  */
    2353             : bool
    2354             : XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
    2355             :                        JS::Handle<JSObject*> obj,
    2356             :                        JS::Handle<jsid> id,
    2357             :                        JS::MutableHandle<JS::PropertyDescriptor> desc,
    2358             :                        bool& cacheOnHolder);
    2359             : 
    2360             : /**
    2361             :  * Define a property on obj through an Xray wrapper.
    2362             :  *
    2363             :  * wrapper is the Xray JS object.
    2364             :  * obj is the target object of the Xray, a binding's instance object or a
    2365             :  *     interface or interface prototype object.
    2366             :  * id and desc are the parameters for the property to be defined.
    2367             :  * result is the out-parameter indicating success (read it only if
    2368             :  *     this returns true and also sets *defined to true).
    2369             :  * defined will be set to true if a property was set as a result of this call.
    2370             :  */
    2371             : bool
    2372             : XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
    2373             :                    JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
    2374             :                    JS::Handle<JS::PropertyDescriptor> desc,
    2375             :                    JS::ObjectOpResult &result,
    2376             :                    bool *defined);
    2377             : 
    2378             : /**
    2379             :  * Add to props the property keys of all indexed or named properties of obj and
    2380             :  * operations, attributes and constants of the interfaces for obj.
    2381             :  *
    2382             :  * wrapper is the Xray JS object.
    2383             :  * obj is the target object of the Xray, a binding's instance object or a
    2384             :  *     interface or interface prototype object.
    2385             :  * flags are JSITER_* flags.
    2386             :  */
    2387             : bool
    2388             : XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
    2389             :                     JS::Handle<JSObject*> obj,
    2390             :                     unsigned flags, JS::AutoIdVector& props);
    2391             : 
    2392             : /**
    2393             :  * Returns the prototype to use for an Xray for a DOM object, wrapped in cx's
    2394             :  * compartment. This always returns the prototype that would be used for a DOM
    2395             :  * object if we ignore any changes that might have been done to the prototype
    2396             :  * chain by JS, the XBL code or plugins.
    2397             :  *
    2398             :  * cx should be in the Xray's compartment.
    2399             :  * obj is the target object of the Xray, a binding's instance object or an
    2400             :  *     interface or interface prototype object.
    2401             :  */
    2402             : inline bool
    2403             : XrayGetNativeProto(JSContext* cx, JS::Handle<JSObject*> obj,
    2404             :                    JS::MutableHandle<JSObject*> protop)
    2405             : {
    2406             :   JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
    2407             :   {
    2408             :     JSAutoRealm ar(cx, global);
    2409             :     const DOMJSClass* domClass = GetDOMClass(obj);
    2410             :     if (domClass) {
    2411             :       ProtoHandleGetter protoGetter = domClass->mGetProto;
    2412             :       if (protoGetter) {
    2413             :         protop.set(protoGetter(cx));
    2414             :       } else {
    2415             :         protop.set(JS::GetRealmObjectPrototype(cx));
    2416             :       }
    2417             :     } else if (JS_ObjectIsFunction(cx, obj)) {
    2418             :       MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
    2419             :       protop.set(JS::GetRealmFunctionPrototype(cx));
    2420             :     } else {
    2421             :       const js::Class* clasp = js::GetObjectClass(obj);
    2422             :       MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
    2423             :       ProtoGetter protoGetter =
    2424             :         DOMIfaceAndProtoJSClass::FromJSClass(clasp)->mGetParentProto;
    2425             :       protop.set(protoGetter(cx));
    2426             :     }
    2427             :   }
    2428             : 
    2429             :   return JS_WrapObject(cx, protop);
    2430             : }
    2431             : 
    2432             : /**
    2433             :  * Get the Xray expando class to use for the given DOM object.
    2434             :  */
    2435             : const JSClass*
    2436             : XrayGetExpandoClass(JSContext* cx, JS::Handle<JSObject*> obj);
    2437             : 
    2438             : /**
    2439             :  * Delete a named property, if any.  Return value is false if exception thrown,
    2440             :  * true otherwise.  The caller should not do any more work after calling this
    2441             :  * function, because it has no way whether a deletion was performed and hence
    2442             :  * opresult already has state set on it.  If callers ever need to change that,
    2443             :  * add a "bool* found" argument and change the generated DeleteNamedProperty to
    2444             :  * use it instead of a local variable.
    2445             :  */
    2446             : bool
    2447             : XrayDeleteNamedProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
    2448             :                         JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
    2449             :                         JS::ObjectOpResult& opresult);
    2450             : 
    2451             : /**
    2452             :  * Get the object which should be used to cache the return value of a property
    2453             :  * getter in the case of a [Cached] or [StoreInSlot] property.  `obj` is the
    2454             :  * `this` value for our property getter that we're working with.
    2455             :  *
    2456             :  * This function can return null on failure to allocate the object, throwing on
    2457             :  * the JSContext in the process.
    2458             :  *
    2459             :  * The isXray outparam will be set to true if obj is an Xray and false
    2460             :  * otherwise.
    2461             :  *
    2462             :  * Note that the Slow version should only be called from
    2463             :  * GetCachedSlotStorageObject.
    2464             :  */
    2465             : JSObject*
    2466             : GetCachedSlotStorageObjectSlow(JSContext* cx, JS::Handle<JSObject*> obj,
    2467             :                                bool* isXray);
    2468             : 
    2469             : inline JSObject*
    2470             : GetCachedSlotStorageObject(JSContext* cx, JS::Handle<JSObject*> obj,
    2471             :                            bool* isXray) {
    2472             :   if (IsDOMObject(obj)) {
    2473             :     *isXray = false;
    2474             :     return obj;
    2475             :   }
    2476             : 
    2477             :   return GetCachedSlotStorageObjectSlow(cx, obj, isXray);
    2478             : }
    2479             : 
    2480             : extern NativePropertyHooks sEmptyNativePropertyHooks;
    2481             : 
    2482             : extern const js::ClassOps sBoringInterfaceObjectClassClassOps;
    2483             : 
    2484             : extern const js::ObjectOps sInterfaceObjectClassObjectOps;
    2485             : 
    2486             : inline bool
    2487             : UseDOMXray(JSObject* obj)
    2488             : {
    2489             :   const js::Class* clasp = js::GetObjectClass(obj);
    2490             :   return IsDOMClass(clasp) ||
    2491             :          JS_IsNativeFunction(obj, Constructor) ||
    2492             :          IsDOMIfaceAndProtoClass(clasp);
    2493             : }
    2494             : 
    2495             : inline bool
    2496             : IsDOMConstructor(JSObject* obj)
    2497             : {
    2498             :   if (JS_IsNativeFunction(obj, dom::Constructor)) {
    2499             :     // NamedConstructor, like Image
    2500             :     return true;
    2501             :   }
    2502             : 
    2503             :   const js::Class* clasp = js::GetObjectClass(obj);
    2504             :   // Check for a DOM interface object.
    2505             :   return dom::IsDOMIfaceAndProtoClass(clasp) &&
    2506             :          dom::DOMIfaceAndProtoJSClass::FromJSClass(clasp)->mType == dom::eInterface;
    2507             : }
    2508             : 
    2509             : #ifdef DEBUG
    2510             : inline bool
    2511             : HasConstructor(JSObject* obj)
    2512             : {
    2513             :   return JS_IsNativeFunction(obj, Constructor) ||
    2514             :          js::GetObjectClass(obj)->getConstruct();
    2515             : }
    2516             : #endif
    2517             : 
    2518             : // Helpers for creating a const version of a type.
    2519             : template<typename T>
    2520             : const T& Constify(T& arg)
    2521             : {
    2522             :   return arg;
    2523             : }
    2524             : 
    2525             : // Helper for turning (Owning)NonNull<T> into T&
    2526             : template<typename T>
    2527             : T& NonNullHelper(T& aArg)
    2528             : {
    2529             :   return aArg;
    2530             : }
    2531             : 
    2532             : template<typename T>
    2533             : T& NonNullHelper(NonNull<T>& aArg)
    2534             : {
    2535             :   return aArg;
    2536             : }
    2537             : 
    2538             : template<typename T>
    2539             : const T& NonNullHelper(const NonNull<T>& aArg)
    2540             : {
    2541             :   return aArg;
    2542             : }
    2543             : 
    2544             : template<typename T>
    2545             : T& NonNullHelper(OwningNonNull<T>& aArg)
    2546             : {
    2547             :   return aArg;
    2548             : }
    2549             : 
    2550             : template<typename T>
    2551             : const T& NonNullHelper(const OwningNonNull<T>& aArg)
    2552             : {
    2553             :   return aArg;
    2554             : }
    2555             : 
    2556             : inline
    2557             : void NonNullHelper(NonNull<binding_detail::FakeString>& aArg)
    2558             : {
    2559             :   // This overload is here to make sure that we never end up applying
    2560             :   // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
    2561             :   // try to, it should fail to compile, since presumably the caller will try to
    2562             :   // use our nonexistent return value.
    2563             : }
    2564             : 
    2565             : inline
    2566             : void NonNullHelper(const NonNull<binding_detail::FakeString>& aArg)
    2567             : {
    2568             :   // This overload is here to make sure that we never end up applying
    2569             :   // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
    2570             :   // try to, it should fail to compile, since presumably the caller will try to
    2571             :   // use our nonexistent return value.
    2572             : }
    2573             : 
    2574             : inline
    2575             : void NonNullHelper(binding_detail::FakeString& aArg)
    2576             : {
    2577             :   // This overload is here to make sure that we never end up applying
    2578             :   // NonNullHelper to a FakeString before we've constified it.  If we
    2579             :   // try to, it should fail to compile, since presumably the caller will try to
    2580             :   // use our nonexistent return value.
    2581             : }
    2582             : 
    2583             : MOZ_ALWAYS_INLINE
    2584             : const nsAString& NonNullHelper(const binding_detail::FakeString& aArg)
    2585             : {
    2586             :   return aArg;
    2587             : }
    2588             : 
    2589             : // Reparent the wrapper of aObj to whatever its native now thinks its
    2590             : // parent should be.
    2591             : void
    2592             : ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObj, ErrorResult& aError);
    2593             : 
    2594             : /**
    2595             :  * Used to implement the Symbol.hasInstance property of an interface object.
    2596             :  */
    2597             : bool
    2598             : InterfaceHasInstance(JSContext* cx, unsigned argc, JS::Value* vp);
    2599             : 
    2600             : bool
    2601             : InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
    2602             :                      JS::Handle<JSObject*> instance,
    2603             :                      bool* bp);
    2604             : 
    2605             : // Used to implement the cross-context <Interface>.isInstance static method.
    2606             : bool
    2607             : InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp);
    2608             : 
    2609             : // Helper for lenient getters/setters to report to console.  If this
    2610             : // returns false, we couldn't even get a global.
    2611             : bool
    2612             : ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj);
    2613             : 
    2614             : // Given a JSObject* that represents the chrome side of a JS-implemented WebIDL
    2615             : // interface, get the nsIGlobalObject corresponding to the content side, if any.
    2616             : // A false return means an exception was thrown.
    2617             : bool
    2618             : GetContentGlobalForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
    2619             :                                        nsIGlobalObject** global);
    2620             : 
    2621             : void
    2622             : ConstructJSImplementation(const char* aContractId,
    2623             :                           nsIGlobalObject* aGlobal,
    2624             :                           JS::MutableHandle<JSObject*> aObject,
    2625             :                           ErrorResult& aRv);
    2626             : 
    2627             : already_AddRefed<nsIGlobalObject>
    2628             : ConstructJSImplementation(const char* aContractId,
    2629             :                           const GlobalObject& aGlobal,
    2630             :                           JS::MutableHandle<JSObject*> aObject,
    2631             :                           ErrorResult& aRv);
    2632             : 
    2633             : /**
    2634             :  * Convert an nsCString to jsval, returning true on success.
    2635             :  * These functions are intended for ByteString implementations.
    2636             :  * As such, the string is not UTF-8 encoded.  Any UTF8 strings passed to these
    2637             :  * methods will be mangled.
    2638             :  */
    2639             : bool NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
    2640             :                               JS::MutableHandle<JS::Value> rval);
    2641             : inline bool ByteStringToJsval(JSContext *cx, const nsACString &str,
    2642             :                               JS::MutableHandle<JS::Value> rval)
    2643             : {
    2644             :     if (str.IsVoid()) {
    2645             :         rval.setNull();
    2646             :         return true;
    2647             :     }
    2648             :     return NonVoidByteStringToJsval(cx, str, rval);
    2649             : }
    2650             : 
    2651             : template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
    2652             : struct PreserveWrapperHelper
    2653             : {
    2654             :   static void PreserveWrapper(T* aObject)
    2655             :   {
    2656             :     aObject->PreserveWrapper(aObject, NS_CYCLE_COLLECTION_PARTICIPANT(T));
    2657             :   }
    2658             : };
    2659             : 
    2660             : template<class T>
    2661             : struct PreserveWrapperHelper<T, true>
    2662             : {
    2663             :   static void PreserveWrapper(T* aObject)
    2664             :   {
    2665             :     aObject->PreserveWrapper(reinterpret_cast<nsISupports*>(aObject));
    2666             :   }
    2667             : };
    2668             : 
    2669             : template<class T>
    2670             : void PreserveWrapper(T* aObject)
    2671             : {
    2672             :   PreserveWrapperHelper<T>::PreserveWrapper(aObject);
    2673             : }
    2674             : 
    2675             : template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
    2676             : struct CastingAssertions
    2677             : {
    2678             :   static bool ToSupportsIsCorrect(T*)
    2679             :   {
    2680             :     return true;
    2681             :   }
    2682             :   static bool ToSupportsIsOnPrimaryInheritanceChain(T*, nsWrapperCache*)
    2683             :   {
    2684             :     return true;
    2685             :   }
    2686             : };
    2687             : 
    2688             : template<class T>
    2689             : struct CastingAssertions<T, true>
    2690             : {
    2691             :   static bool ToSupportsIsCorrect(T* aObject)
    2692             :   {
    2693             :     return ToSupports(aObject) ==  reinterpret_cast<nsISupports*>(aObject);
    2694             :   }
    2695             :   static bool ToSupportsIsOnPrimaryInheritanceChain(T* aObject,
    2696             :                                                     nsWrapperCache* aCache)
    2697             :   {
    2698             :     return reinterpret_cast<void*>(aObject) != aCache;
    2699             :   }
    2700             : };
    2701             : 
    2702             : template<class T>
    2703             : bool
    2704             : ToSupportsIsCorrect(T* aObject)
    2705             : {
    2706             :   return CastingAssertions<T>::ToSupportsIsCorrect(aObject);
    2707             : }
    2708             : 
    2709             : template<class T>
    2710             : bool
    2711             : ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache)
    2712             : {
    2713             :   return CastingAssertions<T>::ToSupportsIsOnPrimaryInheritanceChain(aObject,
    2714             :                                                                      aCache);
    2715             : }
    2716             : 
    2717             : // Get the size of allocated memory to associate with a binding JSObject for a
    2718             : // native object. This is supplied to the JS engine to allow it to schedule GC
    2719             : // when necessary.
    2720             : //
    2721             : // This function supplies a default value and is overloaded for specific native
    2722             : // object types.
    2723             : inline size_t
    2724             : BindingJSObjectMallocBytes(void *aNativePtr)
    2725             : {
    2726             :   return 0;
    2727             : }
    2728             : 
    2729             : // The BindingJSObjectCreator class is supposed to be used by a caller that
    2730             : // wants to create and initialise a binding JSObject. After initialisation has
    2731             : // been successfully completed it should call ForgetObject().
    2732             : // The BindingJSObjectCreator object will root the JSObject until ForgetObject()
    2733             : // is called on it. If the native object for the binding is refcounted it will
    2734             : // also hold a strong reference to it, that reference is transferred to the
    2735             : // JSObject (which holds the native in a slot) when ForgetObject() is called. If
    2736             : // the BindingJSObjectCreator object is destroyed and ForgetObject() was never
    2737             : // called on it then the JSObject's slot holding the native will be set to
    2738             : // undefined, and for a refcounted native the strong reference will be released.
    2739             : template<class T>
    2740             : class MOZ_STACK_CLASS BindingJSObjectCreator
    2741             : {
    2742             : public:
    2743             :   explicit BindingJSObjectCreator(JSContext* aCx)
    2744             :     : mReflector(aCx)
    2745             :   {
    2746             :   }
    2747             : 
    2748             :   ~BindingJSObjectCreator()
    2749             :   {
    2750             :     if (mReflector) {
    2751             :       js::SetReservedSlot(mReflector, DOM_OBJECT_SLOT, JS::UndefinedValue());
    2752             :     }
    2753             :   }
    2754             : 
    2755             :   void
    2756             :   CreateProxyObject(JSContext* aCx, const js::Class* aClass,
    2757             :                     const DOMProxyHandler* aHandler,
    2758             :                     JS::Handle<JSObject*> aProto, T* aNative,
    2759             :                     JS::Handle<JS::Value> aExpandoValue,
    2760             :                     JS::MutableHandle<JSObject*> aReflector)
    2761             :   {
    2762             :     js::ProxyOptions options;
    2763             :     options.setClass(aClass);
    2764             :     aReflector.set(js::NewProxyObject(aCx, aHandler, aExpandoValue, aProto,
    2765             :                                       options));
    2766             :     if (aReflector) {
    2767             :       js::SetProxyReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
    2768             :       mNative = aNative;
    2769             :       mReflector = aReflector;
    2770             :     }
    2771             : 
    2772             :     if (size_t mallocBytes = BindingJSObjectMallocBytes(aNative)) {
    2773             :       JS_updateMallocCounter(aCx, mallocBytes);
    2774             :     }
    2775             :   }
    2776             : 
    2777             :   void
    2778             :   CreateObject(JSContext* aCx, const JSClass* aClass,
    2779             :                JS::Handle<JSObject*> aProto,
    2780             :                T* aNative, JS::MutableHandle<JSObject*> aReflector)
    2781             :   {
    2782             :     aReflector.set(JS_NewObjectWithGivenProto(aCx, aClass, aProto));
    2783             :     if (aReflector) {
    2784             :       js::SetReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
    2785             :       mNative = aNative;
    2786             :       mReflector = aReflector;
    2787             :     }
    2788             : 
    2789             :     if (size_t mallocBytes = BindingJSObjectMallocBytes(aNative)) {
    2790             :       JS_updateMallocCounter(aCx, mallocBytes);
    2791             :     }
    2792             :   }
    2793             : 
    2794             :   void
    2795             :   InitializationSucceeded()
    2796             :   {
    2797             :     void* dummy;
    2798             :     mNative.forget(&dummy);
    2799             :     mReflector = nullptr;
    2800             :   }
    2801             : 
    2802             : private:
    2803             :   struct OwnedNative
    2804             :   {
    2805             :     // Make sure the native objects inherit from NonRefcountedDOMObject so
    2806             :     // that we log their ctor and dtor.
    2807             :     static_assert(IsBaseOf<NonRefcountedDOMObject, T>::value,
    2808             :                   "Non-refcounted objects with DOM bindings should inherit "
    2809             :                   "from NonRefcountedDOMObject.");
    2810             : 
    2811             :     OwnedNative&
    2812             :     operator=(T* aNative)
    2813             :     {
    2814             :       return *this;
    2815             :     }
    2816             : 
    2817             :     // This signature sucks, but it's the only one that will make a nsRefPtr
    2818             :     // just forget about its pointer without warning.
    2819             :     void
    2820             :     forget(void**)
    2821             :     {
    2822             :     }
    2823             :   };
    2824             : 
    2825             :   JS::Rooted<JSObject*> mReflector;
    2826             :   typename Conditional<IsRefcounted<T>::value, RefPtr<T>, OwnedNative>::Type mNative;
    2827             : };
    2828             : 
    2829             : template<class T>
    2830             : struct DeferredFinalizerImpl
    2831             : {
    2832             :   typedef typename Conditional<IsSame<T, nsISupports>::value,
    2833             :                                nsCOMPtr<T>,
    2834             :                                typename Conditional<IsRefcounted<T>::value,
    2835             :                                                     RefPtr<T>,
    2836             :                                                     nsAutoPtr<T>>::Type>::Type SmartPtr;
    2837             :   typedef SegmentedVector<SmartPtr> SmartPtrArray;
    2838             : 
    2839             :   static_assert(IsSame<T, nsISupports>::value || !IsBaseOf<nsISupports, T>::value,
    2840             :                 "nsISupports classes should all use the nsISupports instantiation");
    2841             : 
    2842             :   static inline void
    2843             :   AppendAndTake(SegmentedVector<nsCOMPtr<nsISupports>>& smartPtrArray, nsISupports* ptr)
    2844             :   {
    2845             :     smartPtrArray.InfallibleAppend(dont_AddRef(ptr));
    2846             :   }
    2847             :   template<class U>
    2848             :   static inline void
    2849             :   AppendAndTake(SegmentedVector<RefPtr<U>>& smartPtrArray, U* ptr)
    2850             :   {
    2851             :     smartPtrArray.InfallibleAppend(dont_AddRef(ptr));
    2852             :   }
    2853             :   template<class U>
    2854             :   static inline void
    2855             :   AppendAndTake(SegmentedVector<nsAutoPtr<U>>& smartPtrArray, U* ptr)
    2856             :   {
    2857           0 :     smartPtrArray.InfallibleAppend(ptr);
    2858             :   }
    2859             : 
    2860             :   static void*
    2861           0 :   AppendDeferredFinalizePointer(void* aData, void* aObject)
    2862             :   {
    2863           0 :     SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
    2864           0 :     if (!pointers) {
    2865           0 :       pointers = new SmartPtrArray();
    2866             :     }
    2867           0 :     AppendAndTake(*pointers, static_cast<T*>(aObject));
    2868           0 :     return pointers;
    2869             :   }
    2870             :   static bool
    2871           0 :   DeferredFinalize(uint32_t aSlice, void* aData)
    2872             :   {
    2873           0 :     MOZ_ASSERT(aSlice > 0, "nonsensical/useless call with aSlice == 0");
    2874           0 :     SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
    2875           0 :     uint32_t oldLen = pointers->Length();
    2876           0 :     if (oldLen < aSlice) {
    2877           0 :       aSlice = oldLen;
    2878             :     }
    2879           0 :     uint32_t newLen = oldLen - aSlice;
    2880           0 :     pointers->PopLastN(aSlice);
    2881           0 :     if (newLen == 0) {
    2882           0 :       delete pointers;
    2883             :       return true;
    2884             :     }
    2885             :     return false;
    2886             :   }
    2887             : };
    2888             : 
    2889             : template<class T,
    2890             :          bool isISupports=IsBaseOf<nsISupports, T>::value>
    2891             : struct DeferredFinalizer
    2892             : {
    2893             :   static void
    2894           0 :   AddForDeferredFinalization(T* aObject)
    2895             :   {
    2896             :     typedef DeferredFinalizerImpl<T> Impl;
    2897           0 :     DeferredFinalize(Impl::AppendDeferredFinalizePointer,
    2898             :                      Impl::DeferredFinalize, aObject);
    2899           0 :   }
    2900             : };
    2901             : 
    2902             : template<class T>
    2903             : struct DeferredFinalizer<T, true>
    2904             : {
    2905             :   static void
    2906             :   AddForDeferredFinalization(T* aObject)
    2907             :   {
    2908             :     DeferredFinalize(reinterpret_cast<nsISupports*>(aObject));
    2909             :   }
    2910             : };
    2911             : 
    2912             : template<class T>
    2913             : static void
    2914             : AddForDeferredFinalization(T* aObject)
    2915             : {
    2916           0 :   DeferredFinalizer<T>::AddForDeferredFinalization(aObject);
    2917             : }
    2918             : 
    2919             : // This returns T's CC participant if it participates in CC or null if it
    2920             : // doesn't. This also returns null for classes that don't inherit from
    2921             : // nsISupports (QI should be used to get the participant for those).
    2922             : template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
    2923             : class GetCCParticipant
    2924             : {
    2925             :   // Helper for GetCCParticipant for classes that participate in CC.
    2926             :   template<class U>
    2927             :   static constexpr nsCycleCollectionParticipant*
    2928             :   GetHelper(int, typename U::NS_CYCLE_COLLECTION_INNERCLASS* dummy=nullptr)
    2929             :   {
    2930             :     return T::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant();
    2931             :   }
    2932             :   // Helper for GetCCParticipant for classes that don't participate in CC.
    2933             :   template<class U>
    2934             :   static constexpr nsCycleCollectionParticipant*
    2935             :   GetHelper(double)
    2936             :   {
    2937             :     return nullptr;
    2938             :   }
    2939             : 
    2940             : public:
    2941             :   static constexpr nsCycleCollectionParticipant*
    2942             :   Get()
    2943             :   {
    2944             :     // Passing int() here will try to call the GetHelper that takes an int as
    2945             :     // its firt argument. If T doesn't participate in CC then substitution for
    2946             :     // the second argument (with a default value) will fail and because of
    2947             :     // SFINAE the next best match (the variant taking a double) will be called.
    2948             :     return GetHelper<T>(int());
    2949             :   }
    2950             : };
    2951             : 
    2952             : template<class T>
    2953             : class GetCCParticipant<T, true>
    2954             : {
    2955             : public:
    2956             :   static constexpr nsCycleCollectionParticipant*
    2957             :   Get()
    2958             :   {
    2959             :     return nullptr;
    2960             :   }
    2961             : };
    2962             : 
    2963             : void
    2964             : FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
    2965             : 
    2966             : bool
    2967             : ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
    2968             :               JS::Handle<jsid> aId, bool* aResolvedp);
    2969             : 
    2970             : bool
    2971             : MayResolveGlobal(const JSAtomState& aNames, jsid aId, JSObject* aMaybeObj);
    2972             : 
    2973             : bool
    2974             : EnumerateGlobal(JSContext* aCx, JS::HandleObject aObj,
    2975             :                 JS::AutoIdVector& aProperties, bool aEnumerableOnly);
    2976             : 
    2977             : 
    2978             : struct CreateGlobalOptionsGeneric
    2979             : {
    2980             :   static void TraceGlobal(JSTracer* aTrc, JSObject* aObj)
    2981             :   {
    2982             :     mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
    2983             :   }
    2984             :   static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
    2985             :   {
    2986             :     MOZ_ALWAYS_TRUE(TryPreserveWrapper(aGlobal));
    2987             : 
    2988             :     return true;
    2989             :   }
    2990             : };
    2991             : 
    2992             : struct CreateGlobalOptionsWithXPConnect
    2993             : {
    2994             :   static void TraceGlobal(JSTracer* aTrc, JSObject* aObj);
    2995             :   static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
    2996             : };
    2997             : 
    2998             : template <class T>
    2999             : using IsGlobalWithXPConnect =
    3000             :   IntegralConstant<bool,
    3001             :                    IsBaseOf<nsGlobalWindowInner, T>::value ||
    3002             :                    IsBaseOf<MessageManagerGlobal, T>::value>;
    3003             : 
    3004             : template <class T>
    3005             : struct CreateGlobalOptions
    3006             :   : Conditional<IsGlobalWithXPConnect<T>::value,
    3007             :                 CreateGlobalOptionsWithXPConnect,
    3008             :                 CreateGlobalOptionsGeneric>::Type
    3009             : {
    3010             :   static constexpr ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
    3011             :     ProtoAndIfaceCache::NonWindowLike;
    3012             : };
    3013             : 
    3014             : template <>
    3015             : struct CreateGlobalOptions<nsGlobalWindowInner>
    3016             :   : public CreateGlobalOptionsWithXPConnect
    3017             : {
    3018             :   static constexpr ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
    3019             :     ProtoAndIfaceCache::WindowLike;
    3020             :   static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
    3021             : };
    3022             : 
    3023             : // The return value is true if we created and successfully performed our part of
    3024             : // the setup for the global, false otherwise.
    3025             : //
    3026             : // Typically this method's caller will want to ensure that
    3027             : // xpc::InitGlobalObjectOptions is called before, and xpc::InitGlobalObject is
    3028             : // called after, this method, to ensure that this global object and its
    3029             : // compartment are consistent with other global objects.
    3030             : template <class T, ProtoHandleGetter GetProto>
    3031             : bool
    3032             : CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
    3033             :              const JSClass* aClass, JS::RealmOptions& aOptions,
    3034             :              JSPrincipals* aPrincipal, bool aInitStandardClasses,
    3035             :              JS::MutableHandle<JSObject*> aGlobal)
    3036             : {
    3037             :   aOptions.creationOptions().setTrace(CreateGlobalOptions<T>::TraceGlobal);
    3038             :   if (xpc::SharedMemoryEnabled()) {
    3039             :     aOptions.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
    3040             :   }
    3041             : 
    3042             :   aGlobal.set(JS_NewGlobalObject(aCx, aClass, aPrincipal,
    3043             :                                  JS::DontFireOnNewGlobalHook, aOptions));
    3044             :   if (!aGlobal) {
    3045             :     NS_WARNING("Failed to create global");
    3046             :     return false;
    3047             :   }
    3048             : 
    3049             :   JSAutoRealm ar(aCx, aGlobal);
    3050             : 
    3051             :   {
    3052             :     js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
    3053             :     NS_ADDREF(aNative);
    3054             : 
    3055             :     aCache->SetWrapper(aGlobal);
    3056             : 
    3057             :     dom::AllocateProtoAndIfaceCache(aGlobal,
    3058             :                                     CreateGlobalOptions<T>::ProtoAndIfaceCacheKind);
    3059             : 
    3060             :     if (!CreateGlobalOptions<T>::PostCreateGlobal(aCx, aGlobal)) {
    3061             :       return false;
    3062             :     }
    3063             :   }
    3064             : 
    3065             :   if (aInitStandardClasses && !JS::InitRealmStandardClasses(aCx)) {
    3066             :     NS_WARNING("Failed to init standard classes");
    3067             :     return false;
    3068             :   }
    3069             : 
    3070             :   JS::Handle<JSObject*> proto = GetProto(aCx);
    3071             :   if (!proto || !JS_SplicePrototype(aCx, aGlobal, proto)) {
    3072             :     NS_WARNING("Failed to set proto");
    3073             :     return false;
    3074             :   }
    3075             : 
    3076             :   bool succeeded;
    3077             :   if (!JS_SetImmutablePrototype(aCx, aGlobal, &succeeded)) {
    3078             :     return false;
    3079             :   }
    3080             :   MOZ_ASSERT(succeeded,
    3081             :              "making a fresh global object's [[Prototype]] immutable can "
    3082             :              "internally fail, but it should never be unsuccessful");
    3083             : 
    3084             :   return true;
    3085             : }
    3086             : 
    3087             : /*
    3088             :  * Holds a jsid that is initialized to a pinned string, with automatic
    3089             :  * conversion to Handle<jsid>, as it is held live forever by pinning.
    3090             :  */
    3091             : class PinnedStringId
    3092             : {
    3093             :   jsid id;
    3094             : 
    3095             :  public:
    3096             :   constexpr PinnedStringId() : id(JSID_VOID) {}
    3097             : 
    3098             :   bool init(JSContext *cx, const char *string) {
    3099             :     JSString* str = JS_AtomizeAndPinString(cx, string);
    3100             :     if (!str)
    3101             :       return false;
    3102             :     id = INTERNED_STRING_TO_JSID(cx, str);
    3103             :     return true;
    3104             :   }
    3105             : 
    3106             :   operator const jsid& () const {
    3107             :     return id;
    3108             :   }
    3109             : 
    3110             :   operator JS::Handle<jsid> () const {
    3111             :     /* This is safe because we have pinned the string. */
    3112             :     return JS::Handle<jsid>::fromMarkedLocation(&id);
    3113             :   }
    3114             : } JS_HAZ_ROOTED;
    3115             : 
    3116             : namespace binding_detail {
    3117             : /**
    3118             :  * WebIDL getters have a "generic" JSNative that is responsible for the
    3119             :  * following things:
    3120             :  *
    3121             :  * 1) Determining the "this" pointer for the C++ call.
    3122             :  * 2) Extracting the "specialized" getter from the jitinfo on the JSFunction.
    3123             :  * 3) Calling the specialized getter.
    3124             :  * 4) Handling exceptions as needed.
    3125             :  *
    3126             :  * There are several variants of (1) depending on the interface involved and
    3127             :  * there are two variants of (4) depending on whether the return type is a
    3128             :  * Promise.  We handle this by templating our generic getter on a
    3129             :  * this-determination policy and an exception handling policy, then explicitly
    3130             :  * instantiating the relevant template specializations.
    3131             :  */
    3132             : template<typename ThisPolicy, typename ExceptionPolicy>
    3133             : bool
    3134             : GenericGetter(JSContext* cx, unsigned argc, JS::Value* vp);
    3135             : 
    3136             : /**
    3137             :  * WebIDL setters have a "generic" JSNative that is responsible for the
    3138             :  * following things:
    3139             :  *
    3140             :  * 1) Determining the "this" pointer for the C++ call.
    3141             :  * 2) Extracting the "specialized" setter from the jitinfo on the JSFunction.
    3142             :  * 3) Calling the specialized setter.
    3143             :  *
    3144             :  * There are several variants of (1) depending on the interface
    3145             :  * involved.  We handle this by templating our generic setter on a
    3146             :  * this-determination policy, then explicitly instantiating the
    3147             :  * relevant template specializations.
    3148             :  */
    3149             : template<typename ThisPolicy>
    3150             : bool
    3151             : GenericSetter(JSContext* cx, unsigned argc, JS::Value* vp);
    3152             : 
    3153             : /**
    3154             :  * WebIDL methods have a "generic" JSNative that is responsible for the
    3155             :  * following things:
    3156             :  *
    3157             :  * 1) Determining the "this" pointer for the C++ call.
    3158             :  * 2) Extracting the "specialized" method from the jitinfo on the JSFunction.
    3159             :  * 3) Calling the specialized methodx.
    3160             :  * 4) Handling exceptions as needed.
    3161             :  *
    3162             :  * There are several variants of (1) depending on the interface involved and
    3163             :  * there are two variants of (4) depending on whether the return type is a
    3164             :  * Promise.  We handle this by templating our generic method on a
    3165             :  * this-determination policy and an exception handling policy, then explicitly
    3166             :  * instantiating the relevant template specializations.
    3167             :  */
    3168             : template<typename ThisPolicy, typename ExceptionPolicy>
    3169             : bool
    3170             : GenericMethod(JSContext* cx, unsigned argc, JS::Value* vp);
    3171             : 
    3172             : // A this-extraction policy for normal getters/setters/methods.
    3173             : struct NormalThisPolicy;
    3174             : 
    3175             : // A this-extraction policy for getters/setters/methods on interfaces
    3176             : // that are on some global's proto chain.
    3177             : struct MaybeGlobalThisPolicy;
    3178             : 
    3179             : // A this-extraction policy for lenient getters/setters.
    3180             : struct LenientThisPolicy;
    3181             : 
    3182             : // A this-extraction policy for cross-origin getters/setters/methods.
    3183             : struct CrossOriginThisPolicy;
    3184             : 
    3185             : // An exception-reporting policy for normal getters/setters/methods.
    3186             : struct ThrowExceptions;
    3187             : 
    3188             : // An exception-handling policy for Promise-returning getters/methods.
    3189             : struct ConvertExceptionsToPromises;
    3190             : } // namespace binding_detail
    3191             : 
    3192             : bool
    3193             : StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp);
    3194             : 
    3195             : // ConvertExceptionToPromise should only be called when we have an error
    3196             : // condition (e.g. returned false from a JSAPI method).  Note that there may be
    3197             : // no exception on cx, in which case this is an uncatchable failure that will
    3198             : // simply be propagated.  Otherwise this method will attempt to convert the
    3199             : // exception to a Promise rejected with the exception that it will store in
    3200             : // rval.
    3201             : bool
    3202             : ConvertExceptionToPromise(JSContext* cx,
    3203             :                           JS::MutableHandle<JS::Value> rval);
    3204             : 
    3205             : #ifdef DEBUG
    3206             : void
    3207             : AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
    3208             :                                JS::Handle<JS::Value> aValue);
    3209             : #endif
    3210             : 
    3211             : bool
    3212             : CallerSubsumes(JSObject* aObject);
    3213             : 
    3214             : MOZ_ALWAYS_INLINE bool
    3215             : CallerSubsumes(JS::Handle<JS::Value> aValue)
    3216             : {
    3217             :   if (!aValue.isObject()) {
    3218             :     return true;
    3219             :   }
    3220             :   return CallerSubsumes(&aValue.toObject());
    3221             : }
    3222             : 
    3223             : template<class T>
    3224             : inline bool
    3225             : WrappedJSToDictionary(JSContext* aCx, nsISupports* aObject, T& aDictionary)
    3226             : {
    3227             :   nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
    3228             :   if (!wrappedObj) {
    3229             :     return false;
    3230             :   }
    3231             : 
    3232             :   JS::Rooted<JSObject*> obj(aCx, wrappedObj->GetJSObject());
    3233             :   if (!obj) {
    3234             :     return false;
    3235             :   }
    3236             : 
    3237             :   JSAutoRealm ar(aCx, obj);
    3238             :   JS::Rooted<JS::Value> v(aCx, JS::ObjectValue(*obj));
    3239             :   return aDictionary.Init(aCx, v);
    3240             : }
    3241             : 
    3242             : template<class T>
    3243             : inline bool
    3244             : WrappedJSToDictionary(nsISupports* aObject, T& aDictionary)
    3245             : {
    3246             :   nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
    3247             :   NS_ENSURE_TRUE(wrappedObj, false);
    3248             :   JS::Rooted<JSObject*> obj(RootingCx(), wrappedObj->GetJSObject());
    3249             :   NS_ENSURE_TRUE(obj, false);
    3250             : 
    3251             :   nsIGlobalObject* global = xpc::NativeGlobal(obj);
    3252             :   NS_ENSURE_TRUE(global, false);
    3253             : 
    3254             :   // we need this AutoEntryScript here because the spec requires us to execute
    3255             :   // getters when parsing a dictionary
    3256             :   AutoEntryScript aes(global, "WebIDL dictionary creation");
    3257             : 
    3258             :   JS::Rooted<JS::Value> v(aes.cx(), JS::ObjectValue(*obj));
    3259             :   return aDictionary.Init(aes.cx(), v);
    3260             : }
    3261             : 
    3262             : 
    3263             : template<class T, class S>
    3264             : inline RefPtr<T>
    3265             : StrongOrRawPtr(already_AddRefed<S>&& aPtr)
    3266             : {
    3267             :   return std::move(aPtr);
    3268             : }
    3269             : 
    3270             : template<class T,
    3271             :          class ReturnType=typename Conditional<IsRefcounted<T>::value, T*,
    3272             :                                                nsAutoPtr<T>>::Type>
    3273             : inline ReturnType
    3274             : StrongOrRawPtr(T* aPtr)
    3275             : {
    3276             :   return ReturnType(aPtr);
    3277             : }
    3278             : 
    3279             : template<class T, template<typename> class SmartPtr, class S>
    3280             : inline void
    3281             : StrongOrRawPtr(SmartPtr<S>&& aPtr) = delete;
    3282             : 
    3283             : template<class T>
    3284             : struct StrongPtrForMember
    3285             : {
    3286             :   typedef typename Conditional<IsRefcounted<T>::value,
    3287             :                                RefPtr<T>, nsAutoPtr<T>>::Type Type;
    3288             : };
    3289             : 
    3290             : namespace binding_detail {
    3291             : inline
    3292             : JSObject*
    3293             : GetHackedNamespaceProtoObject(JSContext* aCx)
    3294             : {
    3295             :   return JS_NewPlainObject(aCx);
    3296             : }
    3297             : } // namespace binding_detail
    3298             : 
    3299             : // Resolve an id on the given global object that wants to be included in
    3300             : // Exposed=System webidl annotations.  False return value means exception
    3301             : // thrown.
    3302             : bool SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
    3303             :                          JS::Handle<jsid> id, bool* resolvedp);
    3304             : 
    3305             : // Enumerate all ids on the given global object that wants to be included in
    3306             : // Exposed=System webidl annotations.  False return value means exception
    3307             : // thrown.
    3308             : bool SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj);
    3309             : 
    3310             : // Slot indexes for maplike/setlike forEach functions
    3311             : #define FOREACH_CALLBACK_SLOT 0
    3312             : #define FOREACH_MAPLIKEORSETLIKEOBJ_SLOT 1
    3313             : 
    3314             : // Backing function for running .forEach() on maplike/setlike interfaces.
    3315             : // Unpacks callback and maplike/setlike object from reserved slots, then runs
    3316             : // callback for each key (and value, for maplikes)
    3317             : bool ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
    3318             : 
    3319             : // Unpacks backing object (ES6 map/set) from the reserved slot of a reflector
    3320             : // for a maplike/setlike interface. If backing object does not exist, creates
    3321             : // backing object in the compartment of the reflector involved, making this safe
    3322             : // to use across compartments/via xrays. Return values of these methods will
    3323             : // always be in the context compartment.
    3324             : bool GetMaplikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
    3325             :                              size_t aSlotIndex,
    3326             :                              JS::MutableHandle<JSObject*> aBackingObj,
    3327             :                              bool* aBackingObjCreated);
    3328             : bool GetSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
    3329             :                              size_t aSlotIndex,
    3330             :                              JS::MutableHandle<JSObject*> aBackingObj,
    3331             :                              bool* aBackingObjCreated);
    3332             : 
    3333             : // Get the desired prototype object for an object construction from the given
    3334             : // CallArgs.  Null is returned if the default prototype should be used.
    3335             : bool
    3336             : GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
    3337             :                 JS::MutableHandle<JSObject*> aDesiredProto);
    3338             : 
    3339             : // This function is expected to be called from the constructor function for an
    3340             : // HTML or XUL element interface; the global/callargs need to be whatever was
    3341             : // passed to that constructor function.
    3342             : already_AddRefed<Element>
    3343             : CreateXULOrHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
    3344             :                        JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv);
    3345             : 
    3346             : void
    3347             : SetDocumentAndPageUseCounter(JSObject* aObject, UseCounter aUseCounter);
    3348             : 
    3349             : // Warnings
    3350             : void
    3351             : DeprecationWarning(JSContext* aCx, JSObject* aObject,
    3352             :                    nsIDocument::DeprecatedOperations aOperation);
    3353             : 
    3354             : void
    3355             : DeprecationWarning(const GlobalObject& aGlobal,
    3356             :                    nsIDocument::DeprecatedOperations aOperation);
    3357             : 
    3358             : // A callback to perform funToString on an interface object
    3359             : JSString*
    3360             : InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
    3361             :                         unsigned /* indent */);
    3362             : 
    3363             : namespace binding_detail {
    3364             : // Get a JS global object that can be used for some temporary allocations.  The
    3365             : // idea is that this should be used for situations when you need to operate in
    3366             : // _some_ compartment but don't care which one.  A typical example is when you
    3367             : // have non-JS input, non-JS output, but have to go through some sort of JS
    3368             : // representation in the middle, so need a compartment to allocate things in.
    3369             : //
    3370             : // It's VERY important that any consumers of this function only do things that
    3371             : // are guaranteed to be side-effect-free, even in the face of a script
    3372             : // environment controlled by a hostile adversary.  This is because in the worker
    3373             : // case the global is in fact the worker global, so it and its standard objects
    3374             : // are controlled by the worker script.  This is why this function is in the
    3375             : // binding_detail namespace.  Any use of this function MUST be very carefully
    3376             : // reviewed by someone who is sufficiently devious and has a very good
    3377             : // understanding of all the code that will run while we're using the return
    3378             : // value, including the SpiderMonkey parts.
    3379             : JSObject* UnprivilegedJunkScopeOrWorkerGlobal();
    3380             : 
    3381             : // Implementation of the [HTMLConstructor] extended attribute.
    3382             : bool
    3383             : HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
    3384             :                 constructors::id::ID aConstructorId,
    3385             :                 prototypes::id::ID aProtoId,
    3386             :                 CreateInterfaceObjectsMethod aCreator);
    3387             : 
    3388             : // A method to test whether an attribute with the given JSJitGetterOp getter is
    3389             : // enabled in the given set of prefable proeprty specs.  For use for toJSON
    3390             : // conversions.  aObj is the object that would be used as the "this" value.
    3391             : bool
    3392             : IsGetterEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj,
    3393             :                 JSJitGetterOp aGetter,
    3394             :                 const Prefable<const JSPropertySpec>* aAttributes);
    3395             : } // namespace binding_detail
    3396             : 
    3397             : } // namespace dom
    3398             : } // namespace mozilla
    3399             : 
    3400             : #endif /* mozilla_dom_BindingUtils_h__ */

Generated by: LCOV version 1.13-14-ga5dd952