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