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