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