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

Generated by: LCOV version 1.13