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