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/. */
7 #ifndef mozilla_dom_BindingUtils_h__
8 #define mozilla_dom_BindingUtils_h__
10 #include <type_traits>
12 #include "jsfriendapi.h"
13 #include "js/CharacterEncoding.h"
14 #include "js/Conversions.h"
15 #include "js/experimental/JitInfo.h" // JSJitGetterOp, JSJitInfo
16 #include "js/friend/WindowProxy.h" // js::IsWindow, js::IsWindowProxy, js::ToWindowProxyIfWindow
17 #include "js/MemoryFunctions.h"
18 #include "js/Object.h" // JS::GetClass, JS::GetCompartment, JS::GetReservedSlot, JS::SetReservedSlot
19 #include "js/RealmOptions.h"
20 #include "js/String.h" // JS::GetLatin1LinearStringChars, JS::GetTwoByteLinearStringChars, JS::GetLinearStringLength, JS::LinearStringHasLatin1Chars, JS::StringHasLatin1Chars
21 #include "js/Wrapper.h"
23 #include "mozilla/ArrayUtils.h"
24 #include "mozilla/Array.h"
25 #include "mozilla/Assertions.h"
26 #include "mozilla/DeferredFinalize.h"
27 #include "mozilla/UniquePtr.h"
28 #include "mozilla/dom/BindingCallContext.h"
29 #include "mozilla/dom/BindingDeclarations.h"
30 #include "mozilla/dom/DOMJSClass.h"
31 #include "mozilla/dom/DOMJSProxyHandler.h"
32 #include "mozilla/dom/JSSlots.h"
33 #include "mozilla/dom/NonRefcountedDOMObject.h"
34 #include "mozilla/dom/Nullable.h"
35 #include "mozilla/dom/PrototypeList.h"
36 #include "mozilla/dom/RemoteObjectProxy.h"
37 #include "mozilla/SegmentedVector.h"
38 #include "mozilla/ErrorResult.h"
39 #include "mozilla/Likely.h"
40 #include "mozilla/MemoryReporting.h"
41 #include "nsIGlobalObject.h"
42 #include "nsJSUtils.h"
43 #include "nsISupportsImpl.h"
44 #include "xpcObjectHelper.h"
45 #include "xpcpublic.h"
46 #include "nsIVariant.h"
47 #include "mozilla/dom/FakeString.h"
49 #include "nsWrapperCacheInlines.h"
51 class nsGlobalWindowInner
;
52 class nsGlobalWindowOuter
;
53 class nsIInterfaceRequestor
;
57 enum UseCounter
: int16_t;
58 enum class UseCounterWorker
: int16_t;
61 class CustomElementReactionsStack
;
64 class MessageManagerGlobal
;
65 class ObservableArrayProxyHandler
;
66 class DedicatedWorkerGlobalScope
;
67 template <typename KeyType
, typename ValueType
>
69 class WindowProxyHolder
;
71 enum class DeprecatedOperations
: uint16_t;
73 nsresult
UnwrapArgImpl(JSContext
* cx
, JS::Handle
<JSObject
*> src
,
74 const nsIID
& iid
, void** ppArg
);
76 /** Convert a jsval to an XPCOM pointer. Caller must not assume that src will
77 keep the XPCOM pointer rooted. */
78 template <class Interface
>
79 inline nsresult
UnwrapArg(JSContext
* cx
, JS::Handle
<JSObject
*> src
,
81 return UnwrapArgImpl(cx
, src
, NS_GET_TEMPLATE_IID(Interface
),
82 reinterpret_cast<void**>(ppArg
));
85 nsresult
UnwrapWindowProxyArg(JSContext
* cx
, JS::Handle
<JSObject
*> src
,
86 WindowProxyHolder
& ppArg
);
88 // Returns true if the JSClass is used for DOM objects.
89 inline bool IsDOMClass(const JSClass
* clasp
) {
90 return clasp
->flags
& JSCLASS_IS_DOMJSCLASS
;
93 // Return true if the JSClass is used for non-proxy DOM objects.
94 inline bool IsNonProxyDOMClass(const JSClass
* clasp
) {
95 return IsDOMClass(clasp
) && clasp
->isNativeObject();
98 // Returns true if the JSClass is used for DOM interface and interface
100 inline bool IsDOMIfaceAndProtoClass(const JSClass
* clasp
) {
101 return clasp
->flags
& JSCLASS_IS_DOMIFACEANDPROTOJSCLASS
;
104 static_assert(DOM_OBJECT_SLOT
== 0,
105 "DOM_OBJECT_SLOT doesn't match the proxy private slot. "
106 "Expect bad things");
108 inline T
* UnwrapDOMObject(JSObject
* obj
) {
109 MOZ_ASSERT(IsDOMClass(JS::GetClass(obj
)),
110 "Don't pass non-DOM objects to this function");
112 JS::Value val
= JS::GetReservedSlot(obj
, DOM_OBJECT_SLOT
);
113 return static_cast<T
*>(val
.toPrivate());
117 inline T
* UnwrapPossiblyNotInitializedDOMObject(JSObject
* obj
) {
118 // This is used by the OjectMoved JSClass hook which can be called before
119 // JS_NewObject has returned and so before we have a chance to set
120 // DOM_OBJECT_SLOT to anything useful.
122 MOZ_ASSERT(IsDOMClass(JS::GetClass(obj
)),
123 "Don't pass non-DOM objects to this function");
125 JS::Value val
= JS::GetReservedSlot(obj
, DOM_OBJECT_SLOT
);
126 if (val
.isUndefined()) {
129 return static_cast<T
*>(val
.toPrivate());
132 inline const DOMJSClass
* GetDOMClass(const JSClass
* clasp
) {
133 return IsDOMClass(clasp
) ? DOMJSClass::FromJSClass(clasp
) : nullptr;
136 inline const DOMJSClass
* GetDOMClass(JSObject
* obj
) {
137 return GetDOMClass(JS::GetClass(obj
));
140 inline nsISupports
* UnwrapDOMObjectToISupports(JSObject
* aObject
) {
141 const DOMJSClass
* clasp
= GetDOMClass(aObject
);
142 if (!clasp
|| !clasp
->mDOMObjectIsISupports
) {
146 return UnwrapPossiblyNotInitializedDOMObject
<nsISupports
>(aObject
);
149 inline bool IsDOMObject(JSObject
* obj
) { return IsDOMClass(JS::GetClass(obj
)); }
151 // There are two valid ways to use UNWRAP_OBJECT: Either obj needs to
152 // be a MutableHandle<JSObject*>, or value needs to be a strong-reference
153 // smart pointer type (OwningNonNull or RefPtr or nsCOMPtr), in which case obj
154 // can be anything that converts to JSObject*.
156 // This can't be used with Window, EventTarget, or Location as the "Interface"
157 // argument (and will fail a static_assert if you try to do that). Use
158 // UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT to unwrap to those interfaces.
159 #define UNWRAP_OBJECT(Interface, obj, value) \
160 mozilla::dom::binding_detail::UnwrapObjectWithCrossOriginAsserts< \
161 mozilla::dom::prototypes::id::Interface, \
162 mozilla::dom::Interface##_Binding::NativeType>(obj, value)
164 // UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT is just like UNWRAP_OBJECT but requires a
165 // JSContext in a Realm that represents "who is doing the unwrapping?" to
166 // properly unwrap the object.
167 #define UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT(Interface, obj, value, cx) \
168 mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface, \
169 mozilla::dom::Interface##_Binding::NativeType>( \
172 // Test whether the given object is an instance of the given interface.
173 #define IS_INSTANCE_OF(Interface, obj) \
174 mozilla::dom::IsInstanceOf<mozilla::dom::prototypes::id::Interface, \
175 mozilla::dom::Interface##_Binding::NativeType>( \
178 // Unwrap the given non-wrapper object. This can be used with any obj that
179 // converts to JSObject*; as long as that JSObject* is live the return value
181 #define UNWRAP_NON_WRAPPER_OBJECT(Interface, obj, value) \
182 mozilla::dom::UnwrapNonWrapperObject< \
183 mozilla::dom::prototypes::id::Interface, \
184 mozilla::dom::Interface##_Binding::NativeType>(obj, value)
186 // Some callers don't want to set an exception when unwrapping fails
187 // (for example, overload resolution uses unwrapping to tell what sort
188 // of thing it's looking at).
189 // U must be something that a T* can be assigned to (e.g. T* or an RefPtr<T>).
191 // The obj argument will be mutated to point to CheckedUnwrap of itself if the
192 // passed-in value is not a DOM object and CheckedUnwrap succeeds.
194 // If mayBeWrapper is true, there are three valid ways to invoke
195 // UnwrapObjectInternal: Either obj needs to be a class wrapping a
196 // MutableHandle<JSObject*>, with an assignment operator that sets the handle to
197 // the given object, or U needs to be a strong-reference smart pointer type
198 // (OwningNonNull or RefPtr or nsCOMPtr), or the value being stored in "value"
199 // must not escape past being tested for falsiness immediately after the
200 // UnwrapObjectInternal call.
202 // If mayBeWrapper is false, obj can just be a JSObject*, and U anything that a
203 // T* can be assigned to.
205 // The cx arg is in practice allowed to be either nullptr or JSContext* or a
206 // BindingCallContext reference. If it's nullptr we will do a
207 // CheckedUnwrapStatic and it's the caller's responsibility to make sure they're
208 // not trying to work with Window or Location objects. Otherwise we'll do a
209 // CheckedUnwrapDynamic. This all only matters if mayBeWrapper is true; if it's
210 // false just pass nullptr for the cx arg.
211 namespace binding_detail
{
212 template <class T
, bool mayBeWrapper
, typename U
, typename V
, typename CxType
>
213 MOZ_ALWAYS_INLINE nsresult
UnwrapObjectInternal(V
& obj
, U
& value
,
214 prototypes::ID protoID
,
217 static_assert(std::is_same_v
<CxType
, JSContext
*> ||
218 std::is_same_v
<CxType
, BindingCallContext
> ||
219 std::is_same_v
<CxType
, decltype(nullptr)>,
220 "Unexpected CxType");
222 /* First check to see whether we have a DOM object */
223 const DOMJSClass
* domClass
= GetDOMClass(obj
);
225 /* This object is a DOM object. Double-check that it is safely
226 castable to T by checking whether it claims to inherit from the
227 class identified by protoID. */
228 if (domClass
->mInterfaceChain
[protoDepth
] == protoID
) {
229 value
= UnwrapDOMObject
<T
>(obj
);
234 /* Maybe we have a security wrapper or outer window? */
235 if (!mayBeWrapper
|| !js::IsWrapper(obj
)) {
236 // For non-cross-origin-accessible methods and properties, remote object
237 // proxies should behave the same as opaque wrappers.
238 if (IsRemoteObjectProxy(obj
)) {
239 return NS_ERROR_XPC_SECURITY_MANAGER_VETO
;
242 /* Not a DOM object, not a wrapper, just bail */
243 return NS_ERROR_XPC_BAD_CONVERT_JS
;
246 JSObject
* unwrappedObj
;
247 if (std::is_same_v
<CxType
, decltype(nullptr)>) {
248 unwrappedObj
= js::CheckedUnwrapStatic(obj
);
251 js::CheckedUnwrapDynamic(obj
, cx
, /* stopAtWindowProxy = */ false);
254 return NS_ERROR_XPC_SECURITY_MANAGER_VETO
;
257 if (std::is_same_v
<CxType
, decltype(nullptr)>) {
258 // We might still have a windowproxy here. But it shouldn't matter, because
259 // that's not what the caller is looking for, so we're going to fail out
260 // anyway below once we do the recursive call to ourselves with wrapper
261 // unwrapping disabled.
262 MOZ_ASSERT(!js::IsWrapper(unwrappedObj
) || js::IsWindowProxy(unwrappedObj
));
264 // We shouldn't have a wrapper by now.
265 MOZ_ASSERT(!js::IsWrapper(unwrappedObj
));
268 // Recursive call is OK, because now we're using false for mayBeWrapper and
269 // we never reach this code if that boolean is false, so can't keep calling
272 // Unwrap into a temporary pointer, because in general unwrapping into
273 // something of type U might trigger GC (e.g. release the value currently
274 // stored in there, with arbitrary consequences) and invalidate the
275 // "unwrappedObj" pointer.
276 T
* tempValue
= nullptr;
277 nsresult rv
= UnwrapObjectInternal
<T
, false>(unwrappedObj
, tempValue
, protoID
,
278 protoDepth
, nullptr);
279 if (NS_SUCCEEDED(rv
)) {
280 // Suppress a hazard related to keeping tempValue alive across
281 // UnwrapObjectInternal, because the analysis can't tell that this function
282 // will not GC if maybeWrapped=False and we've already gone through a level
283 // of unwrapping so unwrappedObj will be !IsWrapper.
284 JS::AutoSuppressGCAnalysis suppress
;
286 // It's very important to not update "obj" with the "unwrappedObj" value
287 // until we know the unwrap has succeeded. Otherwise, in a situation in
288 // which we have an overload of object and primitive we could end up
289 // converting to the primitive from the unwrappedObj, whereas we want to do
290 // it from the original object.
292 // And now assign to "value"; at this point we don't care if a GC happens
293 // and invalidates unwrappedObj.
298 /* It's the wrong sort of DOM object */
299 return NS_ERROR_XPC_BAD_CONVERT_JS
;
302 struct MutableObjectHandleWrapper
{
303 explicit MutableObjectHandleWrapper(JS::MutableHandle
<JSObject
*> aHandle
)
304 : mHandle(aHandle
) {}
306 void operator=(JSObject
* aObject
) {
308 mHandle
.set(aObject
);
311 operator JSObject
*() const { return mHandle
; }
314 JS::MutableHandle
<JSObject
*> mHandle
;
317 struct MutableValueHandleWrapper
{
318 explicit MutableValueHandleWrapper(JS::MutableHandle
<JS::Value
> aHandle
)
319 : mHandle(aHandle
) {}
321 void operator=(JSObject
* aObject
) {
323 #ifdef ENABLE_RECORD_TUPLE
324 MOZ_ASSERT(!js::gc::MaybeForwardedIsExtendedPrimitive(*aObject
));
326 mHandle
.setObject(*aObject
);
329 operator JSObject
*() const { return &mHandle
.toObject(); }
332 JS::MutableHandle
<JS::Value
> mHandle
;
335 } // namespace binding_detail
337 // UnwrapObject overloads that ensure we have a MutableHandle to keep it alive.
338 template <prototypes::ID PrototypeID
, class T
, typename U
, typename CxType
>
339 MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JS::MutableHandle
<JSObject
*> obj
,
340 U
& value
, const CxType
& cx
) {
341 binding_detail::MutableObjectHandleWrapper
wrapper(obj
);
342 return binding_detail::UnwrapObjectInternal
<T
, true>(
343 wrapper
, value
, PrototypeID
, PrototypeTraits
<PrototypeID
>::Depth
, cx
);
346 template <prototypes::ID PrototypeID
, class T
, typename U
, typename CxType
>
347 MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JS::MutableHandle
<JS::Value
> obj
,
348 U
& value
, const CxType
& cx
) {
349 MOZ_ASSERT(obj
.isObject());
350 binding_detail::MutableValueHandleWrapper
wrapper(obj
);
351 return binding_detail::UnwrapObjectInternal
<T
, true>(
352 wrapper
, value
, PrototypeID
, PrototypeTraits
<PrototypeID
>::Depth
, cx
);
355 // UnwrapObject overloads that ensure we have a strong ref to keep it alive.
356 template <prototypes::ID PrototypeID
, class T
, typename U
, typename CxType
>
357 MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject
* obj
, RefPtr
<U
>& value
,
359 return binding_detail::UnwrapObjectInternal
<T
, true>(
360 obj
, value
, PrototypeID
, PrototypeTraits
<PrototypeID
>::Depth
, cx
);
363 template <prototypes::ID PrototypeID
, class T
, typename U
, typename CxType
>
364 MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject
* obj
, nsCOMPtr
<U
>& value
,
366 return binding_detail::UnwrapObjectInternal
<T
, true>(
367 obj
, value
, PrototypeID
, PrototypeTraits
<PrototypeID
>::Depth
, cx
);
370 template <prototypes::ID PrototypeID
, class T
, typename U
, typename CxType
>
371 MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject
* obj
, OwningNonNull
<U
>& value
,
373 return binding_detail::UnwrapObjectInternal
<T
, true>(
374 obj
, value
, PrototypeID
, PrototypeTraits
<PrototypeID
>::Depth
, cx
);
377 template <prototypes::ID PrototypeID
, class T
, typename U
, typename CxType
>
378 MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject
* obj
, NonNull
<U
>& value
,
380 return binding_detail::UnwrapObjectInternal
<T
, true>(
381 obj
, value
, PrototypeID
, PrototypeTraits
<PrototypeID
>::Depth
, cx
);
384 // An UnwrapObject overload that just calls one of the JSObject* ones.
385 template <prototypes::ID PrototypeID
, class T
, typename U
, typename CxType
>
386 MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JS::Handle
<JS::Value
> obj
, U
& value
,
388 MOZ_ASSERT(obj
.isObject());
389 return UnwrapObject
<PrototypeID
, T
>(&obj
.toObject(), value
, cx
);
392 template <prototypes::ID PrototypeID
, class T
, typename U
, typename CxType
>
393 MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JS::Handle
<JS::Value
> obj
,
394 NonNull
<U
>& value
, const CxType
& cx
) {
395 MOZ_ASSERT(obj
.isObject());
396 return UnwrapObject
<PrototypeID
, T
>(&obj
.toObject(), value
, cx
);
399 template <prototypes::ID PrototypeID
>
400 MOZ_ALWAYS_INLINE
void AssertStaticUnwrapOK() {
401 static_assert(PrototypeID
!= prototypes::id::Window
,
402 "Can't do static unwrap of WindowProxy; use "
403 "UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT or a cross-origin-object "
404 "aware version of IS_INSTANCE_OF");
405 static_assert(PrototypeID
!= prototypes::id::EventTarget
,
406 "Can't do static unwrap of WindowProxy (which an EventTarget "
407 "might be); use UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT or a "
408 "cross-origin-object aware version of IS_INSTANCE_OF");
409 static_assert(PrototypeID
!= prototypes::id::Location
,
410 "Can't do static unwrap of Location; use "
411 "UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT or a cross-origin-object "
412 "aware version of IS_INSTANCE_OF");
415 namespace binding_detail
{
416 // This function is just here so we can do some static asserts in a centralized
417 // place instead of putting them in every single UnwrapObject overload.
418 template <prototypes::ID PrototypeID
, class T
, typename U
, typename V
>
419 MOZ_ALWAYS_INLINE nsresult
UnwrapObjectWithCrossOriginAsserts(V
&& obj
,
421 AssertStaticUnwrapOK
<PrototypeID
>();
422 return UnwrapObject
<PrototypeID
, T
>(obj
, value
, nullptr);
424 } // namespace binding_detail
426 template <prototypes::ID PrototypeID
, class T
>
427 MOZ_ALWAYS_INLINE
bool IsInstanceOf(JSObject
* obj
) {
428 AssertStaticUnwrapOK
<PrototypeID
>();
430 nsresult unwrapped
= binding_detail::UnwrapObjectInternal
<T
, true>(
431 obj
, ignored
, PrototypeID
, PrototypeTraits
<PrototypeID
>::Depth
, nullptr);
432 return NS_SUCCEEDED(unwrapped
);
435 template <prototypes::ID PrototypeID
, class T
, typename U
>
436 MOZ_ALWAYS_INLINE nsresult
UnwrapNonWrapperObject(JSObject
* obj
, U
& value
) {
437 MOZ_ASSERT(!js::IsWrapper(obj
));
438 return binding_detail::UnwrapObjectInternal
<T
, false>(
439 obj
, value
, PrototypeID
, PrototypeTraits
<PrototypeID
>::Depth
, nullptr);
442 MOZ_ALWAYS_INLINE
bool IsConvertibleToDictionary(JS::Handle
<JS::Value
> val
) {
443 return val
.isNullOrUndefined() || val
.isObject();
446 // The items in the protoAndIfaceCache are indexed by the prototypes::id::ID,
447 // constructors::id::ID and namedpropertiesobjects::id::ID enums, in that order.
448 // The end of the prototype objects should be the start of the interface
449 // objects, and the end of the interface objects should be the start of the
450 // named properties objects.
451 static_assert((size_t)constructors::id::_ID_Start
==
452 (size_t)prototypes::id::_ID_Count
&&
453 (size_t)namedpropertiesobjects::id::_ID_Start
==
454 (size_t)constructors::id::_ID_Count
,
455 "Overlapping or discontiguous indexes.");
456 const size_t kProtoAndIfaceCacheCount
= namedpropertiesobjects::id::_ID_Count
;
458 class ProtoAndIfaceCache
{
459 // The caching strategy we use depends on what sort of global we're dealing
460 // with. For a window-like global, we want everything to be as fast as
461 // possible, so we use a flat array, indexed by prototype/constructor ID.
462 // For everything else (e.g. globals for JSMs), space is more important than
463 // speed, so we use a two-level lookup table.
466 : public Array
<JS::Heap
<JSObject
*>, kProtoAndIfaceCacheCount
> {
468 bool HasEntryInSlot(size_t i
) {
469 // Do an explicit call to the Heap<…> bool conversion operator. Because
470 // that operator is marked explicit we'd otherwise end up doing an
471 // implicit cast to JSObject* first, causing an unnecessary call to
472 // exposeToActiveJS().
473 return bool((*this)[i
]);
476 JS::Heap
<JSObject
*>& EntrySlotOrCreate(size_t i
) { return (*this)[i
]; }
478 JS::Heap
<JSObject
*>& EntrySlotMustExist(size_t i
) { return (*this)[i
]; }
480 void Trace(JSTracer
* aTracer
) {
481 for (size_t i
= 0; i
< ArrayLength(*this); ++i
) {
482 JS::TraceEdge(aTracer
, &(*this)[i
], "protoAndIfaceCache[i]");
486 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) {
487 return aMallocSizeOf(this);
491 class PageTableCache
{
493 PageTableCache() { memset(mPages
.begin(), 0, sizeof(mPages
)); }
496 for (size_t i
= 0; i
< ArrayLength(mPages
); ++i
) {
501 bool HasEntryInSlot(size_t i
) {
502 MOZ_ASSERT(i
< kProtoAndIfaceCacheCount
);
503 size_t pageIndex
= i
/ kPageSize
;
504 size_t leafIndex
= i
% kPageSize
;
505 Page
* p
= mPages
[pageIndex
];
509 // Do an explicit call to the Heap<…> bool conversion operator. Because
510 // that operator is marked explicit we'd otherwise end up doing an
511 // implicit cast to JSObject* first, causing an unnecessary call to
512 // exposeToActiveJS().
513 return bool((*p
)[leafIndex
]);
516 JS::Heap
<JSObject
*>& EntrySlotOrCreate(size_t i
) {
517 MOZ_ASSERT(i
< kProtoAndIfaceCacheCount
);
518 size_t pageIndex
= i
/ kPageSize
;
519 size_t leafIndex
= i
% kPageSize
;
520 Page
* p
= mPages
[pageIndex
];
523 mPages
[pageIndex
] = p
;
525 return (*p
)[leafIndex
];
528 JS::Heap
<JSObject
*>& EntrySlotMustExist(size_t i
) {
529 MOZ_ASSERT(i
< kProtoAndIfaceCacheCount
);
530 size_t pageIndex
= i
/ kPageSize
;
531 size_t leafIndex
= i
% kPageSize
;
532 Page
* p
= mPages
[pageIndex
];
534 return (*p
)[leafIndex
];
537 void Trace(JSTracer
* trc
) {
538 for (size_t i
= 0; i
< ArrayLength(mPages
); ++i
) {
541 for (size_t j
= 0; j
< ArrayLength(*p
); ++j
) {
542 JS::TraceEdge(trc
, &(*p
)[j
], "protoAndIfaceCache[i]");
548 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) {
549 size_t n
= aMallocSizeOf(this);
550 for (size_t i
= 0; i
< ArrayLength(mPages
); ++i
) {
551 n
+= aMallocSizeOf(mPages
[i
]);
557 static const size_t kPageSize
= 16;
558 typedef Array
<JS::Heap
<JSObject
*>, kPageSize
> Page
;
559 static const size_t kNPages
=
560 kProtoAndIfaceCacheCount
/ kPageSize
+
561 size_t(bool(kProtoAndIfaceCacheCount
% kPageSize
));
562 Array
<Page
*, kNPages
> mPages
;
566 enum Kind
{ WindowLike
, NonWindowLike
};
568 explicit ProtoAndIfaceCache(Kind aKind
) : mKind(aKind
) {
569 MOZ_COUNT_CTOR(ProtoAndIfaceCache
);
570 if (aKind
== WindowLike
) {
571 mArrayCache
= new ArrayCache();
573 mPageTableCache
= new PageTableCache();
577 ~ProtoAndIfaceCache() {
578 if (mKind
== WindowLike
) {
581 delete mPageTableCache
;
583 MOZ_COUNT_DTOR(ProtoAndIfaceCache
);
586 #define FORWARD_OPERATION(opName, args) \
588 if (mKind == WindowLike) { \
589 return mArrayCache->opName args; \
591 return mPageTableCache->opName args; \
595 // Return whether slot i contains an object. This doesn't return the object
596 // itself because in practice consumers just want to know whether it's there
597 // or not, and that doesn't require barriering, which returning the object
599 bool HasEntryInSlot(size_t i
) { FORWARD_OPERATION(HasEntryInSlot
, (i
)); }
601 // Return a reference to slot i, creating it if necessary. There
602 // may not be an object in the returned slot.
603 JS::Heap
<JSObject
*>& EntrySlotOrCreate(size_t i
) {
604 FORWARD_OPERATION(EntrySlotOrCreate
, (i
));
607 // Return a reference to slot i, which is guaranteed to already
608 // exist. There may not be an object in the slot, if prototype and
609 // constructor initialization for one of our bindings failed.
610 JS::Heap
<JSObject
*>& EntrySlotMustExist(size_t i
) {
611 FORWARD_OPERATION(EntrySlotMustExist
, (i
));
614 void Trace(JSTracer
* aTracer
) { FORWARD_OPERATION(Trace
, (aTracer
)); }
616 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) {
617 size_t n
= aMallocSizeOf(this);
618 n
+= (mKind
== WindowLike
619 ? mArrayCache
->SizeOfIncludingThis(aMallocSizeOf
)
620 : mPageTableCache
->SizeOfIncludingThis(aMallocSizeOf
));
623 #undef FORWARD_OPERATION
627 ArrayCache
* mArrayCache
;
628 PageTableCache
* mPageTableCache
;
633 inline void AllocateProtoAndIfaceCache(JSObject
* obj
,
634 ProtoAndIfaceCache::Kind aKind
) {
635 MOZ_ASSERT(JS::GetClass(obj
)->flags
& JSCLASS_DOM_GLOBAL
);
636 MOZ_ASSERT(JS::GetReservedSlot(obj
, DOM_PROTOTYPE_SLOT
).isUndefined());
638 ProtoAndIfaceCache
* protoAndIfaceCache
= new ProtoAndIfaceCache(aKind
);
640 JS::SetReservedSlot(obj
, DOM_PROTOTYPE_SLOT
,
641 JS::PrivateValue(protoAndIfaceCache
));
645 struct VerifyTraceProtoAndIfaceCacheCalledTracer
: public JS::CallbackTracer
{
648 explicit VerifyTraceProtoAndIfaceCacheCalledTracer(JSContext
* cx
)
649 : JS::CallbackTracer(cx
, JS::TracerKind::VerifyTraceProtoAndIface
),
652 void onChild(JS::GCCellPtr
, const char* name
) override
{
653 // We don't do anything here, we only want to verify that
654 // TraceProtoAndIfaceCache was called.
659 inline void TraceProtoAndIfaceCache(JSTracer
* trc
, JSObject
* obj
) {
660 MOZ_ASSERT(JS::GetClass(obj
)->flags
& JSCLASS_DOM_GLOBAL
);
663 if (trc
->kind() == JS::TracerKind::VerifyTraceProtoAndIface
) {
664 // We don't do anything here, we only want to verify that
665 // TraceProtoAndIfaceCache was called.
666 static_cast<VerifyTraceProtoAndIfaceCacheCalledTracer
*>(trc
)->ok
= true;
671 if (!DOMGlobalHasProtoAndIFaceCache(obj
)) return;
672 ProtoAndIfaceCache
* protoAndIfaceCache
= GetProtoAndIfaceCache(obj
);
673 protoAndIfaceCache
->Trace(trc
);
676 inline void DestroyProtoAndIfaceCache(JSObject
* obj
) {
677 MOZ_ASSERT(JS::GetClass(obj
)->flags
& JSCLASS_DOM_GLOBAL
);
679 if (!DOMGlobalHasProtoAndIFaceCache(obj
)) {
683 ProtoAndIfaceCache
* protoAndIfaceCache
= GetProtoAndIfaceCache(obj
);
685 delete protoAndIfaceCache
;
689 * Add constants to an object.
691 bool DefineConstants(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
692 const ConstantSpec
* cs
);
694 struct JSNativeHolder
{
696 const NativePropertyHooks
* mPropertyHooks
;
699 struct LegacyFactoryFunction
{
701 const JSNativeHolder mHolder
;
707 * Create a DOM interface object (if constructorClass is non-null) and/or a
708 * DOM interface prototype object (if protoClass is non-null).
710 * global is used as the parent of the interface object and the interface
712 * protoProto is the prototype to use for the interface prototype object.
713 * interfaceProto is the prototype to use for the interface object. This can be
714 * null if both constructorClass and constructor are null (as in,
715 * if we're not creating an interface object at all).
716 * protoClass is the JSClass to use for the interface prototype object.
717 * This is null if we should not create an interface prototype
719 * protoCache a pointer to a JSObject pointer where we should cache the
720 * interface prototype object. This must be null if protoClass is and
722 * constructorClass is the JSClass to use for the interface object.
723 * This is null if we should not create an interface object or
724 * if it should be a function object.
725 * constructor holds the JSNative to back the interface object which should be a
726 * Function, unless constructorClass is non-null in which case it is
727 * ignored. If this is null and constructorClass is also null then
728 * we should not create an interface object at all.
729 * ctorNargs is the length of the constructor function; 0 if no constructor
730 * isConstructorChromeOnly if true, the constructor is ChromeOnly.
731 * constructorCache a pointer to a JSObject pointer where we should cache the
732 * interface object. This must be null if both constructorClass
733 * and constructor are null, and non-null otherwise.
734 * properties contains the methods, attributes and constants to be defined on
735 * objects in any compartment.
736 * chromeProperties contains the methods, attributes and constants to be defined
737 * on objects in chrome compartments. This must be null if the
738 * interface doesn't have any ChromeOnly properties or if the
739 * object is being created in non-chrome compartment.
740 * name the name to use for 1) the WebIDL class string, which is the value
741 * that's used for @@toStringTag, 2) the name property for interface
742 * objects and 3) the property on the global object that would be set to
743 * the interface object. In general this is the interface identifier.
744 * LegacyNamespace would expect something different for 1), but we don't
745 * support that. The class string for default iterator objects is not
746 * usable as 2) or 3), but default iterator objects don't have an interface
748 * defineOnGlobal controls whether properties should be defined on the given
749 * global for the interface object (if any) and named
750 * constructors (if any) for this interface. This can be
751 * false in situations where we want the properties to only
752 * appear on privileged Xrays but not on the unprivileged
754 * unscopableNames if not null it points to a null-terminated list of const
755 * char* names of the unscopable properties for this interface.
756 * isGlobal if true, we're creating interface objects for a [Global] interface,
757 * and hence shouldn't define properties on the prototype object.
758 * legacyWindowAliases if not null it points to a null-terminated list of const
759 * char* names of the legacy window aliases for this
762 * At least one of protoClass, constructorClass or constructor should be
763 * non-null. If constructorClass or constructor are non-null, the resulting
764 * interface object will be defined on the given global with property name
765 * |name|, which must also be non-null.
768 void CreateInterfaceObjects(
769 JSContext
* cx
, JS::Handle
<JSObject
*> global
,
770 JS::Handle
<JSObject
*> protoProto
, const DOMIfaceAndProtoJSClass
* protoClass
,
771 JS::Heap
<JSObject
*>* protoCache
, JS::Handle
<JSObject
*> constructorProto
,
772 const DOMIfaceJSClass
* constructorClass
, unsigned ctorNargs
,
773 bool isConstructorChromeOnly
,
774 const LegacyFactoryFunction
* legacyFactoryFunctions
,
775 JS::Heap
<JSObject
*>* constructorCache
, const NativeProperties
* properties
,
776 const NativeProperties
* chromeOnlyProperties
, const char* name
,
777 bool defineOnGlobal
, const char* const* unscopableNames
, bool isGlobal
,
778 const char* const* legacyWindowAliases
, bool isNamespace
);
781 * Define the properties (regular and chrome-only) on obj.
783 * obj the object to install the properties on. This should be the interface
784 * prototype object for regular interfaces and the instance object for
785 * interfaces marked with Global.
786 * properties contains the methods, attributes and constants to be defined on
787 * objects in any compartment.
788 * chromeProperties contains the methods, attributes and constants to be defined
789 * on objects in chrome compartments. This must be null if the
790 * interface doesn't have any ChromeOnly properties or if the
791 * object is being created in non-chrome compartment.
793 bool DefineProperties(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
794 const NativeProperties
* properties
,
795 const NativeProperties
* chromeOnlyProperties
);
798 * Define the legacy unforgeable methods on an object.
800 bool DefineLegacyUnforgeableMethods(
801 JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
802 const Prefable
<const JSFunctionSpec
>* props
);
805 * Define the legacy unforgeable attributes on an object.
807 bool DefineLegacyUnforgeableAttributes(
808 JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
809 const Prefable
<const JSPropertySpec
>* props
);
811 #define HAS_MEMBER_TYPEDEFS \
813 typedef char yes[1]; \
817 # define HAS_MEMBER_CHECK(_name) \
818 template <typename V> \
819 static yes& Check##_name(char(*)[(&V::_name == 0) + 1])
821 # define HAS_MEMBER_CHECK(_name) \
822 template <typename V> \
823 static yes& Check##_name(char(*)[sizeof(&V::_name) + 1])
826 #define HAS_MEMBER(_memberName, _valueName) \
828 HAS_MEMBER_CHECK(_memberName); \
829 template <typename V> \
830 static no& Check##_memberName(...); \
833 static bool const _valueName = \
834 sizeof(Check##_memberName<T>(nullptr)) == sizeof(yes)
837 struct NativeHasMember
{
840 HAS_MEMBER(GetParentObject
, GetParentObject
);
841 HAS_MEMBER(WrapObject
, WrapObject
);
848 HAS_MEMBER(get
, value
);
852 struct IsRefcounted
{
855 HAS_MEMBER(AddRef
, HasAddref
);
856 HAS_MEMBER(Release
, HasRelease
);
859 static bool const value
= HasAddref
&& HasRelease
;
862 // This struct only works if T is fully declared (not just forward declared).
863 // The std::is_base_of check will ensure that, we don't really need it for any
864 // other reason (the static assert will of course always be true).
865 static_assert(!std::is_base_of
<nsISupports
, T
>::value
|| IsRefcounted::value
,
866 "Classes derived from nsISupports are refcounted!");
870 #undef HAS_MEMBER_CHECK
871 #undef HAS_MEMBER_TYPEDEFS
874 template <class T
, bool isISupports
= std::is_base_of
<nsISupports
, T
>::value
>
875 struct CheckWrapperCacheCast
{
876 static bool Check() {
877 return reinterpret_cast<uintptr_t>(
878 static_cast<nsWrapperCache
*>(reinterpret_cast<T
*>(1))) == 1;
882 struct CheckWrapperCacheCast
<T
, true> {
883 static bool Check() { return true; }
887 inline bool TryToOuterize(JS::MutableHandle
<JS::Value
> rval
) {
888 #ifdef ENABLE_RECORD_TUPLE
889 if (rval
.isExtendedPrimitive()) {
893 MOZ_ASSERT(rval
.isObject());
894 if (js::IsWindow(&rval
.toObject())) {
895 JSObject
* obj
= js::ToWindowProxyIfWindow(&rval
.toObject());
897 rval
.set(JS::ObjectValue(*obj
));
903 inline bool TryToOuterize(JS::MutableHandle
<JSObject
*> obj
) {
904 if (js::IsWindow(obj
)) {
905 JSObject
* proxy
= js::ToWindowProxyIfWindow(obj
);
913 // Make sure to wrap the given string value into the right compartment, as
916 bool MaybeWrapStringValue(JSContext
* cx
, JS::MutableHandle
<JS::Value
> rval
) {
917 MOZ_ASSERT(rval
.isString());
918 JSString
* str
= rval
.toString();
919 if (JS::GetStringZone(str
) != js::GetContextZone(cx
)) {
920 return JS_WrapValue(cx
, rval
);
925 // Make sure to wrap the given object value into the right compartment as
926 // needed. This will work correctly, but possibly slowly, on all objects.
928 bool MaybeWrapObjectValue(JSContext
* cx
, JS::MutableHandle
<JS::Value
> rval
) {
929 MOZ_ASSERT(rval
.hasObjectPayload());
931 // Cross-compartment always requires wrapping.
932 JSObject
* obj
= &rval
.getObjectPayload();
933 if (JS::GetCompartment(obj
) != js::GetContextCompartment(cx
)) {
934 return JS_WrapValue(cx
, rval
);
937 // We're same-compartment, but we might still need to outerize if we
939 return TryToOuterize(rval
);
942 // Like MaybeWrapObjectValue, but working with a
943 // JS::MutableHandle<JSObject*> which must be non-null.
945 bool MaybeWrapObject(JSContext
* cx
, JS::MutableHandle
<JSObject
*> obj
) {
946 if (JS::GetCompartment(obj
) != js::GetContextCompartment(cx
)) {
947 return JS_WrapObject(cx
, obj
);
950 // We're same-compartment, but we might still need to outerize if we
952 return TryToOuterize(obj
);
955 // Like MaybeWrapObjectValue, but also allows null
957 bool MaybeWrapObjectOrNullValue(JSContext
* cx
,
958 JS::MutableHandle
<JS::Value
> rval
) {
959 MOZ_ASSERT(rval
.isObjectOrNull());
963 return MaybeWrapObjectValue(cx
, rval
);
966 // Wrapping for objects that are known to not be DOM objects
968 bool MaybeWrapNonDOMObjectValue(JSContext
* cx
,
969 JS::MutableHandle
<JS::Value
> rval
) {
970 MOZ_ASSERT(rval
.isObject());
971 // Compared to MaybeWrapObjectValue we just skip the TryToOuterize call. The
972 // only reason it would be needed is if we have a Window object, which would
973 // have a DOM class. Assert that we don't have any DOM-class objects coming
975 MOZ_ASSERT(!GetDOMClass(&rval
.toObject()));
977 JSObject
* obj
= &rval
.toObject();
978 if (JS::GetCompartment(obj
) == js::GetContextCompartment(cx
)) {
981 return JS_WrapValue(cx
, rval
);
984 // Like MaybeWrapNonDOMObjectValue but allows null
986 bool MaybeWrapNonDOMObjectOrNullValue(JSContext
* cx
,
987 JS::MutableHandle
<JS::Value
> rval
) {
988 MOZ_ASSERT(rval
.isObjectOrNull());
992 return MaybeWrapNonDOMObjectValue(cx
, rval
);
995 // If rval is a gcthing and is not in the compartment of cx, wrap rval
996 // into the compartment of cx (typically by replacing it with an Xray or
997 // cross-compartment wrapper around the original object).
998 MOZ_ALWAYS_INLINE
bool MaybeWrapValue(JSContext
* cx
,
999 JS::MutableHandle
<JS::Value
> rval
) {
1000 if (rval
.isGCThing()) {
1001 if (rval
.isString()) {
1002 return MaybeWrapStringValue(cx
, rval
);
1004 if (rval
.hasObjectPayload()) {
1005 return MaybeWrapObjectValue(cx
, rval
);
1007 // This could be optimized by checking the zone first, similar to
1008 // the way strings are handled. At present, this is used primarily
1009 // for structured cloning, so avoiding the overhead of JS_WrapValue
1010 // calls is less important than for other types.
1011 if (rval
.isBigInt()) {
1012 return JS_WrapValue(cx
, rval
);
1014 MOZ_ASSERT(rval
.isSymbol());
1015 JS_MarkCrossZoneId(cx
, JS::PropertyKey::Symbol(rval
.toSymbol()));
1020 namespace binding_detail
{
1021 enum GetOrCreateReflectorWrapBehavior
{
1022 eWrapIntoContextCompartment
,
1023 eDontWrapIntoContextCompartment
1027 struct TypeNeedsOuterization
{
1028 // We only need to outerize Window objects, so anything inheriting from
1029 // nsGlobalWindow (which inherits from EventTarget itself).
1030 static const bool value
= std::is_base_of
<nsGlobalWindowInner
, T
>::value
||
1031 std::is_base_of
<nsGlobalWindowOuter
, T
>::value
||
1032 std::is_same_v
<EventTarget
, T
>;
1036 template <typename T
, bool isISupports
= std::is_base_of
<nsISupports
, T
>::value
>
1037 struct CheckWrapperCacheTracing
{
1038 static inline void Check(T
* aObject
) {}
1041 template <typename T
>
1042 struct CheckWrapperCacheTracing
<T
, true> {
1043 static void Check(T
* aObject
) {
1044 // Rooting analysis thinks QueryInterface may GC, but we're dealing with
1045 // a subset of QueryInterface, C++ only types here.
1046 JS::AutoSuppressGCAnalysis nogc
;
1048 nsWrapperCache
* wrapperCacheFromQI
= nullptr;
1049 aObject
->QueryInterface(NS_GET_IID(nsWrapperCache
),
1050 reinterpret_cast<void**>(&wrapperCacheFromQI
));
1052 MOZ_ASSERT(wrapperCacheFromQI
,
1053 "Missing nsWrapperCache from QueryInterface implementation?");
1055 if (!wrapperCacheFromQI
->GetWrapperPreserveColor()) {
1056 // Can't assert that we trace the wrapper, since we don't have any
1057 // wrapper to trace.
1061 nsISupports
* ccISupports
= nullptr;
1062 aObject
->QueryInterface(NS_GET_IID(nsCycleCollectionISupports
),
1063 reinterpret_cast<void**>(&ccISupports
));
1064 MOZ_ASSERT(ccISupports
,
1065 "nsWrapperCache object which isn't cycle collectable?");
1067 nsXPCOMCycleCollectionParticipant
* participant
= nullptr;
1068 CallQueryInterface(ccISupports
, &participant
);
1069 MOZ_ASSERT(participant
, "Can't QI to CycleCollectionParticipant?");
1071 wrapperCacheFromQI
->CheckCCWrapperTraversal(ccISupports
, participant
);
1075 void AssertReflectorHasGivenProto(JSContext
* aCx
, JSObject
* aReflector
,
1076 JS::Handle
<JSObject
*> aGivenProto
);
1079 template <class T
, GetOrCreateReflectorWrapBehavior wrapBehavior
>
1080 MOZ_ALWAYS_INLINE
bool DoGetOrCreateDOMReflector(
1081 JSContext
* cx
, T
* value
, JS::Handle
<JSObject
*> givenProto
,
1082 JS::MutableHandle
<JS::Value
> rval
) {
1084 MOZ_ASSERT_IF(givenProto
, js::IsObjectInContextCompartment(givenProto
, cx
));
1085 JSObject
* obj
= value
->GetWrapper();
1088 AssertReflectorHasGivenProto(cx
, obj
, givenProto
);
1089 // Have to reget obj because AssertReflectorHasGivenProto can
1090 // trigger gc so the pointer may now be invalid.
1091 obj
= value
->GetWrapper();
1094 obj
= value
->WrapObject(cx
, givenProto
);
1096 // At this point, obj is null, so just return false.
1097 // Callers seem to be testing JS_IsExceptionPending(cx) to
1098 // figure out whether WrapObject() threw.
1103 if (std::is_base_of
<nsWrapperCache
, T
>::value
) {
1104 CheckWrapperCacheTracing
<T
>::Check(value
);
1110 const DOMJSClass
* clasp
= GetDOMClass(obj
);
1111 // clasp can be null if the cache contained a non-DOM object.
1113 // Some sanity asserts about our object. Specifically:
1114 // 1) If our class claims we're nsISupports, we better be nsISupports
1115 // XXXbz ideally, we could assert that reinterpret_cast to nsISupports
1116 // does the right thing, but I don't see a way to do it. :(
1117 // 2) If our class doesn't claim we're nsISupports we better be
1118 // reinterpret_castable to nsWrapperCache.
1119 MOZ_ASSERT(clasp
, "What happened here?");
1120 MOZ_ASSERT_IF(clasp
->mDOMObjectIsISupports
,
1121 (std::is_base_of
<nsISupports
, T
>::value
));
1122 MOZ_ASSERT(CheckWrapperCacheCast
<T
>::Check());
1126 #ifdef ENABLE_RECORD_TUPLE
1127 MOZ_ASSERT(!js::gc::MaybeForwardedIsExtendedPrimitive(*obj
));
1129 rval
.set(JS::ObjectValue(*obj
));
1131 if (JS::GetCompartment(obj
) == js::GetContextCompartment(cx
)) {
1132 return TypeNeedsOuterization
<T
>::value
? TryToOuterize(rval
) : true;
1135 if (wrapBehavior
== eDontWrapIntoContextCompartment
) {
1136 if (TypeNeedsOuterization
<T
>::value
) {
1137 JSAutoRealm
ar(cx
, obj
);
1138 return TryToOuterize(rval
);
1144 return JS_WrapValue(cx
, rval
);
1147 } // namespace binding_detail
1149 // Create a JSObject wrapping "value", if there isn't one already, and store it
1150 // in rval. "value" must be a concrete class that implements a
1151 // GetWrapperPreserveColor() which can return its existing wrapper, if any, and
1152 // a WrapObject() which will try to create a wrapper. Typically, this is done by
1153 // having "value" inherit from nsWrapperCache.
1155 // The value stored in rval will be ready to be exposed to whatever JS
1156 // is running on cx right now. In particular, it will be in the
1157 // compartment of cx, and outerized as needed.
1159 MOZ_ALWAYS_INLINE
bool GetOrCreateDOMReflector(
1160 JSContext
* cx
, T
* value
, JS::MutableHandle
<JS::Value
> rval
,
1161 JS::Handle
<JSObject
*> givenProto
= nullptr) {
1162 using namespace binding_detail
;
1163 return DoGetOrCreateDOMReflector
<T
, eWrapIntoContextCompartment
>(
1164 cx
, value
, givenProto
, rval
);
1167 // Like GetOrCreateDOMReflector but doesn't wrap into the context compartment,
1168 // and hence does not actually require cx to be in a compartment.
1170 MOZ_ALWAYS_INLINE
bool GetOrCreateDOMReflectorNoWrap(
1171 JSContext
* cx
, T
* value
, JS::MutableHandle
<JS::Value
> rval
) {
1172 using namespace binding_detail
;
1173 return DoGetOrCreateDOMReflector
<T
, eDontWrapIntoContextCompartment
>(
1174 cx
, value
, nullptr, rval
);
1177 // Helper for different overloadings of WrapNewBindingNonWrapperCachedObject()
1178 inline bool FinishWrapping(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
1179 JS::MutableHandle
<JS::Value
> rval
) {
1180 #ifdef ENABLE_RECORD_TUPLE
1181 // If calling an (object) value's WrapObject() method returned a record/tuple,
1182 // then something is very wrong.
1183 MOZ_ASSERT(!js::gc::MaybeForwardedIsExtendedPrimitive(*obj
));
1186 // We can end up here in all sorts of compartments, per comments in
1187 // WrapNewBindingNonWrapperCachedObject(). Make sure to JS_WrapValue!
1188 rval
.set(JS::ObjectValue(*obj
));
1189 return MaybeWrapObjectValue(cx
, rval
);
1192 // Create a JSObject wrapping "value", for cases when "value" is a
1193 // non-wrapper-cached object using WebIDL bindings. "value" must implement a
1194 // WrapObject() method taking a JSContext and a prototype (possibly null) and
1195 // returning the resulting object via a MutableHandle<JSObject*> outparam.
1197 inline bool WrapNewBindingNonWrapperCachedObject(
1198 JSContext
* cx
, JS::Handle
<JSObject
*> scopeArg
, T
* value
,
1199 JS::MutableHandle
<JS::Value
> rval
,
1200 JS::Handle
<JSObject
*> givenProto
= nullptr) {
1201 static_assert(IsRefcounted
<T
>::value
, "Don't pass owned classes in here.");
1203 // We try to wrap in the realm of the underlying object of "scope"
1204 JS::Rooted
<JSObject
*> obj(cx
);
1206 // scope for the JSAutoRealm so that we restore the realm
1207 // before we call JS_WrapValue.
1208 Maybe
<JSAutoRealm
> ar
;
1209 // Maybe<Handle> doesn't so much work, and in any case, adding
1210 // more Maybe (one for a Rooted and one for a Handle) adds more
1211 // code (and branches!) than just adding a single rooted.
1212 JS::Rooted
<JSObject
*> scope(cx
, scopeArg
);
1213 JS::Rooted
<JSObject
*> proto(cx
, givenProto
);
1214 if (js::IsWrapper(scope
)) {
1215 // We are working in the Realm of cx and will be producing our reflector
1216 // there, so we need to succeed if that realm has access to the scope.
1218 js::CheckedUnwrapDynamic(scope
, cx
, /* stopAtWindowProxy = */ false);
1219 if (!scope
) return false;
1220 ar
.emplace(cx
, scope
);
1221 if (!JS_WrapObject(cx
, &proto
)) {
1225 // cx and scope are same-compartment, but they might still be
1226 // different-Realm. Enter the Realm of scope, since that's
1227 // where we want to create our object.
1228 ar
.emplace(cx
, scope
);
1231 MOZ_ASSERT_IF(proto
, js::IsObjectInContextCompartment(proto
, cx
));
1232 MOZ_ASSERT(js::IsObjectInContextCompartment(scope
, cx
));
1233 if (!value
->WrapObject(cx
, proto
, &obj
)) {
1238 return FinishWrapping(cx
, obj
, rval
);
1241 // Create a JSObject wrapping "value", for cases when "value" is a
1242 // non-wrapper-cached owned object using WebIDL bindings. "value" must
1243 // implement a WrapObject() method taking a taking a JSContext and a prototype
1244 // (possibly null) and returning two pieces of information: the resulting object
1245 // via a MutableHandle<JSObject*> outparam and a boolean return value that is
1246 // true if the JSObject took ownership
1248 inline bool WrapNewBindingNonWrapperCachedObject(
1249 JSContext
* cx
, JS::Handle
<JSObject
*> scopeArg
, UniquePtr
<T
>& value
,
1250 JS::MutableHandle
<JS::Value
> rval
,
1251 JS::Handle
<JSObject
*> givenProto
= nullptr) {
1252 static_assert(!IsRefcounted
<T
>::value
, "Only pass owned classes in here.");
1253 // We do a runtime check on value, because otherwise we might in
1254 // fact end up wrapping a null and invoking methods on it later.
1256 MOZ_CRASH("Don't try to wrap null objects");
1258 // We try to wrap in the realm of the underlying object of "scope"
1259 JS::Rooted
<JSObject
*> obj(cx
);
1261 // scope for the JSAutoRealm so that we restore the realm
1262 // before we call JS_WrapValue.
1263 Maybe
<JSAutoRealm
> ar
;
1264 // Maybe<Handle> doesn't so much work, and in any case, adding
1265 // more Maybe (one for a Rooted and one for a Handle) adds more
1266 // code (and branches!) than just adding a single rooted.
1267 JS::Rooted
<JSObject
*> scope(cx
, scopeArg
);
1268 JS::Rooted
<JSObject
*> proto(cx
, givenProto
);
1269 if (js::IsWrapper(scope
)) {
1270 // We are working in the Realm of cx and will be producing our reflector
1271 // there, so we need to succeed if that realm has access to the scope.
1273 js::CheckedUnwrapDynamic(scope
, cx
, /* stopAtWindowProxy = */ false);
1274 if (!scope
) return false;
1275 ar
.emplace(cx
, scope
);
1276 if (!JS_WrapObject(cx
, &proto
)) {
1280 // cx and scope are same-compartment, but they might still be
1281 // different-Realm. Enter the Realm of scope, since that's
1282 // where we want to create our object.
1283 ar
.emplace(cx
, scope
);
1286 MOZ_ASSERT_IF(proto
, js::IsObjectInContextCompartment(proto
, cx
));
1287 MOZ_ASSERT(js::IsObjectInContextCompartment(scope
, cx
));
1288 if (!value
->WrapObject(cx
, proto
, &obj
)) {
1292 // JS object took ownership
1293 Unused
<< value
.release();
1296 return FinishWrapping(cx
, obj
, rval
);
1299 // Helper for smart pointers (nsRefPtr/nsCOMPtr).
1300 template <template <typename
> class SmartPtr
, typename T
,
1301 typename U
= std::enable_if_t
<IsRefcounted
<T
>::value
, T
>,
1302 typename V
= std::enable_if_t
<IsSmartPtr
<SmartPtr
<T
>>::value
, T
>>
1303 inline bool WrapNewBindingNonWrapperCachedObject(
1304 JSContext
* cx
, JS::Handle
<JSObject
*> scope
, const SmartPtr
<T
>& value
,
1305 JS::MutableHandle
<JS::Value
> rval
,
1306 JS::Handle
<JSObject
*> givenProto
= nullptr) {
1307 return WrapNewBindingNonWrapperCachedObject(cx
, scope
, value
.get(), rval
,
1311 // Helper for object references (as opposed to pointers).
1312 template <typename T
, typename U
= std::enable_if_t
<!IsSmartPtr
<T
>::value
, T
>>
1313 inline bool WrapNewBindingNonWrapperCachedObject(
1314 JSContext
* cx
, JS::Handle
<JSObject
*> scope
, T
& value
,
1315 JS::MutableHandle
<JS::Value
> rval
,
1316 JS::Handle
<JSObject
*> givenProto
= nullptr) {
1317 return WrapNewBindingNonWrapperCachedObject(cx
, scope
, &value
, rval
,
1321 template <bool Fatal
>
1322 inline bool EnumValueNotFound(BindingCallContext
& cx
, JS::Handle
<JSString
*> str
,
1323 const char* type
, const char* sourceDescription
);
1326 inline bool EnumValueNotFound
<false>(BindingCallContext
& cx
,
1327 JS::Handle
<JSString
*> str
,
1329 const char* sourceDescription
) {
1330 // TODO: Log a warning to the console.
1335 inline bool EnumValueNotFound
<true>(BindingCallContext
& cx
,
1336 JS::Handle
<JSString
*> str
, const char* type
,
1337 const char* sourceDescription
) {
1338 JS::UniqueChars deflated
= JS_EncodeStringToUTF8(cx
, str
);
1342 return cx
.ThrowErrorMessage
<MSG_INVALID_ENUM_VALUE
>(sourceDescription
,
1343 deflated
.get(), type
);
1346 template <typename CharT
>
1347 inline int FindEnumStringIndexImpl(const CharT
* chars
, size_t length
,
1348 const EnumEntry
* values
) {
1350 for (const EnumEntry
* value
= values
; value
->value
; ++value
, ++i
) {
1351 if (length
!= value
->length
) {
1356 const char* val
= value
->value
;
1357 for (size_t j
= 0; j
!= length
; ++j
) {
1358 if (unsigned(val
[j
]) != unsigned(chars
[j
])) {
1372 template <bool InvalidValueFatal
>
1373 inline bool FindEnumStringIndex(BindingCallContext
& cx
, JS::Handle
<JS::Value
> v
,
1374 const EnumEntry
* values
, const char* type
,
1375 const char* sourceDescription
, int* index
) {
1376 // JS_StringEqualsAscii is slow as molasses, so don't use it here.
1377 JS::Rooted
<JSString
*> str(cx
, JS::ToString(cx
, v
));
1384 JS::AutoCheckCannotGC nogc
;
1385 if (JS::StringHasLatin1Chars(str
)) {
1386 const JS::Latin1Char
* chars
=
1387 JS_GetLatin1StringCharsAndLength(cx
, nogc
, str
, &length
);
1391 *index
= FindEnumStringIndexImpl(chars
, length
, values
);
1393 const char16_t
* chars
=
1394 JS_GetTwoByteStringCharsAndLength(cx
, nogc
, str
, &length
);
1398 *index
= FindEnumStringIndexImpl(chars
, length
, values
);
1405 return EnumValueNotFound
<InvalidValueFatal
>(cx
, str
, type
, sourceDescription
);
1408 inline nsWrapperCache
* GetWrapperCache(const ParentObject
& aParentObject
) {
1409 return aParentObject
.mWrapperCache
;
1413 inline T
* GetParentPointer(T
* aObject
) {
1417 inline nsISupports
* GetParentPointer(const ParentObject
& aObject
) {
1418 return aObject
.mObject
;
1421 template <typename T
>
1422 inline mozilla::dom::ReflectionScope
GetReflectionScope(T
* aParentObject
) {
1423 return mozilla::dom::ReflectionScope::Content
;
1426 inline mozilla::dom::ReflectionScope
GetReflectionScope(
1427 const ParentObject
& aParentObject
) {
1428 return aParentObject
.mReflectionScope
;
1432 inline void ClearWrapper(T
* p
, nsWrapperCache
* cache
, JSObject
* obj
) {
1433 MOZ_ASSERT(cache
->GetWrapperMaybeDead() == obj
||
1434 (js::RuntimeIsBeingDestroyed() && !cache
->GetWrapperMaybeDead()));
1435 cache
->ClearWrapper(obj
);
1439 inline void ClearWrapper(T
* p
, void*, JSObject
* obj
) {
1440 // QueryInterface to nsWrapperCache can't GC, we hope.
1441 JS::AutoSuppressGCAnalysis nogc
;
1443 nsWrapperCache
* cache
;
1444 CallQueryInterface(p
, &cache
);
1445 ClearWrapper(p
, cache
, obj
);
1449 inline void UpdateWrapper(T
* p
, nsWrapperCache
* cache
, JSObject
* obj
,
1450 const JSObject
* old
) {
1451 JS::AutoAssertGCCallback inCallback
;
1452 cache
->UpdateWrapper(obj
, old
);
1456 inline void UpdateWrapper(T
* p
, void*, JSObject
* obj
, const JSObject
* old
) {
1457 JS::AutoAssertGCCallback inCallback
;
1458 nsWrapperCache
* cache
;
1459 CallQueryInterface(p
, &cache
);
1460 UpdateWrapper(p
, cache
, obj
, old
);
1463 // Attempt to preserve the wrapper, if any, for a Paris DOM bindings object.
1464 // Return true if we successfully preserved the wrapper, or there is no wrapper
1465 // to preserve. In the latter case we don't need to preserve the wrapper,
1466 // because the object can only be obtained by JS once, or they cannot be
1467 // meaningfully owned from the native side.
1469 // This operation will return false only for non-nsISupports cycle-collected
1470 // objects, because we cannot determine if they are wrappercached or not.
1471 bool TryPreserveWrapper(JS::Handle
<JSObject
*> obj
);
1473 bool HasReleasedWrapper(JS::Handle
<JSObject
*> obj
);
1475 // Can only be called with a DOM JSClass.
1476 bool InstanceClassHasProtoAtDepth(const JSClass
* clasp
, uint32_t protoID
,
1479 // Only set allowNativeWrapper to false if you really know you need it; if in
1480 // doubt use true. Setting it to false disables security wrappers.
1481 bool XPCOMObjectToJsval(JSContext
* cx
, JS::Handle
<JSObject
*> scope
,
1482 xpcObjectHelper
& helper
, const nsIID
* iid
,
1483 bool allowNativeWrapper
,
1484 JS::MutableHandle
<JS::Value
> rval
);
1486 // Special-cased wrapping for variants
1487 bool VariantToJsval(JSContext
* aCx
, nsIVariant
* aVariant
,
1488 JS::MutableHandle
<JS::Value
> aRetval
);
1490 // Wrap an object "p" which is not using WebIDL bindings yet. This _will_
1491 // actually work on WebIDL binding objects that are wrappercached, but will be
1492 // much slower than GetOrCreateDOMReflector. "cache" must either be null or be
1493 // the nsWrapperCache for "p".
1495 inline bool WrapObject(JSContext
* cx
, T
* p
, nsWrapperCache
* cache
,
1496 const nsIID
* iid
, JS::MutableHandle
<JS::Value
> rval
) {
1497 if (xpc_FastGetCachedWrapper(cx
, cache
, rval
)) return true;
1498 xpcObjectHelper
helper(ToSupports(p
), cache
);
1499 JS::Rooted
<JSObject
*> scope(cx
, JS::CurrentGlobalOrNull(cx
));
1500 return XPCOMObjectToJsval(cx
, scope
, helper
, iid
, true, rval
);
1503 // A specialization of the above for nsIVariant, because that needs to
1504 // do something different.
1506 inline bool WrapObject
<nsIVariant
>(JSContext
* cx
, nsIVariant
* p
,
1507 nsWrapperCache
* cache
, const nsIID
* iid
,
1508 JS::MutableHandle
<JS::Value
> rval
) {
1510 MOZ_ASSERT(iid
->Equals(NS_GET_IID(nsIVariant
)));
1511 return VariantToJsval(cx
, p
, rval
);
1514 // Wrap an object "p" which is not using WebIDL bindings yet. Just like the
1515 // variant that takes an nsWrapperCache above, but will try to auto-derive the
1516 // nsWrapperCache* from "p".
1518 inline bool WrapObject(JSContext
* cx
, T
* p
, const nsIID
* iid
,
1519 JS::MutableHandle
<JS::Value
> rval
) {
1520 return WrapObject(cx
, p
, GetWrapperCache(p
), iid
, rval
);
1523 // Just like the WrapObject above, but without requiring you to pick which
1524 // interface you're wrapping as. This should only be used for objects that have
1525 // classinfo, for which it doesn't matter what IID is used to wrap.
1527 inline bool WrapObject(JSContext
* cx
, T
* p
, JS::MutableHandle
<JS::Value
> rval
) {
1528 return WrapObject(cx
, p
, nullptr, rval
);
1531 // Helper to make it possible to wrap directly out of an nsCOMPtr
1533 inline bool WrapObject(JSContext
* cx
, const nsCOMPtr
<T
>& p
, const nsIID
* iid
,
1534 JS::MutableHandle
<JS::Value
> rval
) {
1535 return WrapObject(cx
, p
.get(), iid
, rval
);
1538 // Helper to make it possible to wrap directly out of an nsCOMPtr
1540 inline bool WrapObject(JSContext
* cx
, const nsCOMPtr
<T
>& p
,
1541 JS::MutableHandle
<JS::Value
> rval
) {
1542 return WrapObject(cx
, p
, nullptr, rval
);
1545 // Helper to make it possible to wrap directly out of an nsRefPtr
1547 inline bool WrapObject(JSContext
* cx
, const RefPtr
<T
>& p
, const nsIID
* iid
,
1548 JS::MutableHandle
<JS::Value
> rval
) {
1549 return WrapObject(cx
, p
.get(), iid
, rval
);
1552 // Helper to make it possible to wrap directly out of an nsRefPtr
1554 inline bool WrapObject(JSContext
* cx
, const RefPtr
<T
>& p
,
1555 JS::MutableHandle
<JS::Value
> rval
) {
1556 return WrapObject(cx
, p
, nullptr, rval
);
1559 // Specialization to make it easy to use WrapObject in codegen.
1561 inline bool WrapObject
<JSObject
>(JSContext
* cx
, JSObject
* p
,
1562 JS::MutableHandle
<JS::Value
> rval
) {
1563 rval
.set(JS::ObjectOrNullValue(p
));
1567 inline bool WrapObject(JSContext
* cx
, JSObject
& p
,
1568 JS::MutableHandle
<JS::Value
> rval
) {
1569 rval
.set(JS::ObjectValue(p
));
1573 bool WrapObject(JSContext
* cx
, const WindowProxyHolder
& p
,
1574 JS::MutableHandle
<JS::Value
> rval
);
1576 // Given an object "p" that inherits from nsISupports, wrap it and return the
1577 // result. Null is returned on wrapping failure. This is somewhat similar to
1578 // WrapObject() above, but does NOT allow Xrays around the result, since we
1579 // don't want those for our parent object.
1580 template <typename T
>
1581 static inline JSObject
* WrapNativeISupports(JSContext
* cx
, T
* p
,
1582 nsWrapperCache
* cache
) {
1583 JS::Rooted
<JSObject
*> retval(cx
);
1585 xpcObjectHelper
helper(ToSupports(p
), cache
);
1586 JS::Rooted
<JSObject
*> scope(cx
, JS::CurrentGlobalOrNull(cx
));
1587 JS::Rooted
<JS::Value
> v(cx
);
1588 retval
= XPCOMObjectToJsval(cx
, scope
, helper
, nullptr, false, &v
)
1589 ? v
.toObjectOrNull()
1595 // Wrapping of our native parent, for cases when it's a WebIDL object.
1596 template <typename T
, bool hasWrapObject
= NativeHasMember
<T
>::WrapObject
>
1597 struct WrapNativeHelper
{
1598 static inline JSObject
* Wrap(JSContext
* cx
, T
* parent
,
1599 nsWrapperCache
* cache
) {
1603 if ((obj
= cache
->GetWrapper())) {
1604 // GetWrapper always unmarks gray.
1605 JS::AssertObjectIsNotGray(obj
);
1609 // WrapObject never returns a gray thing.
1610 obj
= parent
->WrapObject(cx
, nullptr);
1611 JS::AssertObjectIsNotGray(obj
);
1617 // Wrapping of our native parent, for cases when it's not a WebIDL object. In
1618 // this case it must be nsISupports.
1619 template <typename T
>
1620 struct WrapNativeHelper
<T
, false> {
1621 static inline JSObject
* Wrap(JSContext
* cx
, T
* parent
,
1622 nsWrapperCache
* cache
) {
1624 if (cache
&& (obj
= cache
->GetWrapper())) {
1626 JS::Rooted
<JSObject
*> rootedObj(cx
, obj
);
1627 NS_ASSERTION(WrapNativeISupports(cx
, parent
, cache
) == rootedObj
,
1628 "Unexpected object in nsWrapperCache");
1631 JS::AssertObjectIsNotGray(obj
);
1635 obj
= WrapNativeISupports(cx
, parent
, cache
);
1636 JS::AssertObjectIsNotGray(obj
);
1641 // Finding the associated global for an object.
1642 template <typename T
>
1643 static inline JSObject
* FindAssociatedGlobal(
1644 JSContext
* cx
, T
* p
, nsWrapperCache
* cache
,
1645 mozilla::dom::ReflectionScope scope
=
1646 mozilla::dom::ReflectionScope::Content
) {
1648 return JS::CurrentGlobalOrNull(cx
);
1651 JSObject
* obj
= WrapNativeHelper
<T
>::Wrap(cx
, p
, cache
);
1655 JS::AssertObjectIsNotGray(obj
);
1657 // The object is never a CCW but it may not be in the current compartment of
1659 obj
= JS::GetNonCCWObjectGlobal(obj
);
1662 case mozilla::dom::ReflectionScope::NAC
: {
1663 return xpc::NACScope(obj
);
1666 case mozilla::dom::ReflectionScope::UAWidget
: {
1667 // If scope is set to UAWidgetScope, it means that the canonical reflector
1668 // for this native object should live in the UA widget scope.
1669 if (xpc::IsInUAWidgetScope(obj
)) {
1672 JS::Rooted
<JSObject
*> rootedObj(cx
, obj
);
1673 JSObject
* uaWidgetScope
= xpc::GetUAWidgetScope(cx
, rootedObj
);
1674 MOZ_ASSERT_IF(uaWidgetScope
, JS_IsGlobalObject(uaWidgetScope
));
1675 JS::AssertObjectIsNotGray(uaWidgetScope
);
1676 return uaWidgetScope
;
1679 case ReflectionScope::Content
:
1683 MOZ_CRASH("Unknown ReflectionScope variant");
1688 // Finding of the associated global for an object, when we don't want to
1689 // explicitly pass in things like the nsWrapperCache for it.
1690 template <typename T
>
1691 static inline JSObject
* FindAssociatedGlobal(JSContext
* cx
, const T
& p
) {
1692 return FindAssociatedGlobal(cx
, GetParentPointer(p
), GetWrapperCache(p
),
1693 GetReflectionScope(p
));
1696 // Specialization for the case of nsIGlobalObject, since in that case
1697 // we can just get the JSObject* directly.
1699 inline JSObject
* FindAssociatedGlobal(JSContext
* cx
,
1700 nsIGlobalObject
* const& p
) {
1702 return JS::CurrentGlobalOrNull(cx
);
1705 JSObject
* global
= p
->GetGlobalJSObject();
1707 // nsIGlobalObject doesn't have a JS object anymore,
1708 // fallback to the current global.
1709 return JS::CurrentGlobalOrNull(cx
);
1712 MOZ_ASSERT(JS_IsGlobalObject(global
));
1713 JS::AssertObjectIsNotGray(global
);
1717 template <typename T
,
1718 bool hasAssociatedGlobal
= NativeHasMember
<T
>::GetParentObject
>
1719 struct FindAssociatedGlobalForNative
{
1720 static JSObject
* Get(JSContext
* cx
, JS::Handle
<JSObject
*> obj
) {
1721 MOZ_ASSERT(js::IsObjectInContextCompartment(obj
, cx
));
1722 T
* native
= UnwrapDOMObject
<T
>(obj
);
1723 return FindAssociatedGlobal(cx
, native
->GetParentObject());
1727 template <typename T
>
1728 struct FindAssociatedGlobalForNative
<T
, false> {
1729 static JSObject
* Get(JSContext
* cx
, JS::Handle
<JSObject
*> obj
) {
1735 // Helper for calling GetOrCreateDOMReflector with smart pointers
1736 // (UniquePtr/RefPtr/nsCOMPtr) or references.
1737 template <class T
, bool isSmartPtr
= IsSmartPtr
<T
>::value
>
1738 struct GetOrCreateDOMReflectorHelper
{
1739 static inline bool GetOrCreate(JSContext
* cx
, const T
& value
,
1740 JS::Handle
<JSObject
*> givenProto
,
1741 JS::MutableHandle
<JS::Value
> rval
) {
1742 return GetOrCreateDOMReflector(cx
, value
.get(), rval
, givenProto
);
1747 struct GetOrCreateDOMReflectorHelper
<T
, false> {
1748 static inline bool GetOrCreate(JSContext
* cx
, T
& value
,
1749 JS::Handle
<JSObject
*> givenProto
,
1750 JS::MutableHandle
<JS::Value
> rval
) {
1751 static_assert(IsRefcounted
<T
>::value
, "Don't pass owned classes in here.");
1752 return GetOrCreateDOMReflector(cx
, &value
, rval
, givenProto
);
1757 inline bool GetOrCreateDOMReflector(
1758 JSContext
* cx
, T
& value
, JS::MutableHandle
<JS::Value
> rval
,
1759 JS::Handle
<JSObject
*> givenProto
= nullptr) {
1760 return GetOrCreateDOMReflectorHelper
<T
>::GetOrCreate(cx
, value
, givenProto
,
1764 // Helper for calling GetOrCreateDOMReflectorNoWrap with smart pointers
1765 // (UniquePtr/RefPtr/nsCOMPtr) or references.
1766 template <class T
, bool isSmartPtr
= IsSmartPtr
<T
>::value
>
1767 struct GetOrCreateDOMReflectorNoWrapHelper
{
1768 static inline bool GetOrCreate(JSContext
* cx
, const T
& value
,
1769 JS::MutableHandle
<JS::Value
> rval
) {
1770 return GetOrCreateDOMReflectorNoWrap(cx
, value
.get(), rval
);
1775 struct GetOrCreateDOMReflectorNoWrapHelper
<T
, false> {
1776 static inline bool GetOrCreate(JSContext
* cx
, T
& value
,
1777 JS::MutableHandle
<JS::Value
> rval
) {
1778 return GetOrCreateDOMReflectorNoWrap(cx
, &value
, rval
);
1783 inline bool GetOrCreateDOMReflectorNoWrap(JSContext
* cx
, T
& value
,
1784 JS::MutableHandle
<JS::Value
> rval
) {
1785 return GetOrCreateDOMReflectorNoWrapHelper
<T
>::GetOrCreate(cx
, value
, rval
);
1789 inline JSObject
* GetCallbackFromCallbackObject(JSContext
* aCx
, T
* aObj
) {
1790 return aObj
->Callback(aCx
);
1793 // Helper for getting the callback JSObject* of a smart ptr around a
1794 // CallbackObject or a reference to a CallbackObject or something like
1796 template <class T
, bool isSmartPtr
= IsSmartPtr
<T
>::value
>
1797 struct GetCallbackFromCallbackObjectHelper
{
1798 static inline JSObject
* Get(JSContext
* aCx
, const T
& aObj
) {
1799 return GetCallbackFromCallbackObject(aCx
, aObj
.get());
1804 struct GetCallbackFromCallbackObjectHelper
<T
, false> {
1805 static inline JSObject
* Get(JSContext
* aCx
, T
& aObj
) {
1806 return GetCallbackFromCallbackObject(aCx
, &aObj
);
1811 inline JSObject
* GetCallbackFromCallbackObject(JSContext
* aCx
, T
& aObj
) {
1812 return GetCallbackFromCallbackObjectHelper
<T
>::Get(aCx
, aObj
);
1815 static inline bool AtomizeAndPinJSString(JSContext
* cx
, jsid
& id
,
1816 const char* chars
) {
1817 if (JSString
* str
= ::JS_AtomizeAndPinString(cx
, chars
)) {
1818 id
= JS::PropertyKey::fromPinnedString(str
);
1824 void GetInterfaceImpl(JSContext
* aCx
, nsIInterfaceRequestor
* aRequestor
,
1825 nsWrapperCache
* aCache
, JS::Handle
<JS::Value
> aIID
,
1826 JS::MutableHandle
<JS::Value
> aRetval
,
1827 ErrorResult
& aError
);
1830 void GetInterface(JSContext
* aCx
, T
* aThis
, JS::Handle
<JS::Value
> aIID
,
1831 JS::MutableHandle
<JS::Value
> aRetval
, ErrorResult
& aError
) {
1832 GetInterfaceImpl(aCx
, aThis
, aThis
, aIID
, aRetval
, aError
);
1835 bool ThrowingConstructor(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
1837 bool ThrowConstructorWithoutNew(JSContext
* cx
, const char* name
);
1839 // Helper for throwing an "invalid this" exception.
1840 bool ThrowInvalidThis(JSContext
* aCx
, const JS::CallArgs
& aArgs
,
1841 bool aSecurityError
, prototypes::ID aProtoId
);
1843 bool GetPropertyOnPrototype(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
1844 JS::Handle
<JS::Value
> receiver
, JS::Handle
<jsid
> id
,
1845 bool* found
, JS::MutableHandle
<JS::Value
> vp
);
1848 bool HasPropertyOnPrototype(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
1849 JS::Handle
<jsid
> id
, bool* has
);
1851 // Append the property names in "names" to "props". If
1852 // shadowPrototypeProperties is false then skip properties that are also
1853 // present on the proto chain of proxy. If shadowPrototypeProperties is true,
1854 // then the "proxy" argument is ignored.
1855 bool AppendNamedPropertyIds(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
1856 nsTArray
<nsString
>& names
,
1857 bool shadowPrototypeProperties
,
1858 JS::MutableHandleVector
<jsid
> props
);
1860 enum StringificationBehavior
{ eStringify
, eEmpty
, eNull
};
1862 static inline JSString
* ConvertJSValueToJSString(JSContext
* cx
,
1863 JS::Handle
<JS::Value
> v
) {
1864 if (MOZ_LIKELY(v
.isString())) {
1865 return v
.toString();
1867 return JS::ToString(cx
, v
);
1870 template <typename T
>
1871 static inline bool ConvertJSValueToString(
1872 JSContext
* cx
, JS::Handle
<JS::Value
> v
,
1873 StringificationBehavior nullBehavior
,
1874 StringificationBehavior undefinedBehavior
, T
& result
) {
1879 StringificationBehavior behavior
;
1881 behavior
= nullBehavior
;
1882 } else if (v
.isUndefined()) {
1883 behavior
= undefinedBehavior
;
1885 behavior
= eStringify
;
1888 if (behavior
!= eStringify
) {
1889 if (behavior
== eEmpty
) {
1892 result
.SetIsVoid(true);
1897 s
= JS::ToString(cx
, v
);
1903 return AssignJSString(cx
, result
, s
);
1906 template <typename T
>
1907 static inline bool ConvertJSValueToString(
1908 JSContext
* cx
, JS::Handle
<JS::Value
> v
,
1909 const char* /* unused sourceDescription */, T
& result
) {
1910 return ConvertJSValueToString(cx
, v
, eStringify
, eStringify
, result
);
1913 [[nodiscard
]] bool NormalizeUSVString(nsAString
& aString
);
1915 [[nodiscard
]] bool NormalizeUSVString(
1916 binding_detail::FakeString
<char16_t
>& aString
);
1918 template <typename T
>
1919 static inline bool ConvertJSValueToUSVString(
1920 JSContext
* cx
, JS::Handle
<JS::Value
> v
,
1921 const char* /* unused sourceDescription */, T
& result
) {
1922 if (!ConvertJSValueToString(cx
, v
, eStringify
, eStringify
, result
)) {
1926 if (!NormalizeUSVString(result
)) {
1927 JS_ReportOutOfMemory(cx
);
1934 template <typename T
>
1935 inline bool ConvertIdToString(JSContext
* cx
, JS::Handle
<JS::PropertyKey
> id
,
1936 T
& result
, bool& isSymbol
) {
1937 if (MOZ_LIKELY(id
.isString())) {
1938 if (!AssignJSString(cx
, result
, id
.toString())) {
1941 } else if (id
.isSymbol()) {
1945 JS::Rooted
<JS::Value
> nameVal(cx
, js::IdToValue(id
));
1946 if (!ConvertJSValueToString(cx
, nameVal
, eStringify
, eStringify
, result
)) {
1954 bool ConvertJSValueToByteString(BindingCallContext
& cx
, JS::Handle
<JS::Value
> v
,
1955 bool nullable
, const char* sourceDescription
,
1956 nsACString
& result
);
1958 inline bool ConvertJSValueToByteString(BindingCallContext
& cx
,
1959 JS::Handle
<JS::Value
> v
,
1960 const char* sourceDescription
,
1961 nsACString
& result
) {
1962 return ConvertJSValueToByteString(cx
, v
, false, sourceDescription
, result
);
1965 template <typename T
>
1966 void DoTraceSequence(JSTracer
* trc
, FallibleTArray
<T
>& seq
);
1967 template <typename T
>
1968 void DoTraceSequence(JSTracer
* trc
, nsTArray
<T
>& seq
);
1970 // Class used to trace sequences, with specializations for various
1972 template <typename T
, bool isDictionary
= is_dom_dictionary
<T
>,
1973 bool isTypedArray
= is_dom_typed_array
<T
>,
1974 bool isOwningUnion
= is_dom_owning_union
<T
>>
1975 class SequenceTracer
{
1976 explicit SequenceTracer() = delete; // Should never be instantiated
1979 // sequence<object> or sequence<object?>
1981 class SequenceTracer
<JSObject
*, false, false, false> {
1982 explicit SequenceTracer() = delete; // Should never be instantiated
1985 static void TraceSequence(JSTracer
* trc
, JSObject
** objp
, JSObject
** end
) {
1986 for (; objp
!= end
; ++objp
) {
1987 JS::TraceRoot(trc
, objp
, "sequence<object>");
1994 class SequenceTracer
<JS::Value
, false, false, false> {
1995 explicit SequenceTracer() = delete; // Should never be instantiated
1998 static void TraceSequence(JSTracer
* trc
, JS::Value
* valp
, JS::Value
* end
) {
1999 for (; valp
!= end
; ++valp
) {
2000 JS::TraceRoot(trc
, valp
, "sequence<any>");
2005 // sequence<sequence<T>>
2006 template <typename T
>
2007 class SequenceTracer
<Sequence
<T
>, false, false, false> {
2008 explicit SequenceTracer() = delete; // Should never be instantiated
2011 static void TraceSequence(JSTracer
* trc
, Sequence
<T
>* seqp
,
2013 for (; seqp
!= end
; ++seqp
) {
2014 DoTraceSequence(trc
, *seqp
);
2019 // sequence<sequence<T>> as return value
2020 template <typename T
>
2021 class SequenceTracer
<nsTArray
<T
>, false, false, false> {
2022 explicit SequenceTracer() = delete; // Should never be instantiated
2025 static void TraceSequence(JSTracer
* trc
, nsTArray
<T
>* seqp
,
2027 for (; seqp
!= end
; ++seqp
) {
2028 DoTraceSequence(trc
, *seqp
);
2033 // sequence<someDictionary>
2034 template <typename T
>
2035 class SequenceTracer
<T
, true, false, false> {
2036 explicit SequenceTracer() = delete; // Should never be instantiated
2039 static void TraceSequence(JSTracer
* trc
, T
* dictp
, T
* end
) {
2040 for (; dictp
!= end
; ++dictp
) {
2041 dictp
->TraceDictionary(trc
);
2046 // sequence<SomeTypedArray>
2047 template <typename T
>
2048 class SequenceTracer
<T
, false, true, false> {
2049 explicit SequenceTracer() = delete; // Should never be instantiated
2052 static void TraceSequence(JSTracer
* trc
, T
* arrayp
, T
* end
) {
2053 for (; arrayp
!= end
; ++arrayp
) {
2054 arrayp
->TraceSelf(trc
);
2059 // sequence<SomeOwningUnion>
2060 template <typename T
>
2061 class SequenceTracer
<T
, false, false, true> {
2062 explicit SequenceTracer() = delete; // Should never be instantiated
2065 static void TraceSequence(JSTracer
* trc
, T
* arrayp
, T
* end
) {
2066 for (; arrayp
!= end
; ++arrayp
) {
2067 arrayp
->TraceUnion(trc
);
2072 // sequence<T?> with T? being a Nullable<T>
2073 template <typename T
>
2074 class SequenceTracer
<Nullable
<T
>, false, false, false> {
2075 explicit SequenceTracer() = delete; // Should never be instantiated
2078 static void TraceSequence(JSTracer
* trc
, Nullable
<T
>* seqp
,
2080 for (; seqp
!= end
; ++seqp
) {
2081 if (!seqp
->IsNull()) {
2082 // Pretend like we actually have a length-one sequence here so
2083 // we can do template instantiation correctly for T.
2084 T
& val
= seqp
->Value();
2086 SequenceTracer
<T
>::TraceSequence(trc
, ptr
, ptr
+ 1);
2092 template <typename K
, typename V
>
2093 void TraceRecord(JSTracer
* trc
, Record
<K
, V
>& record
) {
2094 for (auto& entry
: record
.Entries()) {
2095 // Act like it's a one-element sequence to leverage all that infrastructure.
2096 SequenceTracer
<V
>::TraceSequence(trc
, &entry
.mValue
, &entry
.mValue
+ 1);
2101 template <typename K
, typename V
>
2102 class SequenceTracer
<Record
<K
, V
>, false, false, false> {
2103 explicit SequenceTracer() = delete; // Should never be instantiated
2106 static void TraceSequence(JSTracer
* trc
, Record
<K
, V
>* seqp
,
2107 Record
<K
, V
>* end
) {
2108 for (; seqp
!= end
; ++seqp
) {
2109 TraceRecord(trc
, *seqp
);
2114 template <typename T
>
2115 void DoTraceSequence(JSTracer
* trc
, FallibleTArray
<T
>& seq
) {
2116 SequenceTracer
<T
>::TraceSequence(trc
, seq
.Elements(),
2117 seq
.Elements() + seq
.Length());
2120 template <typename T
>
2121 void DoTraceSequence(JSTracer
* trc
, nsTArray
<T
>& seq
) {
2122 SequenceTracer
<T
>::TraceSequence(trc
, seq
.Elements(),
2123 seq
.Elements() + seq
.Length());
2126 // Rooter class for sequences; this is what we mostly use in the codegen
2127 template <typename T
>
2128 class MOZ_RAII SequenceRooter final
: private JS::CustomAutoRooter
{
2130 template <typename CX
>
2131 SequenceRooter(const CX
& cx
, FallibleTArray
<T
>* aSequence
)
2132 : JS::CustomAutoRooter(cx
),
2133 mFallibleArray(aSequence
),
2134 mSequenceType(eFallibleArray
) {}
2136 template <typename CX
>
2137 SequenceRooter(const CX
& cx
, nsTArray
<T
>* aSequence
)
2138 : JS::CustomAutoRooter(cx
),
2139 mInfallibleArray(aSequence
),
2140 mSequenceType(eInfallibleArray
) {}
2142 template <typename CX
>
2143 SequenceRooter(const CX
& cx
, Nullable
<nsTArray
<T
>>* aSequence
)
2144 : JS::CustomAutoRooter(cx
),
2145 mNullableArray(aSequence
),
2146 mSequenceType(eNullableArray
) {}
2149 enum SequenceType
{ eInfallibleArray
, eFallibleArray
, eNullableArray
};
2151 virtual void trace(JSTracer
* trc
) override
{
2152 if (mSequenceType
== eFallibleArray
) {
2153 DoTraceSequence(trc
, *mFallibleArray
);
2154 } else if (mSequenceType
== eInfallibleArray
) {
2155 DoTraceSequence(trc
, *mInfallibleArray
);
2157 MOZ_ASSERT(mSequenceType
== eNullableArray
);
2158 if (!mNullableArray
->IsNull()) {
2159 DoTraceSequence(trc
, mNullableArray
->Value());
2165 nsTArray
<T
>* mInfallibleArray
;
2166 FallibleTArray
<T
>* mFallibleArray
;
2167 Nullable
<nsTArray
<T
>>* mNullableArray
;
2170 SequenceType mSequenceType
;
2173 // Rooter class for Record; this is what we mostly use in the codegen.
2174 template <typename K
, typename V
>
2175 class MOZ_RAII RecordRooter final
: private JS::CustomAutoRooter
{
2177 template <typename CX
>
2178 RecordRooter(const CX
& cx
, Record
<K
, V
>* aRecord
)
2179 : JS::CustomAutoRooter(cx
), mRecord(aRecord
), mRecordType(eRecord
) {}
2181 template <typename CX
>
2182 RecordRooter(const CX
& cx
, Nullable
<Record
<K
, V
>>* aRecord
)
2183 : JS::CustomAutoRooter(cx
),
2184 mNullableRecord(aRecord
),
2185 mRecordType(eNullableRecord
) {}
2188 enum RecordType
{ eRecord
, eNullableRecord
};
2190 virtual void trace(JSTracer
* trc
) override
{
2191 if (mRecordType
== eRecord
) {
2192 TraceRecord(trc
, *mRecord
);
2194 MOZ_ASSERT(mRecordType
== eNullableRecord
);
2195 if (!mNullableRecord
->IsNull()) {
2196 TraceRecord(trc
, mNullableRecord
->Value());
2202 Record
<K
, V
>* mRecord
;
2203 Nullable
<Record
<K
, V
>>* mNullableRecord
;
2206 RecordType mRecordType
;
2209 template <typename T
>
2210 class MOZ_RAII RootedUnion
: public T
, private JS::CustomAutoRooter
{
2212 template <typename CX
>
2213 explicit RootedUnion(const CX
& cx
) : T(), JS::CustomAutoRooter(cx
) {}
2215 virtual void trace(JSTracer
* trc
) override
{ this->TraceUnion(trc
); }
2218 template <typename T
>
2219 class MOZ_STACK_CLASS NullableRootedUnion
: public Nullable
<T
>,
2220 private JS::CustomAutoRooter
{
2222 template <typename CX
>
2223 explicit NullableRootedUnion(const CX
& cx
)
2224 : Nullable
<T
>(), JS::CustomAutoRooter(cx
) {}
2226 virtual void trace(JSTracer
* trc
) override
{
2227 if (!this->IsNull()) {
2228 this->Value().TraceUnion(trc
);
2233 inline bool AddStringToIDVector(JSContext
* cx
,
2234 JS::MutableHandleVector
<jsid
> vector
,
2236 return vector
.growBy(1) &&
2237 AtomizeAndPinJSString(cx
, *(vector
[vector
.length() - 1]).address(),
2241 // We use one constructor JSNative to represent all DOM interface objects (so
2242 // we can easily detect when we need to wrap them in an Xray wrapper). We store
2243 // the real JSNative in the mNative member of a JSNativeHolder in the
2244 // CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction object for a
2245 // specific interface object. We also store the NativeProperties in the
2247 // Note that some interface objects are not yet a JSFunction but a normal
2248 // JSObject with a DOMJSClass, those do not use these slots.
2250 enum { CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT
= 0 };
2252 bool Constructor(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
2254 // Implementation of the bits that XrayWrapper needs
2257 * This resolves operations, attributes and constants of the interfaces for obj.
2259 * wrapper is the Xray JS object.
2260 * obj is the target object of the Xray, a binding's instance object or a
2261 * interface or interface prototype object.
2263 bool XrayResolveOwnProperty(
2264 JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
, JS::Handle
<JSObject
*> obj
,
2265 JS::Handle
<jsid
> id
,
2266 JS::MutableHandle
<mozilla::Maybe
<JS::PropertyDescriptor
>> desc
,
2267 bool& cacheOnHolder
);
2270 * Define a property on obj through an Xray wrapper.
2272 * wrapper is the Xray JS object.
2273 * obj is the target object of the Xray, a binding's instance object or a
2274 * interface or interface prototype object.
2275 * id and desc are the parameters for the property to be defined.
2276 * result is the out-parameter indicating success (read it only if
2277 * this returns true and also sets *done to true).
2278 * done will be set to true if a property was set as a result of this call
2279 * or if we want to always avoid setting this property
2280 * (i.e. indexed properties on DOM objects)
2282 bool XrayDefineProperty(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
2283 JS::Handle
<JSObject
*> obj
, JS::Handle
<jsid
> id
,
2284 JS::Handle
<JS::PropertyDescriptor
> desc
,
2285 JS::ObjectOpResult
& result
, bool* done
);
2288 * Add to props the property keys of all indexed or named properties of obj and
2289 * operations, attributes and constants of the interfaces for obj.
2291 * wrapper is the Xray JS object.
2292 * obj is the target object of the Xray, a binding's instance object or a
2293 * interface or interface prototype object.
2294 * flags are JSITER_* flags.
2296 bool XrayOwnPropertyKeys(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
2297 JS::Handle
<JSObject
*> obj
, unsigned flags
,
2298 JS::MutableHandleVector
<jsid
> props
);
2301 * Returns the prototype to use for an Xray for a DOM object, wrapped in cx's
2302 * compartment. This always returns the prototype that would be used for a DOM
2303 * object if we ignore any changes that might have been done to the prototype
2304 * chain by JS, the XBL code or plugins.
2306 * cx should be in the Xray's compartment.
2307 * obj is the target object of the Xray, a binding's instance object or an
2308 * interface or interface prototype object.
2310 inline bool XrayGetNativeProto(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
2311 JS::MutableHandle
<JSObject
*> protop
) {
2312 JS::Rooted
<JSObject
*> global(cx
, JS::GetNonCCWObjectGlobal(obj
));
2314 JSAutoRealm
ar(cx
, global
);
2315 const DOMJSClass
* domClass
= GetDOMClass(obj
);
2317 ProtoHandleGetter protoGetter
= domClass
->mGetProto
;
2319 protop
.set(protoGetter(cx
));
2321 protop
.set(JS::GetRealmObjectPrototype(cx
));
2323 } else if (JS_ObjectIsFunction(obj
)) {
2324 MOZ_ASSERT(JS_IsNativeFunction(obj
, Constructor
));
2325 protop
.set(JS::GetRealmFunctionPrototype(cx
));
2327 const JSClass
* clasp
= JS::GetClass(obj
);
2328 MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp
));
2329 ProtoGetter protoGetter
=
2330 DOMIfaceAndProtoJSClass::FromJSClass(clasp
)->mGetParentProto
;
2331 protop
.set(protoGetter(cx
));
2335 return JS_WrapObject(cx
, protop
);
2339 * Get the Xray expando class to use for the given DOM object.
2341 const JSClass
* XrayGetExpandoClass(JSContext
* cx
, JS::Handle
<JSObject
*> obj
);
2344 * Delete a named property, if any. Return value is false if exception thrown,
2345 * true otherwise. The caller should not do any more work after calling this
2346 * function, because it has no way whether a deletion was performed and hence
2347 * opresult already has state set on it. If callers ever need to change that,
2348 * add a "bool* found" argument and change the generated DeleteNamedProperty to
2349 * use it instead of a local variable.
2351 bool XrayDeleteNamedProperty(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
2352 JS::Handle
<JSObject
*> obj
, JS::Handle
<jsid
> id
,
2353 JS::ObjectOpResult
& opresult
);
2355 namespace binding_detail
{
2357 // Default implementations of the NativePropertyHooks' mResolveOwnProperty and
2358 // mEnumerateOwnProperties for WebIDL bindings implemented as proxies.
2359 bool ResolveOwnProperty(
2360 JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
, JS::Handle
<JSObject
*> obj
,
2361 JS::Handle
<jsid
> id
,
2362 JS::MutableHandle
<mozilla::Maybe
<JS::PropertyDescriptor
>> desc
);
2363 bool EnumerateOwnProperties(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
2364 JS::Handle
<JSObject
*> obj
,
2365 JS::MutableHandleVector
<jsid
> props
);
2367 } // namespace binding_detail
2370 * Get the object which should be used to cache the return value of a property
2371 * getter in the case of a [Cached] or [StoreInSlot] property. `obj` is the
2372 * `this` value for our property getter that we're working with.
2374 * This function can return null on failure to allocate the object, throwing on
2375 * the JSContext in the process.
2377 * The isXray outparam will be set to true if obj is an Xray and false
2380 * Note that the Slow version should only be called from
2381 * GetCachedSlotStorageObject.
2383 JSObject
* GetCachedSlotStorageObjectSlow(JSContext
* cx
,
2384 JS::Handle
<JSObject
*> obj
,
2387 inline JSObject
* GetCachedSlotStorageObject(JSContext
* cx
,
2388 JS::Handle
<JSObject
*> obj
,
2390 if (IsDOMObject(obj
)) {
2395 return GetCachedSlotStorageObjectSlow(cx
, obj
, isXray
);
2398 extern NativePropertyHooks sEmptyNativePropertyHooks
;
2400 extern const JSClassOps sBoringInterfaceObjectClassClassOps
;
2402 extern const js::ObjectOps sInterfaceObjectClassObjectOps
;
2404 inline bool UseDOMXray(JSObject
* obj
) {
2405 const JSClass
* clasp
= JS::GetClass(obj
);
2406 return IsDOMClass(clasp
) || JS_IsNativeFunction(obj
, Constructor
) ||
2407 IsDOMIfaceAndProtoClass(clasp
);
2410 inline bool IsDOMConstructor(JSObject
* obj
) {
2411 if (JS_IsNativeFunction(obj
, dom::Constructor
)) {
2412 // LegacyFactoryFunction, like Image
2416 const JSClass
* clasp
= JS::GetClass(obj
);
2417 // Check for a DOM interface object.
2418 return dom::IsDOMIfaceAndProtoClass(clasp
) &&
2419 dom::DOMIfaceAndProtoJSClass::FromJSClass(clasp
)->mType
==
2424 inline bool HasConstructor(JSObject
* obj
) {
2425 return JS_IsNativeFunction(obj
, Constructor
) ||
2426 JS::GetClass(obj
)->getConstruct();
2430 // Helpers for creating a const version of a type.
2431 template <typename T
>
2432 const T
& Constify(T
& arg
) {
2436 // Helper for turning (Owning)NonNull<T> into T&
2437 template <typename T
>
2438 T
& NonNullHelper(T
& aArg
) {
2442 template <typename T
>
2443 T
& NonNullHelper(NonNull
<T
>& aArg
) {
2447 template <typename T
>
2448 const T
& NonNullHelper(const NonNull
<T
>& aArg
) {
2452 template <typename T
>
2453 T
& NonNullHelper(OwningNonNull
<T
>& aArg
) {
2457 template <typename T
>
2458 const T
& NonNullHelper(const OwningNonNull
<T
>& aArg
) {
2462 template <typename CharT
>
2463 inline void NonNullHelper(NonNull
<binding_detail::FakeString
<CharT
>>& aArg
) {
2464 // This overload is here to make sure that we never end up applying
2465 // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
2466 // try to, it should fail to compile, since presumably the caller will try to
2467 // use our nonexistent return value.
2470 template <typename CharT
>
2471 inline void NonNullHelper(
2472 const NonNull
<binding_detail::FakeString
<CharT
>>& aArg
) {
2473 // This overload is here to make sure that we never end up applying
2474 // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
2475 // try to, it should fail to compile, since presumably the caller will try to
2476 // use our nonexistent return value.
2479 template <typename CharT
>
2480 inline void NonNullHelper(binding_detail::FakeString
<CharT
>& aArg
) {
2481 // This overload is here to make sure that we never end up applying
2482 // NonNullHelper to a FakeString before we've constified it. If we
2483 // try to, it should fail to compile, since presumably the caller will try to
2484 // use our nonexistent return value.
2487 template <typename CharT
>
2488 MOZ_ALWAYS_INLINE
const nsTSubstring
<CharT
>& NonNullHelper(
2489 const binding_detail::FakeString
<CharT
>& aArg
) {
2493 // Given a DOM reflector aObj, give its underlying DOM object a reflector in
2494 // whatever global that underlying DOM object now thinks it should be in. If
2495 // this is in a different compartment from aObj, aObj will become a
2496 // cross-compatment wrapper for the new object. Otherwise, aObj will become the
2497 // new object (via a brain transplant). If the new global is the same as the
2498 // old global, we just keep using the same object.
2500 // On entry to this method, aCx and aObj must be same-compartment.
2501 void UpdateReflectorGlobal(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
,
2502 ErrorResult
& aError
);
2504 // Helper for lenient getters/setters to report to console. If this
2505 // returns false, we couldn't even get a global.
2506 bool ReportLenientThisUnwrappingFailure(JSContext
* cx
, JSObject
* obj
);
2508 // Given a JSObject* that represents the chrome side of a JS-implemented WebIDL
2509 // interface, get the nsIGlobalObject corresponding to the content side, if any.
2510 // A false return means an exception was thrown.
2511 bool GetContentGlobalForJSImplementedObject(BindingCallContext
& cx
,
2512 JS::Handle
<JSObject
*> obj
,
2513 nsIGlobalObject
** global
);
2515 void ConstructJSImplementation(const char* aContractId
,
2516 nsIGlobalObject
* aGlobal
,
2517 JS::MutableHandle
<JSObject
*> aObject
,
2520 // XXX Avoid pulling in the whole ScriptSettings.h, however there should be a
2521 // unique declaration of this function somewhere else.
2522 JS::RootingContext
* RootingCx();
2524 template <typename T
>
2525 already_AddRefed
<T
> ConstructJSImplementation(const char* aContractId
,
2526 nsIGlobalObject
* aGlobal
,
2528 JS::RootingContext
* cx
= RootingCx();
2529 JS::Rooted
<JSObject
*> jsImplObj(cx
);
2530 ConstructJSImplementation(aContractId
, aGlobal
, &jsImplObj
, aRv
);
2535 MOZ_RELEASE_ASSERT(!js::IsWrapper(jsImplObj
));
2536 JS::Rooted
<JSObject
*> jsImplGlobal(cx
, JS::GetNonCCWObjectGlobal(jsImplObj
));
2537 RefPtr
<T
> newObj
= new T(jsImplObj
, jsImplGlobal
, aGlobal
);
2538 return newObj
.forget();
2541 template <typename T
>
2542 already_AddRefed
<T
> ConstructJSImplementation(const char* aContractId
,
2543 const GlobalObject
& aGlobal
,
2545 nsCOMPtr
<nsIGlobalObject
> global
= do_QueryInterface(aGlobal
.GetAsSupports());
2547 aRv
.Throw(NS_ERROR_FAILURE
);
2551 return ConstructJSImplementation
<T
>(aContractId
, global
, aRv
);
2555 * Convert an nsCString to jsval, returning true on success.
2556 * These functions are intended for ByteString implementations.
2557 * As such, the string is not UTF-8 encoded. Any UTF8 strings passed to these
2558 * methods will be mangled.
2560 inline bool NonVoidByteStringToJsval(JSContext
* cx
, const nsACString
& str
,
2561 JS::MutableHandle
<JS::Value
> rval
) {
2562 return xpc::NonVoidLatin1StringToJsval(cx
, str
, rval
);
2564 inline bool ByteStringToJsval(JSContext
* cx
, const nsACString
& str
,
2565 JS::MutableHandle
<JS::Value
> rval
) {
2570 return NonVoidByteStringToJsval(cx
, str
, rval
);
2573 // Convert an utf-8 encoded nsCString to jsval, returning true on success.
2575 // TODO(bug 1606957): This could probably be better.
2576 inline bool NonVoidUTF8StringToJsval(JSContext
* cx
, const nsACString
& str
,
2577 JS::MutableHandle
<JS::Value
> rval
) {
2578 return xpc::NonVoidUTF8StringToJsval(cx
, str
, rval
);
2581 inline bool UTF8StringToJsval(JSContext
* cx
, const nsACString
& str
,
2582 JS::MutableHandle
<JS::Value
> rval
) {
2587 return NonVoidUTF8StringToJsval(cx
, str
, rval
);
2590 template <class T
, bool isISupports
= std::is_base_of
<nsISupports
, T
>::value
>
2591 struct PreserveWrapperHelper
{
2592 static void PreserveWrapper(T
* aObject
) {
2593 aObject
->PreserveWrapper(aObject
, NS_CYCLE_COLLECTION_PARTICIPANT(T
));
2598 struct PreserveWrapperHelper
<T
, true> {
2599 static void PreserveWrapper(T
* aObject
) {
2600 aObject
->PreserveWrapper(reinterpret_cast<nsISupports
*>(aObject
));
2605 void PreserveWrapper(T
* aObject
) {
2606 PreserveWrapperHelper
<T
>::PreserveWrapper(aObject
);
2609 template <class T
, bool isISupports
= std::is_base_of
<nsISupports
, T
>::value
>
2610 struct CastingAssertions
{
2611 static bool ToSupportsIsCorrect(T
*) { return true; }
2612 static bool ToSupportsIsOnPrimaryInheritanceChain(T
*, nsWrapperCache
*) {
2618 struct CastingAssertions
<T
, true> {
2619 static bool ToSupportsIsCorrect(T
* aObject
) {
2620 return ToSupports(aObject
) == reinterpret_cast<nsISupports
*>(aObject
);
2622 static bool ToSupportsIsOnPrimaryInheritanceChain(T
* aObject
,
2623 nsWrapperCache
* aCache
) {
2624 return reinterpret_cast<void*>(aObject
) != aCache
;
2629 bool ToSupportsIsCorrect(T
* aObject
) {
2630 return CastingAssertions
<T
>::ToSupportsIsCorrect(aObject
);
2634 bool ToSupportsIsOnPrimaryInheritanceChain(T
* aObject
, nsWrapperCache
* aCache
) {
2635 return CastingAssertions
<T
>::ToSupportsIsOnPrimaryInheritanceChain(aObject
,
2639 // Get the size of allocated memory to associate with a binding JSObject for a
2640 // native object. This is supplied to the JS engine to allow it to schedule GC
2643 // This function supplies a default value and is overloaded for specific native
2645 inline size_t BindingJSObjectMallocBytes(void* aNativePtr
) { return 0; }
2647 // The BindingJSObjectCreator class is supposed to be used by a caller that
2648 // wants to create and initialise a binding JSObject. After initialisation has
2649 // been successfully completed it should call InitializationSucceeded().
2650 // The BindingJSObjectCreator object will root the JSObject until
2651 // InitializationSucceeded() is called on it. If the native object for the
2652 // binding is refcounted it will also hold a strong reference to it, that
2653 // reference is transferred to the JSObject (which holds the native in a slot)
2654 // when InitializationSucceeded() is called. If the BindingJSObjectCreator
2655 // object is destroyed and InitializationSucceeded() was never called on it then
2656 // the JSObject's slot holding the native will be set to undefined, and for a
2657 // refcounted native the strong reference will be released.
2659 class MOZ_STACK_CLASS BindingJSObjectCreator
{
2661 explicit BindingJSObjectCreator(JSContext
* aCx
) : mReflector(aCx
) {}
2663 ~BindingJSObjectCreator() {
2665 JS::SetReservedSlot(mReflector
, DOM_OBJECT_SLOT
, JS::UndefinedValue());
2669 void CreateProxyObject(JSContext
* aCx
, const JSClass
* aClass
,
2670 const DOMProxyHandler
* aHandler
,
2671 JS::Handle
<JSObject
*> aProto
, bool aLazyProto
,
2672 T
* aNative
, JS::Handle
<JS::Value
> aExpandoValue
,
2673 JS::MutableHandle
<JSObject
*> aReflector
) {
2674 js::ProxyOptions options
;
2675 options
.setClass(aClass
);
2676 options
.setLazyProto(aLazyProto
);
2679 js::NewProxyObject(aCx
, aHandler
, aExpandoValue
, aProto
, options
));
2681 js::SetProxyReservedSlot(aReflector
, DOM_OBJECT_SLOT
,
2682 JS::PrivateValue(aNative
));
2684 mReflector
= aReflector
;
2686 if (size_t mallocBytes
= BindingJSObjectMallocBytes(aNative
)) {
2687 JS::AddAssociatedMemory(aReflector
, mallocBytes
,
2688 JS::MemoryUse::DOMBinding
);
2693 void CreateObject(JSContext
* aCx
, const JSClass
* aClass
,
2694 JS::Handle
<JSObject
*> aProto
, T
* aNative
,
2695 JS::MutableHandle
<JSObject
*> aReflector
) {
2696 aReflector
.set(JS_NewObjectWithGivenProto(aCx
, aClass
, aProto
));
2698 JS::SetReservedSlot(aReflector
, DOM_OBJECT_SLOT
,
2699 JS::PrivateValue(aNative
));
2701 mReflector
= aReflector
;
2703 if (size_t mallocBytes
= BindingJSObjectMallocBytes(aNative
)) {
2704 JS::AddAssociatedMemory(aReflector
, mallocBytes
,
2705 JS::MemoryUse::DOMBinding
);
2710 void InitializationSucceeded() {
2712 mNative
.forget(&pointer
);
2713 mReflector
= nullptr;
2717 struct OwnedNative
{
2718 // Make sure the native objects inherit from NonRefcountedDOMObject so
2719 // that we log their ctor and dtor.
2720 static_assert(std::is_base_of
<NonRefcountedDOMObject
, T
>::value
,
2721 "Non-refcounted objects with DOM bindings should inherit "
2722 "from NonRefcountedDOMObject.");
2724 OwnedNative
& operator=(T
* aNative
) {
2729 // This signature sucks, but it's the only one that will make a nsRefPtr
2730 // just forget about its pointer without warning.
2731 void forget(T
** aResult
) {
2736 // Keep track of the pointer for use in InitializationSucceeded().
2737 // The caller (or, after initialization succeeds, the JS object) retains
2738 // ownership of the object.
2742 JS::Rooted
<JSObject
*> mReflector
;
2743 std::conditional_t
<IsRefcounted
<T
>::value
, RefPtr
<T
>, OwnedNative
> mNative
;
2747 struct DeferredFinalizerImpl
{
2748 using SmartPtr
= std::conditional_t
<
2749 std::is_same_v
<T
, nsISupports
>, nsCOMPtr
<T
>,
2750 std::conditional_t
<IsRefcounted
<T
>::value
, RefPtr
<T
>, UniquePtr
<T
>>>;
2751 typedef SegmentedVector
<SmartPtr
> SmartPtrArray
;
2754 std::is_same_v
<T
, nsISupports
> || !std::is_base_of
<nsISupports
, T
>::value
,
2755 "nsISupports classes should all use the nsISupports instantiation");
2757 static inline void AppendAndTake(
2758 SegmentedVector
<nsCOMPtr
<nsISupports
>>& smartPtrArray
, nsISupports
* ptr
) {
2759 smartPtrArray
.InfallibleAppend(dont_AddRef(ptr
));
2762 static inline void AppendAndTake(SegmentedVector
<RefPtr
<U
>>& smartPtrArray
,
2764 smartPtrArray
.InfallibleAppend(dont_AddRef(ptr
));
2767 static inline void AppendAndTake(SegmentedVector
<UniquePtr
<U
>>& smartPtrArray
,
2769 smartPtrArray
.InfallibleAppend(ptr
);
2772 static void* AppendDeferredFinalizePointer(void* aData
, void* aObject
) {
2773 SmartPtrArray
* pointers
= static_cast<SmartPtrArray
*>(aData
);
2775 pointers
= new SmartPtrArray();
2777 AppendAndTake(*pointers
, static_cast<T
*>(aObject
));
2780 static bool DeferredFinalize(uint32_t aSlice
, void* aData
) {
2781 MOZ_ASSERT(aSlice
> 0, "nonsensical/useless call with aSlice == 0");
2782 SmartPtrArray
* pointers
= static_cast<SmartPtrArray
*>(aData
);
2783 uint32_t oldLen
= pointers
->Length();
2784 if (oldLen
< aSlice
) {
2787 uint32_t newLen
= oldLen
- aSlice
;
2788 pointers
->PopLastN(aSlice
);
2797 template <class T
, bool isISupports
= std::is_base_of
<nsISupports
, T
>::value
>
2798 struct DeferredFinalizer
{
2799 static void AddForDeferredFinalization(T
* aObject
) {
2800 typedef DeferredFinalizerImpl
<T
> Impl
;
2801 DeferredFinalize(Impl::AppendDeferredFinalizePointer
,
2802 Impl::DeferredFinalize
, aObject
);
2807 struct DeferredFinalizer
<T
, true> {
2808 static void AddForDeferredFinalization(T
* aObject
) {
2809 DeferredFinalize(reinterpret_cast<nsISupports
*>(aObject
));
2814 static void AddForDeferredFinalization(T
* aObject
) {
2815 DeferredFinalizer
<T
>::AddForDeferredFinalization(aObject
);
2818 // This returns T's CC participant if it participates in CC and does not inherit
2819 // from nsISupports. Otherwise, it returns null. QI should be used to get the
2820 // participant if T inherits from nsISupports.
2821 template <class T
, bool isISupports
= std::is_base_of
<nsISupports
, T
>::value
>
2822 class GetCCParticipant
{
2823 // Helper for GetCCParticipant for classes that participate in CC.
2825 static constexpr nsCycleCollectionParticipant
* GetHelper(
2826 int, typename
U::NS_CYCLE_COLLECTION_INNERCLASS
* dummy
= nullptr) {
2827 return T::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant();
2829 // Helper for GetCCParticipant for classes that don't participate in CC.
2831 static constexpr nsCycleCollectionParticipant
* GetHelper(double) {
2836 static constexpr nsCycleCollectionParticipant
* Get() {
2837 // Passing int() here will try to call the GetHelper that takes an int as
2838 // its first argument. If T doesn't participate in CC then substitution for
2839 // the second argument (with a default value) will fail and because of
2840 // SFINAE the next best match (the variant taking a double) will be called.
2841 return GetHelper
<T
>(int());
2846 class GetCCParticipant
<T
, true> {
2848 static constexpr nsCycleCollectionParticipant
* Get() { return nullptr; }
2851 void FinalizeGlobal(JS::GCContext
* aGcx
, JSObject
* aObj
);
2853 bool ResolveGlobal(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
,
2854 JS::Handle
<jsid
> aId
, bool* aResolvedp
);
2856 bool MayResolveGlobal(const JSAtomState
& aNames
, jsid aId
, JSObject
* aMaybeObj
);
2858 bool EnumerateGlobal(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
,
2859 JS::MutableHandleVector
<jsid
> aProperties
,
2860 bool aEnumerableOnly
);
2862 struct CreateGlobalOptionsGeneric
{
2863 static void TraceGlobal(JSTracer
* aTrc
, JSObject
* aObj
) {
2864 mozilla::dom::TraceProtoAndIfaceCache(aTrc
, aObj
);
2866 static bool PostCreateGlobal(JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
) {
2867 MOZ_ALWAYS_TRUE(TryPreserveWrapper(aGlobal
));
2873 struct CreateGlobalOptionsWithXPConnect
{
2874 static void TraceGlobal(JSTracer
* aTrc
, JSObject
* aObj
);
2875 static bool PostCreateGlobal(JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
);
2879 using IsGlobalWithXPConnect
=
2880 std::integral_constant
<bool,
2881 std::is_base_of
<nsGlobalWindowInner
, T
>::value
||
2882 std::is_base_of
<MessageManagerGlobal
, T
>::value
>;
2885 struct CreateGlobalOptions
2886 : std::conditional_t
<IsGlobalWithXPConnect
<T
>::value
,
2887 CreateGlobalOptionsWithXPConnect
,
2888 CreateGlobalOptionsGeneric
> {
2889 static constexpr ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind
=
2890 ProtoAndIfaceCache::NonWindowLike
;
2894 struct CreateGlobalOptions
<nsGlobalWindowInner
>
2895 : public CreateGlobalOptionsWithXPConnect
{
2896 static constexpr ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind
=
2897 ProtoAndIfaceCache::WindowLike
;
2900 uint64_t GetWindowID(void* aGlobal
);
2901 uint64_t GetWindowID(nsGlobalWindowInner
* aGlobal
);
2902 uint64_t GetWindowID(DedicatedWorkerGlobalScope
* aGlobal
);
2904 // The return value is true if we created and successfully performed our part of
2905 // the setup for the global, false otherwise.
2907 // Typically this method's caller will want to ensure that
2908 // xpc::InitGlobalObjectOptions is called before, and xpc::InitGlobalObject is
2909 // called after, this method, to ensure that this global object and its
2910 // compartment are consistent with other global objects.
2911 template <class T
, ProtoHandleGetter GetProto
>
2912 bool CreateGlobal(JSContext
* aCx
, T
* aNative
, nsWrapperCache
* aCache
,
2913 const JSClass
* aClass
, JS::RealmOptions
& aOptions
,
2914 JSPrincipals
* aPrincipal
,
2915 JS::MutableHandle
<JSObject
*> aGlobal
) {
2916 aOptions
.creationOptions()
2917 .setTrace(CreateGlobalOptions
<T
>::TraceGlobal
)
2918 .setProfilerRealmID(GetWindowID(aNative
));
2919 xpc::SetPrefableRealmOptions(aOptions
);
2921 aGlobal
.set(JS_NewGlobalObject(aCx
, aClass
, aPrincipal
,
2922 JS::DontFireOnNewGlobalHook
, aOptions
));
2924 NS_WARNING("Failed to create global");
2928 JSAutoRealm
ar(aCx
, aGlobal
);
2931 JS::SetReservedSlot(aGlobal
, DOM_OBJECT_SLOT
, JS::PrivateValue(aNative
));
2934 aCache
->SetWrapper(aGlobal
);
2936 dom::AllocateProtoAndIfaceCache(
2937 aGlobal
, CreateGlobalOptions
<T
>::ProtoAndIfaceCacheKind
);
2939 if (!CreateGlobalOptions
<T
>::PostCreateGlobal(aCx
, aGlobal
)) {
2943 // Initializing this at this point for nsGlobalWindowInner makes no sense,
2944 // because GetRTPCallerType doesn't return the correct result before
2945 // the global is completely initialized with a document.
2946 if constexpr (!std::is_base_of_v
<nsGlobalWindowInner
, T
>) {
2947 JS::SetRealmReduceTimerPrecisionCallerType(
2948 js::GetNonCCWObjectRealm(aGlobal
),
2949 RTPCallerTypeToToken(aNative
->GetRTPCallerType()));
2953 JS::Handle
<JSObject
*> proto
= GetProto(aCx
);
2954 if (!proto
|| !JS_SetPrototype(aCx
, aGlobal
, proto
)) {
2955 NS_WARNING("Failed to set proto");
2960 if (!JS_SetImmutablePrototype(aCx
, aGlobal
, &succeeded
)) {
2963 MOZ_ASSERT(succeeded
,
2964 "making a fresh global object's [[Prototype]] immutable can "
2965 "internally fail, but it should never be unsuccessful");
2970 namespace binding_detail
{
2972 * WebIDL getters have a "generic" JSNative that is responsible for the
2975 * 1) Determining the "this" pointer for the C++ call.
2976 * 2) Extracting the "specialized" getter from the jitinfo on the JSFunction.
2977 * 3) Calling the specialized getter.
2978 * 4) Handling exceptions as needed.
2980 * There are several variants of (1) depending on the interface involved and
2981 * there are two variants of (4) depending on whether the return type is a
2982 * Promise. We handle this by templating our generic getter on a
2983 * this-determination policy and an exception handling policy, then explicitly
2984 * instantiating the relevant template specializations.
2986 template <typename ThisPolicy
, typename ExceptionPolicy
>
2987 bool GenericGetter(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
2990 * WebIDL setters have a "generic" JSNative that is responsible for the
2993 * 1) Determining the "this" pointer for the C++ call.
2994 * 2) Extracting the "specialized" setter from the jitinfo on the JSFunction.
2995 * 3) Calling the specialized setter.
2997 * There are several variants of (1) depending on the interface
2998 * involved. We handle this by templating our generic setter on a
2999 * this-determination policy, then explicitly instantiating the
3000 * relevant template specializations.
3002 template <typename ThisPolicy
>
3003 bool GenericSetter(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
3006 * WebIDL methods have a "generic" JSNative that is responsible for the
3009 * 1) Determining the "this" pointer for the C++ call.
3010 * 2) Extracting the "specialized" method from the jitinfo on the JSFunction.
3011 * 3) Calling the specialized methodx.
3012 * 4) Handling exceptions as needed.
3014 * There are several variants of (1) depending on the interface involved and
3015 * there are two variants of (4) depending on whether the return type is a
3016 * Promise. We handle this by templating our generic method on a
3017 * this-determination policy and an exception handling policy, then explicitly
3018 * instantiating the relevant template specializations.
3020 template <typename ThisPolicy
, typename ExceptionPolicy
>
3021 bool GenericMethod(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
3023 // A this-extraction policy for normal getters/setters/methods.
3024 struct NormalThisPolicy
;
3026 // A this-extraction policy for getters/setters/methods on interfaces
3027 // that are on some global's proto chain.
3028 struct MaybeGlobalThisPolicy
;
3030 // A this-extraction policy for lenient getters/setters.
3031 struct LenientThisPolicy
;
3033 // A this-extraction policy for cross-origin getters/setters/methods.
3034 struct CrossOriginThisPolicy
;
3036 // A this-extraction policy for getters/setters/methods that should
3037 // not be allowed to be called cross-origin but expect objects that
3038 // _can_ be cross-origin.
3039 struct MaybeCrossOriginObjectThisPolicy
;
3041 // A this-extraction policy which is just like
3042 // MaybeCrossOriginObjectThisPolicy but has lenient-this behavior.
3043 struct MaybeCrossOriginObjectLenientThisPolicy
;
3045 // An exception-reporting policy for normal getters/setters/methods.
3046 struct ThrowExceptions
;
3048 // An exception-handling policy for Promise-returning getters/methods.
3049 struct ConvertExceptionsToPromises
;
3050 } // namespace binding_detail
3052 bool StaticMethodPromiseWrapper(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
3054 // ConvertExceptionToPromise should only be called when we have an error
3055 // condition (e.g. returned false from a JSAPI method). Note that there may be
3056 // no exception on cx, in which case this is an uncatchable failure that will
3057 // simply be propagated. Otherwise this method will attempt to convert the
3058 // exception to a Promise rejected with the exception that it will store in
3060 bool ConvertExceptionToPromise(JSContext
* cx
,
3061 JS::MutableHandle
<JS::Value
> rval
);
3064 void AssertReturnTypeMatchesJitinfo(const JSJitInfo
* aJitinfo
,
3065 JS::Handle
<JS::Value
> aValue
);
3068 bool CallerSubsumes(JSObject
* aObject
);
3070 MOZ_ALWAYS_INLINE
bool CallerSubsumes(JS::Handle
<JS::Value
> aValue
) {
3071 if (!aValue
.isObject()) {
3074 return CallerSubsumes(&aValue
.toObject());
3077 template <class T
, class S
>
3078 inline RefPtr
<T
> StrongOrRawPtr(already_AddRefed
<S
>&& aPtr
) {
3079 return std::move(aPtr
);
3082 template <class T
, class S
>
3083 inline RefPtr
<T
> StrongOrRawPtr(RefPtr
<S
>&& aPtr
) {
3084 return std::move(aPtr
);
3087 template <class T
, typename
= std::enable_if_t
<IsRefcounted
<T
>::value
>>
3088 inline T
* StrongOrRawPtr(T
* aPtr
) {
3092 template <class T
, class S
,
3093 typename
= std::enable_if_t
<!IsRefcounted
<S
>::value
>>
3094 inline UniquePtr
<T
> StrongOrRawPtr(UniquePtr
<S
>&& aPtr
) {
3095 return std::move(aPtr
);
3098 template <class T
, template <typename
> class SmartPtr
, class S
>
3099 inline void StrongOrRawPtr(SmartPtr
<S
>&& aPtr
) = delete;
3102 using StrongPtrForMember
=
3103 std::conditional_t
<IsRefcounted
<T
>::value
, RefPtr
<T
>, UniquePtr
<T
>>;
3105 namespace binding_detail
{
3106 inline JSObject
* GetHackedNamespaceProtoObject(JSContext
* aCx
) {
3107 return JS_NewPlainObject(aCx
);
3109 } // namespace binding_detail
3111 // Resolve an id on the given global object that wants to be included in
3112 // Exposed=System webidl annotations. False return value means exception
3114 bool SystemGlobalResolve(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
3115 JS::Handle
<jsid
> id
, bool* resolvedp
);
3117 // Enumerate all ids on the given global object that wants to be included in
3118 // Exposed=System webidl annotations. False return value means exception
3120 bool SystemGlobalEnumerate(JSContext
* cx
, JS::Handle
<JSObject
*> obj
);
3122 // Slot indexes for maplike/setlike forEach functions
3123 #define FOREACH_CALLBACK_SLOT 0
3124 #define FOREACH_MAPLIKEORSETLIKEOBJ_SLOT 1
3126 // Backing function for running .forEach() on maplike/setlike interfaces.
3127 // Unpacks callback and maplike/setlike object from reserved slots, then runs
3128 // callback for each key (and value, for maplikes)
3129 bool ForEachHandler(JSContext
* aCx
, unsigned aArgc
, JS::Value
* aVp
);
3131 // Unpacks backing object (ES6 map/set) from the reserved slot of a reflector
3132 // for a maplike/setlike interface. If backing object does not exist, creates
3133 // backing object in the compartment of the reflector involved, making this safe
3134 // to use across compartments/via xrays. Return values of these methods will
3135 // always be in the context compartment.
3136 bool GetMaplikeBackingObject(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
,
3138 JS::MutableHandle
<JSObject
*> aBackingObj
,
3139 bool* aBackingObjCreated
);
3140 bool GetSetlikeBackingObject(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
,
3142 JS::MutableHandle
<JSObject
*> aBackingObj
,
3143 bool* aBackingObjCreated
);
3145 // Unpacks backing object (ES Proxy exotic object) from the reserved slot of a
3146 // reflector for a observableArray attribute. If backing object does not exist,
3147 // creates backing object in the compartment of the reflector involved, making
3148 // this safe to use across compartments/via xrays. Return values of these
3149 // methods will always be in the context compartment.
3150 bool GetObservableArrayBackingObject(
3151 JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
, size_t aSlotIndex
,
3152 JS::MutableHandle
<JSObject
*> aBackingObj
, bool* aBackingObjCreated
,
3153 const ObservableArrayProxyHandler
* aHandler
, void* aOwner
);
3155 // Get the desired prototype object for an object construction from the given
3156 // CallArgs. The CallArgs must be for a constructor call. The
3157 // aProtoId/aCreator arguments are used to get a default if we don't find a
3158 // prototype on the newTarget of the callargs.
3159 bool GetDesiredProto(JSContext
* aCx
, const JS::CallArgs
& aCallArgs
,
3160 prototypes::id::ID aProtoId
,
3161 CreateInterfaceObjectsMethod aCreator
,
3162 JS::MutableHandle
<JSObject
*> aDesiredProto
);
3164 // This function is expected to be called from the constructor function for an
3165 // HTML or XUL element interface; the global/callargs need to be whatever was
3166 // passed to that constructor function.
3167 already_AddRefed
<Element
> CreateXULOrHTMLElement(
3168 const GlobalObject
& aGlobal
, const JS::CallArgs
& aCallArgs
,
3169 JS::Handle
<JSObject
*> aGivenProto
, ErrorResult
& aRv
);
3171 void SetUseCounter(JSObject
* aObject
, UseCounter aUseCounter
);
3172 void SetUseCounter(UseCounterWorker aUseCounter
);
3175 void DeprecationWarning(JSContext
* aCx
, JSObject
* aObject
,
3176 DeprecatedOperations aOperation
);
3178 void DeprecationWarning(const GlobalObject
& aGlobal
,
3179 DeprecatedOperations aOperation
);
3181 // A callback to perform funToString on an interface object
3182 JSString
* InterfaceObjectToString(JSContext
* aCx
, JS::Handle
<JSObject
*> aObject
,
3183 unsigned /* indent */);
3185 namespace binding_detail
{
3186 // Get a JS global object that can be used for some temporary allocations. The
3187 // idea is that this should be used for situations when you need to operate in
3188 // _some_ compartment but don't care which one. A typical example is when you
3189 // have non-JS input, non-JS output, but have to go through some sort of JS
3190 // representation in the middle, so need a compartment to allocate things in.
3192 // It's VERY important that any consumers of this function only do things that
3193 // are guaranteed to be side-effect-free, even in the face of a script
3194 // environment controlled by a hostile adversary. This is because in the worker
3195 // case the global is in fact the worker global, so it and its standard objects
3196 // are controlled by the worker script. This is why this function is in the
3197 // binding_detail namespace. Any use of this function MUST be very carefully
3198 // reviewed by someone who is sufficiently devious and has a very good
3199 // understanding of all the code that will run while we're using the return
3200 // value, including the SpiderMonkey parts.
3201 JSObject
* UnprivilegedJunkScopeOrWorkerGlobal(const fallible_t
&);
3203 // Implementation of the [HTMLConstructor] extended attribute.
3204 bool HTMLConstructor(JSContext
* aCx
, unsigned aArgc
, JS::Value
* aVp
,
3205 constructors::id::ID aConstructorId
,
3206 prototypes::id::ID aProtoId
,
3207 CreateInterfaceObjectsMethod aCreator
);
3209 // A method to test whether an attribute with the given JSJitGetterOp getter is
3210 // enabled in the given set of prefable proeprty specs. For use for toJSON
3211 // conversions. aObj is the object that would be used as the "this" value.
3212 bool IsGetterEnabled(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
,
3213 JSJitGetterOp aGetter
,
3214 const Prefable
<const JSPropertySpec
>* aAttributes
);
3216 // A class that can be used to examine the chars of a linear string.
3217 class StringIdChars
{
3219 // Require a non-const ref to an AutoRequireNoGC to prevent callers
3220 // from passing temporaries.
3221 StringIdChars(JS::AutoRequireNoGC
& nogc
, JSLinearString
* str
) {
3222 mIsLatin1
= JS::LinearStringHasLatin1Chars(str
);
3224 mLatin1Chars
= JS::GetLatin1LinearStringChars(nogc
, str
);
3226 mTwoByteChars
= JS::GetTwoByteLinearStringChars(nogc
, str
);
3229 mLength
= JS::GetLinearStringLength(str
);
3233 MOZ_ALWAYS_INLINE char16_t
operator[](size_t index
) {
3234 MOZ_ASSERT(index
< mLength
);
3236 return mLatin1Chars
[index
];
3238 return mTwoByteChars
[index
];
3244 const JS::Latin1Char
* mLatin1Chars
;
3245 const char16_t
* mTwoByteChars
;
3252 already_AddRefed
<Promise
> CreateRejectedPromiseFromThrownException(
3253 JSContext
* aCx
, ErrorResult
& aError
);
3255 } // namespace binding_detail
3258 } // namespace mozilla
3260 #endif /* mozilla_dom_BindingUtils_h__ */