1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 /* vim: set ts=2 sw=2 et tw=79: */
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 "jsfriendapi.h"
11 #include "jswrapper.h"
12 #include "mozilla/ArrayUtils.h"
13 #include "mozilla/Alignment.h"
14 #include "mozilla/Array.h"
15 #include "mozilla/Assertions.h"
16 #include "mozilla/dom/BindingDeclarations.h"
17 #include "mozilla/dom/CallbackObject.h"
18 #include "mozilla/dom/DOMJSClass.h"
19 #include "mozilla/dom/DOMJSProxyHandler.h"
20 #include "mozilla/dom/Exceptions.h"
21 #include "mozilla/dom/NonRefcountedDOMObject.h"
22 #include "mozilla/dom/Nullable.h"
23 #include "mozilla/dom/RootedDictionary.h"
24 #include "mozilla/dom/workers/Workers.h"
25 #include "mozilla/ErrorResult.h"
26 #include "mozilla/Likely.h"
27 #include "mozilla/MemoryReporting.h"
28 #include "nsCycleCollector.h"
29 #include "nsIXPConnect.h"
30 #include "nsJSUtils.h"
31 #include "MainThreadUtils.h"
32 #include "nsISupportsImpl.h"
33 #include "qsObjectHelper.h"
34 #include "xpcpublic.h"
35 #include "nsIVariant.h"
36 #include "pldhash.h" // For PLDHashOperator
38 #include "nsWrapperCacheInlines.h"
44 xpc_qsUnwrapArgImpl(JSContext
* cx
, JS::Handle
<JS::Value
> v
, const nsIID
& iid
, void** ppArg
,
45 nsISupports
** ppArgRef
, JS::MutableHandle
<JS::Value
> vp
);
49 template<typename DataType
> class MozMap
;
53 SelfRef() : ptr(nullptr) {}
54 explicit SelfRef(nsISupports
*p
) : ptr(p
) {}
55 ~SelfRef() { NS_IF_RELEASE(ptr
); }
60 /** Convert a jsval to an XPCOM pointer. */
61 template <class Interface
, class StrongRefType
>
63 UnwrapArg(JSContext
* cx
, JS::Handle
<JS::Value
> v
, Interface
** ppArg
,
64 StrongRefType
** ppArgRef
, JS::MutableHandle
<JS::Value
> vp
)
66 nsISupports
* argRef
= *ppArgRef
;
67 nsresult rv
= xpc_qsUnwrapArgImpl(cx
, v
, NS_GET_TEMPLATE_IID(Interface
),
68 reinterpret_cast<void**>(ppArg
), &argRef
,
70 *ppArgRef
= static_cast<StrongRefType
*>(argRef
);
75 GetInvalidThisErrorForMethod(bool aSecurityError
)
77 return aSecurityError
? MSG_METHOD_THIS_UNWRAPPING_DENIED
:
78 MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE
;
82 GetInvalidThisErrorForGetter(bool aSecurityError
)
84 return aSecurityError
? MSG_GETTER_THIS_UNWRAPPING_DENIED
:
85 MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE
;
89 GetInvalidThisErrorForSetter(bool aSecurityError
)
91 return aSecurityError
? MSG_SETTER_THIS_UNWRAPPING_DENIED
:
92 MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE
;
96 ThrowInvalidThis(JSContext
* aCx
, const JS::CallArgs
& aArgs
,
97 const ErrNum aErrorNumber
,
98 const char* aInterfaceName
);
101 ThrowInvalidThis(JSContext
* aCx
, const JS::CallArgs
& aArgs
,
102 const ErrNum aErrorNumber
,
103 prototypes::ID aProtoId
);
106 ThrowMethodFailedWithDetails(JSContext
* cx
, ErrorResult
& rv
,
107 const char* ifaceName
,
108 const char* memberName
,
109 bool reportJSContentExceptions
= false)
111 if (rv
.IsTypeError()) {
112 rv
.ReportTypeError(cx
);
115 if (rv
.IsJSException()) {
116 if (reportJSContentExceptions
) {
117 rv
.ReportJSExceptionFromJSImplementation(cx
);
119 rv
.ReportJSException(cx
);
123 if (rv
.IsNotEnoughArgsError()) {
124 rv
.ReportNotEnoughArgsError(cx
, ifaceName
, memberName
);
127 return Throw(cx
, rv
.ErrorCode());
130 // Returns true if the JSClass is used for DOM objects.
132 IsDOMClass(const JSClass
* clasp
)
134 return clasp
->flags
& JSCLASS_IS_DOMJSCLASS
;
138 IsDOMClass(const js::Class
* clasp
)
140 return IsDOMClass(Jsvalify(clasp
));
143 // Return true if the JSClass is used for non-proxy DOM objects.
145 IsNonProxyDOMClass(const js::Class
* clasp
)
147 return IsDOMClass(clasp
) && !clasp
->isProxy();
151 IsNonProxyDOMClass(const JSClass
* clasp
)
153 return IsNonProxyDOMClass(js::Valueify(clasp
));
156 // Returns true if the JSClass is used for DOM interface and interface
157 // prototype objects.
159 IsDOMIfaceAndProtoClass(const JSClass
* clasp
)
161 return clasp
->flags
& JSCLASS_IS_DOMIFACEANDPROTOJSCLASS
;
165 IsDOMIfaceAndProtoClass(const js::Class
* clasp
)
167 return IsDOMIfaceAndProtoClass(Jsvalify(clasp
));
170 static_assert(DOM_OBJECT_SLOT
== js::PROXY_PRIVATE_SLOT
,
171 "js::PROXY_PRIVATE_SLOT doesn't match DOM_OBJECT_SLOT. "
172 "Expect bad things");
175 UnwrapDOMObject(JSObject
* obj
)
177 MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj
)),
178 "Don't pass non-DOM objects to this function");
180 JS::Value val
= js::GetReservedSlot(obj
, DOM_OBJECT_SLOT
);
181 return static_cast<T
*>(val
.toPrivate());
184 inline const DOMJSClass
*
185 GetDOMClass(JSObject
* obj
)
187 const js::Class
* clasp
= js::GetObjectClass(obj
);
188 if (IsDOMClass(clasp
)) {
189 return DOMJSClass::FromJSClass(clasp
);
195 UnwrapDOMObjectToISupports(JSObject
* aObject
)
197 const DOMJSClass
* clasp
= GetDOMClass(aObject
);
198 if (!clasp
|| !clasp
->mDOMObjectIsISupports
) {
202 return UnwrapDOMObject
<nsISupports
>(aObject
);
206 IsDOMObject(JSObject
* obj
)
208 return IsDOMClass(js::GetObjectClass(obj
));
211 #define UNWRAP_OBJECT(Interface, obj, value) \
212 mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface, \
213 mozilla::dom::Interface##Binding::NativeType>(obj, value)
215 // Some callers don't want to set an exception when unwrapping fails
216 // (for example, overload resolution uses unwrapping to tell what sort
217 // of thing it's looking at).
218 // U must be something that a T* can be assigned to (e.g. T* or an nsRefPtr<T>).
219 template <class T
, typename U
>
220 MOZ_ALWAYS_INLINE nsresult
221 UnwrapObject(JSObject
* obj
, U
& value
, prototypes::ID protoID
,
224 /* First check to see whether we have a DOM object */
225 const DOMJSClass
* domClass
= GetDOMClass(obj
);
227 /* Maybe we have a security wrapper or outer window? */
228 if (!js::IsWrapper(obj
)) {
229 /* Not a DOM object, not a wrapper, just bail */
230 return NS_ERROR_XPC_BAD_CONVERT_JS
;
233 obj
= js::CheckedUnwrap(obj
, /* stopAtOuter = */ false);
235 return NS_ERROR_XPC_SECURITY_MANAGER_VETO
;
237 MOZ_ASSERT(!js::IsWrapper(obj
));
238 domClass
= GetDOMClass(obj
);
240 /* We don't have a DOM object */
241 return NS_ERROR_XPC_BAD_CONVERT_JS
;
245 /* This object is a DOM object. Double-check that it is safely
246 castable to T by checking whether it claims to inherit from the
247 class identified by protoID. */
248 if (domClass
->mInterfaceChain
[protoDepth
] == protoID
) {
249 value
= UnwrapDOMObject
<T
>(obj
);
253 /* It's the wrong sort of DOM object */
254 return NS_ERROR_XPC_BAD_CONVERT_JS
;
257 template <prototypes::ID PrototypeID
, class T
, typename U
>
258 MOZ_ALWAYS_INLINE nsresult
259 UnwrapObject(JSObject
* obj
, U
& value
)
261 return UnwrapObject
<T
>(obj
, value
, PrototypeID
,
262 PrototypeTraits
<PrototypeID
>::Depth
);
266 IsNotDateOrRegExp(JSContext
* cx
, JS::Handle
<JSObject
*> obj
)
269 return !JS_ObjectIsDate(cx
, obj
) && !JS_ObjectIsRegExp(cx
, obj
);
272 MOZ_ALWAYS_INLINE
bool
273 IsObjectValueConvertibleToDictionary(JSContext
* cx
,
274 JS::Handle
<JS::Value
> objVal
)
276 JS::Rooted
<JSObject
*> obj(cx
, &objVal
.toObject());
277 return IsNotDateOrRegExp(cx
, obj
);
280 MOZ_ALWAYS_INLINE
bool
281 IsConvertibleToDictionary(JSContext
* cx
, JS::Handle
<JS::Value
> val
)
283 return val
.isNullOrUndefined() ||
284 (val
.isObject() && IsObjectValueConvertibleToDictionary(cx
, val
));
287 MOZ_ALWAYS_INLINE
bool
288 IsConvertibleToCallbackInterface(JSContext
* cx
, JS::Handle
<JSObject
*> obj
)
290 return IsNotDateOrRegExp(cx
, obj
);
293 // The items in the protoAndIfaceCache are indexed by the prototypes::id::ID and
294 // constructors::id::ID enums, in that order. The end of the prototype objects
295 // should be the start of the interface objects.
296 static_assert((size_t)constructors::id::_ID_Start
==
297 (size_t)prototypes::id::_ID_Count
,
298 "Overlapping or discontiguous indexes.");
299 const size_t kProtoAndIfaceCacheCount
= constructors::id::_ID_Count
;
301 class ProtoAndIfaceCache
303 // The caching strategy we use depends on what sort of global we're dealing
304 // with. For a window-like global, we want everything to be as fast as
305 // possible, so we use a flat array, indexed by prototype/constructor ID.
306 // For everything else (e.g. globals for JSMs), space is more important than
307 // speed, so we use a two-level lookup table.
309 class ArrayCache
: public Array
<JS::Heap
<JSObject
*>, kProtoAndIfaceCacheCount
>
312 JSObject
* EntrySlotIfExists(size_t i
) {
316 JS::Heap
<JSObject
*>& EntrySlotOrCreate(size_t i
) {
320 JS::Heap
<JSObject
*>& EntrySlotMustExist(size_t i
) {
321 MOZ_ASSERT((*this)[i
]);
325 void Trace(JSTracer
* aTracer
) {
326 for (size_t i
= 0; i
< ArrayLength(*this); ++i
) {
328 JS_CallObjectTracer(aTracer
, &(*this)[i
], "protoAndIfaceCache[i]");
333 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) {
334 return aMallocSizeOf(this);
342 memset(&mPages
, 0, sizeof(mPages
));
346 for (size_t i
= 0; i
< ArrayLength(mPages
); ++i
) {
351 JSObject
* EntrySlotIfExists(size_t i
) {
352 MOZ_ASSERT(i
< kProtoAndIfaceCacheCount
);
353 size_t pageIndex
= i
/ kPageSize
;
354 size_t leafIndex
= i
% kPageSize
;
355 Page
* p
= mPages
[pageIndex
];
359 return (*p
)[leafIndex
];
362 JS::Heap
<JSObject
*>& EntrySlotOrCreate(size_t i
) {
363 MOZ_ASSERT(i
< kProtoAndIfaceCacheCount
);
364 size_t pageIndex
= i
/ kPageSize
;
365 size_t leafIndex
= i
% kPageSize
;
366 Page
* p
= mPages
[pageIndex
];
369 mPages
[pageIndex
] = p
;
371 return (*p
)[leafIndex
];
374 JS::Heap
<JSObject
*>& EntrySlotMustExist(size_t i
) {
375 MOZ_ASSERT(i
< kProtoAndIfaceCacheCount
);
376 size_t pageIndex
= i
/ kPageSize
;
377 size_t leafIndex
= i
% kPageSize
;
378 Page
* p
= mPages
[pageIndex
];
380 return (*p
)[leafIndex
];
383 void Trace(JSTracer
* trc
) {
384 for (size_t i
= 0; i
< ArrayLength(mPages
); ++i
) {
387 for (size_t j
= 0; j
< ArrayLength(*p
); ++j
) {
389 JS_CallObjectTracer(trc
, &(*p
)[j
], "protoAndIfaceCache[i]");
396 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) {
397 size_t n
= aMallocSizeOf(this);
398 for (size_t i
= 0; i
< ArrayLength(mPages
); ++i
) {
399 n
+= aMallocSizeOf(mPages
[i
]);
405 static const size_t kPageSize
= 16;
406 typedef Array
<JS::Heap
<JSObject
*>, kPageSize
> Page
;
407 static const size_t kNPages
= kProtoAndIfaceCacheCount
/ kPageSize
+
408 size_t(bool(kProtoAndIfaceCacheCount
% kPageSize
));
409 Array
<Page
*, kNPages
> mPages
;
418 explicit ProtoAndIfaceCache(Kind aKind
) : mKind(aKind
) {
419 MOZ_COUNT_CTOR(ProtoAndIfaceCache
);
420 if (aKind
== WindowLike
) {
421 mArrayCache
= new ArrayCache();
423 mPageTableCache
= new PageTableCache();
427 ~ProtoAndIfaceCache() {
428 if (mKind
== WindowLike
) {
431 delete mPageTableCache
;
433 MOZ_COUNT_DTOR(ProtoAndIfaceCache
);
436 #define FORWARD_OPERATION(opName, args) \
438 if (mKind == WindowLike) { \
439 return mArrayCache->opName args; \
441 return mPageTableCache->opName args; \
445 JSObject
* EntrySlotIfExists(size_t i
) {
446 FORWARD_OPERATION(EntrySlotIfExists
, (i
));
449 JS::Heap
<JSObject
*>& EntrySlotOrCreate(size_t i
) {
450 FORWARD_OPERATION(EntrySlotOrCreate
, (i
));
453 JS::Heap
<JSObject
*>& EntrySlotMustExist(size_t i
) {
454 FORWARD_OPERATION(EntrySlotMustExist
, (i
));
457 void Trace(JSTracer
*aTracer
) {
458 FORWARD_OPERATION(Trace
, (aTracer
));
461 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) {
462 size_t n
= aMallocSizeOf(this);
463 n
+= (mKind
== WindowLike
464 ? mArrayCache
->SizeOfIncludingThis(aMallocSizeOf
)
465 : mPageTableCache
->SizeOfIncludingThis(aMallocSizeOf
));
468 #undef FORWARD_OPERATION
472 ArrayCache
*mArrayCache
;
473 PageTableCache
*mPageTableCache
;
479 AllocateProtoAndIfaceCache(JSObject
* obj
, ProtoAndIfaceCache::Kind aKind
)
481 MOZ_ASSERT(js::GetObjectClass(obj
)->flags
& JSCLASS_DOM_GLOBAL
);
482 MOZ_ASSERT(js::GetReservedSlot(obj
, DOM_PROTOTYPE_SLOT
).isUndefined());
484 ProtoAndIfaceCache
* protoAndIfaceCache
= new ProtoAndIfaceCache(aKind
);
486 js::SetReservedSlot(obj
, DOM_PROTOTYPE_SLOT
,
487 JS::PrivateValue(protoAndIfaceCache
));
492 VerifyTraceProtoAndIfaceCacheCalled(JSTracer
*trc
, void **thingp
,
495 struct VerifyTraceProtoAndIfaceCacheCalledTracer
: public JSTracer
499 explicit VerifyTraceProtoAndIfaceCacheCalledTracer(JSRuntime
*rt
)
500 : JSTracer(rt
, VerifyTraceProtoAndIfaceCacheCalled
), ok(false)
506 TraceProtoAndIfaceCache(JSTracer
* trc
, JSObject
* obj
)
508 MOZ_ASSERT(js::GetObjectClass(obj
)->flags
& JSCLASS_DOM_GLOBAL
);
511 if (trc
->callback
== VerifyTraceProtoAndIfaceCacheCalled
) {
512 // We don't do anything here, we only want to verify that
513 // TraceProtoAndIfaceCache was called.
514 static_cast<VerifyTraceProtoAndIfaceCacheCalledTracer
*>(trc
)->ok
= true;
519 if (!HasProtoAndIfaceCache(obj
))
521 ProtoAndIfaceCache
* protoAndIfaceCache
= GetProtoAndIfaceCache(obj
);
522 protoAndIfaceCache
->Trace(trc
);
526 DestroyProtoAndIfaceCache(JSObject
* obj
)
528 MOZ_ASSERT(js::GetObjectClass(obj
)->flags
& JSCLASS_DOM_GLOBAL
);
530 ProtoAndIfaceCache
* protoAndIfaceCache
= GetProtoAndIfaceCache(obj
);
532 delete protoAndIfaceCache
;
536 * Add constants to an object.
539 DefineConstants(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
540 const ConstantSpec
* cs
);
542 struct JSNativeHolder
545 const NativePropertyHooks
* mPropertyHooks
;
548 struct NamedConstructor
551 const JSNativeHolder mHolder
;
556 * Create a DOM interface object (if constructorClass is non-null) and/or a
557 * DOM interface prototype object (if protoClass is non-null).
559 * global is used as the parent of the interface object and the interface
561 * protoProto is the prototype to use for the interface prototype object.
562 * interfaceProto is the prototype to use for the interface object.
563 * protoClass is the JSClass to use for the interface prototype object.
564 * This is null if we should not create an interface prototype
566 * protoCache a pointer to a JSObject pointer where we should cache the
567 * interface prototype object. This must be null if protoClass is and
569 * constructorClass is the JSClass to use for the interface object.
570 * This is null if we should not create an interface object or
571 * if it should be a function object.
572 * constructor holds the JSNative to back the interface object which should be a
573 * Function, unless constructorClass is non-null in which case it is
574 * ignored. If this is null and constructorClass is also null then
575 * we should not create an interface object at all.
576 * ctorNargs is the length of the constructor function; 0 if no constructor
577 * constructorCache a pointer to a JSObject pointer where we should cache the
578 * interface object. This must be null if both constructorClass
579 * and constructor are null, and non-null otherwise.
580 * properties contains the methods, attributes and constants to be defined on
581 * objects in any compartment.
582 * chromeProperties contains the methods, attributes and constants to be defined
583 * on objects in chrome compartments. This must be null if the
584 * interface doesn't have any ChromeOnly properties or if the
585 * object is being created in non-chrome compartment.
586 * defineOnGlobal controls whether properties should be defined on the given
587 * global for the interface object (if any) and named
588 * constructors (if any) for this interface. This can be
589 * false in situations where we want the properties to only
590 * appear on privileged Xrays but not on the unprivileged
593 * At least one of protoClass, constructorClass or constructor should be
594 * non-null. If constructorClass or constructor are non-null, the resulting
595 * interface object will be defined on the given global with property name
596 * |name|, which must also be non-null.
599 CreateInterfaceObjects(JSContext
* cx
, JS::Handle
<JSObject
*> global
,
600 JS::Handle
<JSObject
*> protoProto
,
601 const JSClass
* protoClass
, JS::Heap
<JSObject
*>* protoCache
,
602 JS::Handle
<JSObject
*> interfaceProto
,
603 const JSClass
* constructorClass
, const JSNativeHolder
* constructor
,
604 unsigned ctorNargs
, const NamedConstructor
* namedConstructors
,
605 JS::Heap
<JSObject
*>* constructorCache
,
606 const NativeProperties
* regularProperties
,
607 const NativeProperties
* chromeOnlyProperties
,
608 const char* name
, bool defineOnGlobal
);
611 * Define the properties (regular and chrome-only) on obj.
613 * obj the object to instal the properties on. This should be the interface
614 * prototype object for regular interfaces and the instance object for
615 * interfaces marked with Global.
616 * properties contains the methods, attributes and constants to be defined on
617 * objects in any compartment.
618 * chromeProperties contains the methods, attributes and constants to be defined
619 * on objects in chrome compartments. This must be null if the
620 * interface doesn't have any ChromeOnly properties or if the
621 * object is being created in non-chrome compartment.
624 DefineProperties(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
625 const NativeProperties
* properties
,
626 const NativeProperties
* chromeOnlyProperties
);
629 * Define the unforgeable methods on an object.
632 DefineUnforgeableMethods(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
633 const Prefable
<const JSFunctionSpec
>* props
);
636 * Define the unforgeable attributes on an object.
639 DefineUnforgeableAttributes(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
640 const Prefable
<const JSPropertySpec
>* props
);
643 DefineWebIDLBindingUnforgeablePropertiesOnXPCObject(JSContext
* cx
,
644 JS::Handle
<JSObject
*> obj
,
645 const NativeProperties
* properties
);
648 DefineWebIDLBindingPropertiesOnXPCObject(JSContext
* cx
,
649 JS::Handle
<JSObject
*> obj
,
650 const NativeProperties
* properties
);
653 #define HAS_MEMBER_CHECK(_name) \
654 template<typename V> static yes& Check(char (*)[(&V::_name == 0) + 1])
656 #define HAS_MEMBER_CHECK(_name) \
657 template<typename V> static yes& Check(char (*)[sizeof(&V::_name) + 1])
660 #define HAS_MEMBER(_name) \
661 template<typename T> \
662 class Has##_name##Member { \
663 typedef char yes[1]; \
664 typedef char no[2]; \
665 HAS_MEMBER_CHECK(_name); \
666 template<typename V> static no& Check(...); \
669 static bool const Value = sizeof(Check<T>(nullptr)) == sizeof(yes); \
672 HAS_MEMBER(WrapObject
)
674 // HasWrapObject<T>::Value will be true if T has a WrapObject member but it's
675 // not nsWrapperCache::WrapObject.
682 typedef JSObject
* (nsWrapperCache::*WrapObject
)(JSContext
*,
683 JS::Handle
<JSObject
*>);
684 template<typename U
, U
> struct SFINAE
;
685 template <typename V
> static no
& Check(SFINAE
<WrapObject
, &V::WrapObject
>*);
686 template <typename V
> static yes
& Check(...);
689 static bool const Value
= HasWrapObjectMember
<T
>::Value
&&
690 sizeof(Check
<T
>(nullptr)) == sizeof(yes
);
694 template <class T
, bool isISupports
=IsBaseOf
<nsISupports
, T
>::value
>
696 CheckWrapperCacheCast
700 return reinterpret_cast<uintptr_t>(
701 static_cast<nsWrapperCache
*>(
702 reinterpret_cast<T
*>(1))) == 1;
707 CheckWrapperCacheCast
<T
, true>
716 MOZ_ALWAYS_INLINE
bool
717 CouldBeDOMBinding(void*)
722 MOZ_ALWAYS_INLINE
bool
723 CouldBeDOMBinding(nsWrapperCache
* aCache
)
725 return aCache
->IsDOMBinding();
729 TryToOuterize(JSContext
* cx
, JS::MutableHandle
<JS::Value
> rval
)
731 if (js::IsInnerObject(&rval
.toObject())) {
732 JS::Rooted
<JSObject
*> obj(cx
, &rval
.toObject());
733 obj
= JS_ObjectToOuterObject(cx
, obj
);
738 rval
.set(JS::ObjectValue(*obj
));
744 // Make sure to wrap the given string value into the right compartment, as
748 MaybeWrapStringValue(JSContext
* cx
, JS::MutableHandle
<JS::Value
> rval
)
750 MOZ_ASSERT(rval
.isString());
751 JSString
* str
= rval
.toString();
752 if (JS::GetTenuredGCThingZone(str
) != js::GetContextZone(cx
)) {
753 return JS_WrapValue(cx
, rval
);
758 // Make sure to wrap the given object value into the right compartment as
759 // needed. This will work correctly, but possibly slowly, on all objects.
762 MaybeWrapObjectValue(JSContext
* cx
, JS::MutableHandle
<JS::Value
> rval
)
764 MOZ_ASSERT(rval
.isObject());
766 // Cross-compartment always requires wrapping.
767 JSObject
* obj
= &rval
.toObject();
768 if (js::GetObjectCompartment(obj
) != js::GetContextCompartment(cx
)) {
769 return JS_WrapValue(cx
, rval
);
772 // We're same-compartment, but even then we might need to wrap
773 // objects specially. Check for that.
774 if (IsDOMObject(obj
)) {
775 return TryToOuterize(cx
, rval
);
778 // It's not a WebIDL object. But it might be an XPConnect one, in which case
779 // we may need to outerize here, so make sure to call JS_WrapValue.
780 return JS_WrapValue(cx
, rval
);
783 // Like MaybeWrapObjectValue, but also allows null
786 MaybeWrapObjectOrNullValue(JSContext
* cx
, JS::MutableHandle
<JS::Value
> rval
)
788 MOZ_ASSERT(rval
.isObjectOrNull());
792 return MaybeWrapObjectValue(cx
, rval
);
795 // Wrapping for objects that are known to not be DOM or XPConnect objects
798 MaybeWrapNonDOMObjectValue(JSContext
* cx
, JS::MutableHandle
<JS::Value
> rval
)
800 MOZ_ASSERT(rval
.isObject());
801 MOZ_ASSERT(!GetDOMClass(&rval
.toObject()));
802 MOZ_ASSERT(!(js::GetObjectClass(&rval
.toObject())->flags
&
803 JSCLASS_PRIVATE_IS_NSISUPPORTS
));
805 JSObject
* obj
= &rval
.toObject();
806 if (js::GetObjectCompartment(obj
) == js::GetContextCompartment(cx
)) {
809 return JS_WrapValue(cx
, rval
);
812 // Like MaybeWrapNonDOMObjectValue but allows null
815 MaybeWrapNonDOMObjectOrNullValue(JSContext
* cx
, JS::MutableHandle
<JS::Value
> rval
)
817 MOZ_ASSERT(rval
.isObjectOrNull());
821 return MaybeWrapNonDOMObjectValue(cx
, rval
);
824 // If rval is a gcthing and is not in the compartment of cx, wrap rval
825 // into the compartment of cx (typically by replacing it with an Xray or
826 // cross-compartment wrapper around the original object).
827 MOZ_ALWAYS_INLINE
bool
828 MaybeWrapValue(JSContext
* cx
, JS::MutableHandle
<JS::Value
> rval
)
830 if (rval
.isString()) {
831 return MaybeWrapStringValue(cx
, rval
);
834 if (!rval
.isObject()) {
838 return MaybeWrapObjectValue(cx
, rval
);
841 // Create a JSObject wrapping "value", if there isn't one already, and store it
842 // in rval. "value" must be a concrete class that implements a
843 // GetWrapperPreserveColor() which can return its existing wrapper, if any, and
844 // a WrapObject() which will try to create a wrapper. Typically, this is done by
845 // having "value" inherit from nsWrapperCache.
847 MOZ_ALWAYS_INLINE
bool
848 WrapNewBindingObject(JSContext
* cx
, T
* value
, JS::MutableHandle
<JS::Value
> rval
)
851 JSObject
* obj
= value
->GetWrapperPreserveColor();
852 // We can get rid of this when we remove support for hasXPConnectImpls.
853 bool couldBeDOMBinding
= CouldBeDOMBinding(value
);
855 JS::ExposeObjectToActiveJS(obj
);
857 // Inline this here while we have non-dom objects in wrapper caches.
858 if (!couldBeDOMBinding
) {
862 obj
= value
->WrapObject(cx
);
864 // At this point, obj is null, so just return false.
865 // Callers seem to be testing JS_IsExceptionPending(cx) to
866 // figure out whether WrapObject() threw.
872 const DOMJSClass
* clasp
= GetDOMClass(obj
);
873 // clasp can be null if the cache contained a non-DOM object.
875 // Some sanity asserts about our object. Specifically:
876 // 1) If our class claims we're nsISupports, we better be nsISupports
877 // XXXbz ideally, we could assert that reinterpret_cast to nsISupports
878 // does the right thing, but I don't see a way to do it. :(
879 // 2) If our class doesn't claim we're nsISupports we better be
880 // reinterpret_castable to nsWrapperCache.
881 MOZ_ASSERT(clasp
, "What happened here?");
882 MOZ_ASSERT_IF(clasp
->mDOMObjectIsISupports
, (IsBaseOf
<nsISupports
, T
>::value
));
883 MOZ_ASSERT(CheckWrapperCacheCast
<T
>::Check());
887 rval
.set(JS::ObjectValue(*obj
));
889 bool sameCompartment
=
890 js::GetObjectCompartment(obj
) == js::GetContextCompartment(cx
);
891 if (sameCompartment
&& couldBeDOMBinding
) {
892 // We only need to outerize Window objects, so anything inheriting from
893 // nsGlobalWindow (which inherits from EventTarget itself).
894 return IsBaseOf
<nsGlobalWindow
, T
>::value
|| IsSame
<EventTarget
, T
>::value
?
895 TryToOuterize(cx
, rval
) : true;
898 return JS_WrapValue(cx
, rval
);
901 // Create a JSObject wrapping "value", for cases when "value" is a
902 // non-wrapper-cached object using WebIDL bindings. "value" must implement a
903 // WrapObject() method taking a JSContext and a scope.
906 WrapNewBindingNonWrapperCachedObject(JSContext
* cx
,
907 JS::Handle
<JSObject
*> scopeArg
,
909 JS::MutableHandle
<JS::Value
> rval
)
912 // We try to wrap in the compartment of the underlying object of "scope"
913 JS::Rooted
<JSObject
*> obj(cx
);
915 // scope for the JSAutoCompartment so that we restore the compartment
916 // before we call JS_WrapValue.
917 Maybe
<JSAutoCompartment
> ac
;
918 // Maybe<Handle> doesn't so much work, and in any case, adding
919 // more Maybe (one for a Rooted and one for a Handle) adds more
920 // code (and branches!) than just adding a single rooted.
921 JS::Rooted
<JSObject
*> scope(cx
, scopeArg
);
922 if (js::IsWrapper(scope
)) {
923 scope
= js::CheckedUnwrap(scope
, /* stopAtOuter = */ false);
926 ac
.emplace(cx
, scope
);
929 MOZ_ASSERT(js::IsObjectInContextCompartment(scope
, cx
));
930 obj
= value
->WrapObject(cx
);
937 // We can end up here in all sorts of compartments, per above. Make
938 // sure to JS_WrapValue!
939 rval
.set(JS::ObjectValue(*obj
));
940 return JS_WrapValue(cx
, rval
);
943 // Create a JSObject wrapping "value", for cases when "value" is a
944 // non-wrapper-cached owned object using WebIDL bindings. "value" must implement a
945 // WrapObject() method taking a JSContext, a scope, and a boolean outparam that
946 // is true if the JSObject took ownership
949 WrapNewBindingNonWrapperCachedOwnedObject(JSContext
* cx
,
950 JS::Handle
<JSObject
*> scopeArg
,
952 JS::MutableHandle
<JS::Value
> rval
)
954 // We do a runtime check on value, because otherwise we might in
955 // fact end up wrapping a null and invoking methods on it later.
957 NS_RUNTIMEABORT("Don't try to wrap null objects");
959 // We try to wrap in the compartment of the underlying object of "scope"
960 JS::Rooted
<JSObject
*> obj(cx
);
962 // scope for the JSAutoCompartment so that we restore the compartment
963 // before we call JS_WrapValue.
964 Maybe
<JSAutoCompartment
> ac
;
965 // Maybe<Handle> doesn't so much work, and in any case, adding
966 // more Maybe (one for a Rooted and one for a Handle) adds more
967 // code (and branches!) than just adding a single rooted.
968 JS::Rooted
<JSObject
*> scope(cx
, scopeArg
);
969 if (js::IsWrapper(scope
)) {
970 scope
= js::CheckedUnwrap(scope
, /* stopAtOuter = */ false);
973 ac
.emplace(cx
, scope
);
976 bool tookOwnership
= false;
977 MOZ_ASSERT(js::IsObjectInContextCompartment(scope
, cx
));
978 obj
= value
->WrapObject(cx
, &tookOwnership
);
979 MOZ_ASSERT_IF(obj
, tookOwnership
);
989 // We can end up here in all sorts of compartments, per above. Make
990 // sure to JS_WrapValue!
991 rval
.set(JS::ObjectValue(*obj
));
992 return JS_WrapValue(cx
, rval
);
995 // Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr).
996 template <template <typename
> class SmartPtr
, typename T
>
998 WrapNewBindingNonWrapperCachedObject(JSContext
* cx
, JS::Handle
<JSObject
*> scope
,
999 const SmartPtr
<T
>& value
,
1000 JS::MutableHandle
<JS::Value
> rval
)
1002 return WrapNewBindingNonWrapperCachedObject(cx
, scope
, value
.get(), rval
);
1005 // Only set allowNativeWrapper to false if you really know you need it, if in
1006 // doubt use true. Setting it to false disables security wrappers.
1008 NativeInterface2JSObjectAndThrowIfFailed(JSContext
* aCx
,
1009 JS::Handle
<JSObject
*> aScope
,
1010 JS::MutableHandle
<JS::Value
> aRetval
,
1011 xpcObjectHelper
& aHelper
,
1013 bool aAllowNativeWrapper
);
1016 * A method to handle new-binding wrap failure, by possibly falling back to
1017 * wrapping as a non-new-binding object.
1020 MOZ_ALWAYS_INLINE
bool
1021 HandleNewBindingWrappingFailure(JSContext
* cx
, JS::Handle
<JSObject
*> scope
,
1022 T
* value
, JS::MutableHandle
<JS::Value
> rval
)
1024 if (JS_IsExceptionPending(cx
)) {
1028 qsObjectHelper
helper(value
, GetWrapperCache(value
));
1029 return NativeInterface2JSObjectAndThrowIfFailed(cx
, scope
, rval
,
1030 helper
, nullptr, true);
1033 // Helper for calling HandleNewBindingWrappingFailure with smart pointers
1034 // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
1037 template <class T
, bool isSmartPtr
=HasgetMember
<T
>::Value
>
1038 struct HandleNewBindingWrappingFailureHelper
1040 static inline bool Wrap(JSContext
* cx
, JS::Handle
<JSObject
*> scope
,
1041 const T
& value
, JS::MutableHandle
<JS::Value
> rval
)
1043 return HandleNewBindingWrappingFailure(cx
, scope
, value
.get(), rval
);
1048 struct HandleNewBindingWrappingFailureHelper
<T
, false>
1050 static inline bool Wrap(JSContext
* cx
, JS::Handle
<JSObject
*> scope
, T
& value
,
1051 JS::MutableHandle
<JS::Value
> rval
)
1053 return HandleNewBindingWrappingFailure(cx
, scope
, &value
, rval
);
1059 HandleNewBindingWrappingFailure(JSContext
* cx
, JS::Handle
<JSObject
*> scope
,
1060 T
& value
, JS::MutableHandle
<JS::Value
> rval
)
1062 return HandleNewBindingWrappingFailureHelper
<T
>::Wrap(cx
, scope
, value
, rval
);
1065 template<bool Fatal
>
1067 EnumValueNotFound(JSContext
* cx
, JSString
* str
, const char* type
,
1068 const char* sourceDescription
)
1075 EnumValueNotFound
<false>(JSContext
* cx
, JSString
* str
, const char* type
,
1076 const char* sourceDescription
)
1078 // TODO: Log a warning to the console.
1084 EnumValueNotFound
<true>(JSContext
* cx
, JSString
* str
, const char* type
,
1085 const char* sourceDescription
)
1087 JSAutoByteString
deflated(cx
, str
);
1091 return ThrowErrorMessage(cx
, MSG_INVALID_ENUM_VALUE
, sourceDescription
,
1092 deflated
.ptr(), type
);
1095 template<typename CharT
>
1097 FindEnumStringIndexImpl(const CharT
* chars
, size_t length
, const EnumEntry
* values
)
1100 for (const EnumEntry
* value
= values
; value
->value
; ++value
, ++i
) {
1101 if (length
!= value
->length
) {
1106 const char* val
= value
->value
;
1107 for (size_t j
= 0; j
!= length
; ++j
) {
1108 if (unsigned(val
[j
]) != unsigned(chars
[j
])) {
1122 template<bool InvalidValueFatal
>
1124 FindEnumStringIndex(JSContext
* cx
, JS::Handle
<JS::Value
> v
, const EnumEntry
* values
,
1125 const char* type
, const char* sourceDescription
, bool* ok
)
1127 // JS_StringEqualsAscii is slow as molasses, so don't use it here.
1128 JSString
* str
= JS::ToString(cx
, v
);
1133 JS::Anchor
<JSString
*> anchor(str
);
1138 JS::AutoCheckCannotGC nogc
;
1139 if (js::StringHasLatin1Chars(str
)) {
1140 const JS::Latin1Char
* chars
= JS_GetLatin1StringCharsAndLength(cx
, nogc
, str
,
1146 index
= FindEnumStringIndexImpl(chars
, length
, values
);
1148 const jschar
* chars
= JS_GetTwoByteStringCharsAndLength(cx
, nogc
, str
,
1154 index
= FindEnumStringIndexImpl(chars
, length
, values
);
1162 *ok
= EnumValueNotFound
<InvalidValueFatal
>(cx
, str
, type
, sourceDescription
);
1166 inline nsWrapperCache
*
1167 GetWrapperCache(const ParentObject
& aParentObject
)
1169 return aParentObject
.mWrapperCache
;
1174 GetParentPointer(T
* aObject
)
1180 GetParentPointer(const ParentObject
& aObject
)
1182 return aObject
.mObject
;
1185 template <typename T
>
1187 GetUseXBLScope(T
* aParentObject
)
1193 GetUseXBLScope(const ParentObject
& aParentObject
)
1195 return aParentObject
.mUseXBLScope
;
1200 ClearWrapper(T
* p
, nsWrapperCache
* cache
)
1202 cache
->ClearWrapper();
1207 ClearWrapper(T
* p
, void*)
1209 nsWrapperCache
* cache
;
1210 CallQueryInterface(p
, &cache
);
1211 ClearWrapper(p
, cache
);
1214 // Attempt to preserve the wrapper, if any, for a Paris DOM bindings object.
1215 // Return true if we successfully preserved the wrapper, or there is no wrapper
1216 // to preserve. In the latter case we don't need to preserve the wrapper, because
1217 // the object can only be obtained by JS once, or they cannot be meaningfully
1218 // owned from the native side.
1220 // This operation will return false only for non-nsISupports cycle-collected
1221 // objects, because we cannot determine if they are wrappercached or not.
1223 TryPreserveWrapper(JSObject
* obj
);
1225 // Can only be called with a DOM JSClass.
1227 InstanceClassHasProtoAtDepth(const js::Class
* clasp
,
1228 uint32_t protoID
, uint32_t depth
);
1230 // Only set allowNativeWrapper to false if you really know you need it, if in
1231 // doubt use true. Setting it to false disables security wrappers.
1233 XPCOMObjectToJsval(JSContext
* cx
, JS::Handle
<JSObject
*> scope
,
1234 xpcObjectHelper
& helper
, const nsIID
* iid
,
1235 bool allowNativeWrapper
, JS::MutableHandle
<JS::Value
> rval
);
1237 // Special-cased wrapping for variants
1239 VariantToJsval(JSContext
* aCx
, nsIVariant
* aVariant
,
1240 JS::MutableHandle
<JS::Value
> aRetval
);
1242 // Wrap an object "p" which is not using WebIDL bindings yet. This _will_
1243 // actually work on WebIDL binding objects that are wrappercached, but will be
1244 // much slower than WrapNewBindingObject. "cache" must either be null or be the
1245 // nsWrapperCache for "p".
1248 WrapObject(JSContext
* cx
, T
* p
, nsWrapperCache
* cache
, const nsIID
* iid
,
1249 JS::MutableHandle
<JS::Value
> rval
)
1251 if (xpc_FastGetCachedWrapper(cx
, cache
, rval
))
1253 qsObjectHelper
helper(p
, cache
);
1254 JS::Rooted
<JSObject
*> scope(cx
, JS::CurrentGlobalOrNull(cx
));
1255 return XPCOMObjectToJsval(cx
, scope
, helper
, iid
, true, rval
);
1258 // A specialization of the above for nsIVariant, because that needs to
1259 // do something different.
1262 WrapObject
<nsIVariant
>(JSContext
* cx
, nsIVariant
* p
,
1263 nsWrapperCache
* cache
, const nsIID
* iid
,
1264 JS::MutableHandle
<JS::Value
> rval
)
1267 MOZ_ASSERT(iid
->Equals(NS_GET_IID(nsIVariant
)));
1268 return VariantToJsval(cx
, p
, rval
);
1271 // Wrap an object "p" which is not using WebIDL bindings yet. Just like the
1272 // variant that takes an nsWrapperCache above, but will try to auto-derive the
1273 // nsWrapperCache* from "p".
1276 WrapObject(JSContext
* cx
, T
* p
, const nsIID
* iid
,
1277 JS::MutableHandle
<JS::Value
> rval
)
1279 return WrapObject(cx
, p
, GetWrapperCache(p
), iid
, rval
);
1282 // Just like the WrapObject above, but without requiring you to pick which
1283 // interface you're wrapping as. This should only be used for objects that have
1284 // classinfo, for which it doesn't matter what IID is used to wrap.
1287 WrapObject(JSContext
* cx
, T
* p
, JS::MutableHandle
<JS::Value
> rval
)
1289 return WrapObject(cx
, p
, nullptr, rval
);
1292 // Helper to make it possible to wrap directly out of an nsCOMPtr
1295 WrapObject(JSContext
* cx
, const nsCOMPtr
<T
>& p
,
1296 const nsIID
* iid
, JS::MutableHandle
<JS::Value
> rval
)
1298 return WrapObject(cx
, p
.get(), iid
, rval
);
1301 // Helper to make it possible to wrap directly out of an nsCOMPtr
1304 WrapObject(JSContext
* cx
, const nsCOMPtr
<T
>& p
,
1305 JS::MutableHandle
<JS::Value
> rval
)
1307 return WrapObject(cx
, p
, nullptr, rval
);
1310 // Helper to make it possible to wrap directly out of an nsRefPtr
1313 WrapObject(JSContext
* cx
, const nsRefPtr
<T
>& p
,
1314 const nsIID
* iid
, JS::MutableHandle
<JS::Value
> rval
)
1316 return WrapObject(cx
, p
.get(), iid
, rval
);
1319 // Helper to make it possible to wrap directly out of an nsRefPtr
1322 WrapObject(JSContext
* cx
, const nsRefPtr
<T
>& p
,
1323 JS::MutableHandle
<JS::Value
> rval
)
1325 return WrapObject(cx
, p
, nullptr, rval
);
1328 // Specialization to make it easy to use WrapObject in codegen.
1331 WrapObject
<JSObject
>(JSContext
* cx
, JSObject
* p
,
1332 JS::MutableHandle
<JS::Value
> rval
)
1334 rval
.set(JS::ObjectOrNullValue(p
));
1339 WrapObject(JSContext
* cx
, JSObject
& p
, JS::MutableHandle
<JS::Value
> rval
)
1341 rval
.set(JS::ObjectValue(p
));
1345 // Given an object "p" that inherits from nsISupports, wrap it and return the
1346 // result. Null is returned on wrapping failure. This is somewhat similar to
1347 // WrapObject() above, but does NOT allow Xrays around the result, since we
1348 // don't want those for our parent object.
1349 template<typename T
>
1350 static inline JSObject
*
1351 WrapNativeISupportsParent(JSContext
* cx
, T
* p
, nsWrapperCache
* cache
)
1353 qsObjectHelper
helper(ToSupports(p
), cache
);
1354 JS::Rooted
<JSObject
*> scope(cx
, JS::CurrentGlobalOrNull(cx
));
1355 JS::Rooted
<JS::Value
> v(cx
);
1356 return XPCOMObjectToJsval(cx
, scope
, helper
, nullptr, false, &v
) ?
1357 v
.toObjectOrNull() :
1362 // Fallback for when our parent is not a WebIDL binding object.
1363 template<typename T
, bool isISupports
=IsBaseOf
<nsISupports
, T
>::value
>
1364 struct WrapNativeParentFallback
1366 static inline JSObject
* Wrap(JSContext
* cx
, T
* parent
, nsWrapperCache
* cache
)
1372 // Fallback for when our parent is not a WebIDL binding object but _is_ an
1373 // nsISupports object.
1374 template<typename T
>
1375 struct WrapNativeParentFallback
<T
, true >
1377 static inline JSObject
* Wrap(JSContext
* cx
, T
* parent
, nsWrapperCache
* cache
)
1379 return WrapNativeISupportsParent(cx
, parent
, cache
);
1383 // Wrapping of our native parent, for cases when it's a WebIDL object (though
1384 // possibly preffed off).
1385 template<typename T
, bool hasWrapObject
=HasWrapObject
<T
>::Value
>
1386 struct WrapNativeParentHelper
1388 static inline JSObject
* Wrap(JSContext
* cx
, T
* parent
, nsWrapperCache
* cache
)
1393 if ((obj
= cache
->GetWrapper())) {
1397 // Inline this here while we have non-dom objects in wrapper caches.
1398 if (!CouldBeDOMBinding(parent
)) {
1399 obj
= WrapNativeParentFallback
<T
>::Wrap(cx
, parent
, cache
);
1401 obj
= parent
->WrapObject(cx
);
1408 // Wrapping of our native parent, for cases when it's not a WebIDL object. In
1409 // this case it must be nsISupports.
1410 template<typename T
>
1411 struct WrapNativeParentHelper
<T
, false >
1413 static inline JSObject
* Wrap(JSContext
* cx
, T
* parent
, nsWrapperCache
* cache
)
1416 if (cache
&& (obj
= cache
->GetWrapper())) {
1418 NS_ASSERTION(WrapNativeISupportsParent(cx
, parent
, cache
) == obj
,
1419 "Unexpected object in nsWrapperCache");
1424 return WrapNativeISupportsParent(cx
, parent
, cache
);
1428 // Wrapping of our native parent.
1429 template<typename T
>
1430 static inline JSObject
*
1431 WrapNativeParent(JSContext
* cx
, T
* p
, nsWrapperCache
* cache
,
1432 bool useXBLScope
= false)
1435 return JS::CurrentGlobalOrNull(cx
);
1438 JSObject
* parent
= WrapNativeParentHelper
<T
>::Wrap(cx
, p
, cache
);
1443 // If useXBLScope is true, it means that the canonical reflector for this
1444 // native object should live in the content XBL scope. Note that we never put
1445 // anonymous content inside an add-on scope.
1446 if (xpc::IsInContentXBLScope(parent
)) {
1449 JS::Rooted
<JSObject
*> rootedParent(cx
, parent
);
1450 JS::Rooted
<JSObject
*> xblScope(cx
, xpc::GetXBLScope(cx
, rootedParent
));
1451 NS_ENSURE_TRUE(xblScope
, nullptr);
1452 JSAutoCompartment
ac(cx
, xblScope
);
1453 if (NS_WARN_IF(!JS_WrapObject(cx
, &rootedParent
))) {
1457 return rootedParent
;
1460 // Wrapping of our native parent, when we don't want to explicitly pass in
1461 // things like the nsWrapperCache for it.
1462 template<typename T
>
1463 static inline JSObject
*
1464 WrapNativeParent(JSContext
* cx
, const T
& p
)
1466 return WrapNativeParent(cx
, GetParentPointer(p
), GetWrapperCache(p
), GetUseXBLScope(p
));
1469 // A way to differentiate between nodes, which use the parent object
1470 // returned by native->GetParentObject(), and all other objects, which
1471 // just use the parent's global.
1472 static inline JSObject
*
1473 GetRealParentObject(void* aParent
, JSObject
* aParentObject
)
1475 return aParentObject
?
1476 js::GetGlobalForObjectCrossCompartment(aParentObject
) : nullptr;
1479 static inline JSObject
*
1480 GetRealParentObject(Element
* aParent
, JSObject
* aParentObject
)
1482 return aParentObject
;
1485 HAS_MEMBER(GetParentObject
)
1487 template<typename T
, bool WrapperCached
=HasGetParentObjectMember
<T
>::Value
>
1488 struct GetParentObject
1490 static JSObject
* Get(JSContext
* cx
, JS::Handle
<JSObject
*> obj
)
1492 MOZ_ASSERT(js::IsObjectInContextCompartment(obj
, cx
));
1493 T
* native
= UnwrapDOMObject
<T
>(obj
);
1495 GetRealParentObject(native
,
1496 WrapNativeParent(cx
, native
->GetParentObject()));
1500 template<typename T
>
1501 struct GetParentObject
<T
, false>
1503 static JSObject
* Get(JSContext
* cx
, JS::Handle
<JSObject
*> obj
)
1511 JSObject
* GetJSObjectFromCallback(CallbackObject
* callback
)
1513 return callback
->Callback();
1517 JSObject
* GetJSObjectFromCallback(void* noncallback
)
1522 template<typename T
>
1523 static inline JSObject
*
1524 WrapCallThisObject(JSContext
* cx
, const T
& p
)
1526 // Callbacks are nsISupports, so WrapNativeParent will just happily wrap them
1527 // up as an nsISupports XPCWrappedNative... which is not at all what we want.
1528 // So we need to special-case them.
1529 JS::Rooted
<JSObject
*> obj(cx
, GetJSObjectFromCallback(p
));
1531 // WrapNativeParent is a bit of a Swiss army knife that will
1532 // wrap anything for us.
1533 obj
= WrapNativeParent(cx
, p
);
1539 // But all that won't necessarily put things in the compartment of cx.
1540 if (!JS_WrapObject(cx
, &obj
)) {
1548 * This specialized function simply wraps a JS::Rooted<> since
1549 * WrapNativeParent() is not applicable for JS objects.
1553 WrapCallThisObject
<JS::Rooted
<JSObject
*>>(JSContext
* cx
,
1554 const JS::Rooted
<JSObject
*>& p
)
1556 JS::Rooted
<JSObject
*> obj(cx
, p
);
1558 if (!JS_WrapObject(cx
, &obj
)) {
1565 // Helper for calling WrapNewBindingObject with smart pointers
1566 // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
1567 template <class T
, bool isSmartPtr
=HasgetMember
<T
>::Value
>
1568 struct WrapNewBindingObjectHelper
1570 static inline bool Wrap(JSContext
* cx
, const T
& value
,
1571 JS::MutableHandle
<JS::Value
> rval
)
1573 return WrapNewBindingObject(cx
, value
.get(), rval
);
1578 struct WrapNewBindingObjectHelper
<T
, false>
1580 static inline bool Wrap(JSContext
* cx
, T
& value
,
1581 JS::MutableHandle
<JS::Value
> rval
)
1583 return WrapNewBindingObject(cx
, &value
, rval
);
1589 WrapNewBindingObject(JSContext
* cx
, T
& value
, JS::MutableHandle
<JS::Value
> rval
)
1591 return WrapNewBindingObjectHelper
<T
>::Wrap(cx
, value
, rval
);
1594 // We need this version of WrapNewBindingObject for codegen, so it'll have the
1595 // same signature as WrapNewBindingNonWrapperCachedObject and
1596 // WrapNewBindingNonWrapperCachedOwnedObject, which still need the scope.
1599 WrapNewBindingObject(JSContext
* cx
, JS::Handle
<JSObject
*> scope
, T
& value
,
1600 JS::MutableHandle
<JS::Value
> rval
)
1602 return WrapNewBindingObject(cx
, value
, rval
);
1607 GetCallbackFromCallbackObject(T
* aObj
)
1609 return aObj
->Callback();
1612 // Helper for getting the callback JSObject* of a smart ptr around a
1613 // CallbackObject or a reference to a CallbackObject or something like
1615 template <class T
, bool isSmartPtr
=HasgetMember
<T
>::Value
>
1616 struct GetCallbackFromCallbackObjectHelper
1618 static inline JSObject
* Get(const T
& aObj
)
1620 return GetCallbackFromCallbackObject(aObj
.get());
1625 struct GetCallbackFromCallbackObjectHelper
<T
, false>
1627 static inline JSObject
* Get(T
& aObj
)
1629 return GetCallbackFromCallbackObject(&aObj
);
1635 GetCallbackFromCallbackObject(T
& aObj
)
1637 return GetCallbackFromCallbackObjectHelper
<T
>::Get(aObj
);
1641 InternJSString(JSContext
* cx
, jsid
& id
, const char* chars
)
1643 if (JSString
*str
= ::JS_InternString(cx
, chars
)) {
1644 id
= INTERNED_STRING_TO_JSID(cx
, str
);
1650 // Spec needs a name property
1651 template <typename Spec
>
1653 InitIds(JSContext
* cx
, const Prefable
<Spec
>* prefableSpecs
, jsid
* ids
)
1655 MOZ_ASSERT(prefableSpecs
);
1656 MOZ_ASSERT(prefableSpecs
->specs
);
1658 // We ignore whether the set of ids is enabled and just intern all the IDs,
1659 // because this is only done once per application runtime.
1660 Spec
* spec
= prefableSpecs
->specs
;
1662 if (!InternJSString(cx
, *ids
, spec
->name
)) {
1665 } while (++ids
, (++spec
)->name
);
1667 // We ran out of ids for that pref. Put a JSID_VOID in on the id
1668 // corresponding to the list terminator for the pref.
1671 } while ((++prefableSpecs
)->specs
);
1677 QueryInterface(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
1683 static_assert(IsBaseOf
<nsISupports
, T
>::value
,
1684 "QueryInterface can't work without an nsISupports.");
1685 static bool Enabled(JSContext
* aCx
, JSObject
* aGlobal
)
1687 return NS_IsMainThread() && IsChromeOrXBL(aCx
, aGlobal
);
1692 GetInterfaceImpl(JSContext
* aCx
, nsIInterfaceRequestor
* aRequestor
,
1693 nsWrapperCache
* aCache
, nsIJSID
* aIID
,
1694 JS::MutableHandle
<JS::Value
> aRetval
, ErrorResult
& aError
);
1698 GetInterface(JSContext
* aCx
, T
* aThis
, nsIJSID
* aIID
,
1699 JS::MutableHandle
<JS::Value
> aRetval
, ErrorResult
& aError
)
1701 GetInterfaceImpl(aCx
, aThis
, aThis
, aIID
, aRetval
, aError
);
1705 UnforgeableValueOf(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
1708 ThrowingConstructor(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
1711 ThrowConstructorWithoutNew(JSContext
* cx
, const char* name
);
1713 // vp is allowed to be null; in that case no get will be attempted,
1714 // and *found will simply indicate whether the property exists.
1716 GetPropertyOnPrototype(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
1717 JS::Handle
<jsid
> id
, bool* found
,
1721 HasPropertyOnPrototype(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
1722 JS::Handle
<jsid
> id
);
1725 // Append the property names in "names" to "props". If
1726 // shadowPrototypeProperties is false then skip properties that are also
1727 // present on the proto chain of proxy. If shadowPrototypeProperties is true,
1728 // then the "proxy" argument is ignored.
1730 AppendNamedPropertyIds(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
1731 nsTArray
<nsString
>& names
,
1732 bool shadowPrototypeProperties
, JS::AutoIdVector
& props
);
1734 namespace binding_detail
{
1736 // A struct that has the same layout as an nsString but much faster
1737 // constructor and destructor behavior. FakeString uses inline storage
1738 // for small strings and a nsStringBuffer for longer strings.
1741 mFlags(nsString::F_TERMINATED
)
1746 if (mFlags
& nsString::F_SHARED
) {
1747 nsStringBuffer::FromData(mData
)->Release();
1751 void Rebind(const nsString::char_type
* aData
, nsString::size_type aLength
) {
1752 MOZ_ASSERT(mFlags
== nsString::F_TERMINATED
);
1753 mData
= const_cast<nsString::char_type
*>(aData
);
1758 MOZ_ASSERT(mFlags
== nsString::F_TERMINATED
);
1759 mData
= nsString::char_traits::sEmptyBuffer
;
1763 void SetIsVoid(bool aValue
) {
1765 "We don't support SetIsVoid(false) on FakeString!");
1767 mFlags
|= nsString::F_VOIDED
;
1770 const nsString::char_type
* Data() const
1775 nsString::char_type
* BeginWriting()
1780 nsString::size_type
Length() const
1785 // Reserve space to write aLength chars, not including null-terminator.
1786 bool SetLength(nsString::size_type aLength
, mozilla::fallible_t
const&) {
1787 // Use mInlineStorage for small strings.
1788 if (aLength
< sInlineCapacity
) {
1789 SetData(mInlineStorage
);
1791 nsStringBuffer
*buf
= nsStringBuffer::Alloc((aLength
+ 1) * sizeof(nsString::char_type
)).take();
1792 if (MOZ_UNLIKELY(!buf
)) {
1796 SetData(static_cast<nsString::char_type
*>(buf
->Data()));
1797 mFlags
= nsString::F_SHARED
| nsString::F_TERMINATED
;
1800 mData
[mLength
] = char16_t(0);
1804 // If this ever changes, change the corresponding code in the
1805 // Optional<nsAString> specialization as well.
1806 const nsAString
* ToAStringPtr() const {
1807 return reinterpret_cast<const nsString
*>(this);
1810 nsAString
* ToAStringPtr() {
1811 return reinterpret_cast<nsString
*>(this);
1814 operator const nsAString
& () const {
1815 return *reinterpret_cast<const nsString
*>(this);
1819 nsString::char_type
* mData
;
1820 nsString::size_type mLength
;
1823 static const size_t sInlineCapacity
= 64;
1824 nsString::char_type mInlineStorage
[sInlineCapacity
];
1826 FakeString(const FakeString
& other
) MOZ_DELETE
;
1827 void operator=(const FakeString
& other
) MOZ_DELETE
;
1829 void SetData(nsString::char_type
* aData
) {
1830 MOZ_ASSERT(mFlags
== nsString::F_TERMINATED
);
1831 mData
= const_cast<nsString::char_type
*>(aData
);
1834 // A class to use for our static asserts to ensure our object layout
1835 // matches that of nsString.
1836 class StringAsserter
;
1837 friend class StringAsserter
;
1839 class StringAsserter
: public nsString
{
1841 static void StaticAsserts() {
1842 static_assert(offsetof(FakeString
, mInlineStorage
) ==
1844 "FakeString should include all nsString members");
1845 static_assert(offsetof(FakeString
, mData
) ==
1846 offsetof(StringAsserter
, mData
),
1847 "Offset of mData should match");
1848 static_assert(offsetof(FakeString
, mLength
) ==
1849 offsetof(StringAsserter
, mLength
),
1850 "Offset of mLength should match");
1851 static_assert(offsetof(FakeString
, mFlags
) ==
1852 offsetof(StringAsserter
, mFlags
),
1853 "Offset of mFlags should match");
1858 } // namespace binding_detail
1860 enum StringificationBehavior
{
1866 template<typename T
>
1868 ConvertJSValueToString(JSContext
* cx
, JS::Handle
<JS::Value
> v
,
1869 StringificationBehavior nullBehavior
,
1870 StringificationBehavior undefinedBehavior
,
1877 StringificationBehavior behavior
;
1879 behavior
= nullBehavior
;
1880 } else if (v
.isUndefined()) {
1881 behavior
= undefinedBehavior
;
1883 behavior
= eStringify
;
1886 if (behavior
!= eStringify
) {
1887 if (behavior
== eEmpty
) {
1890 result
.SetIsVoid(true);
1895 s
= JS::ToString(cx
, v
);
1901 return AssignJSString(cx
, result
, s
);
1905 NormalizeScalarValueString(JSContext
* aCx
, nsAString
& aString
);
1908 NormalizeScalarValueString(JSContext
* aCx
, binding_detail::FakeString
& aString
);
1910 template<typename T
>
1912 ConvertIdToString(JSContext
* cx
, JS::HandleId id
, T
& result
, bool& isSymbol
)
1914 if (MOZ_LIKELY(JSID_IS_STRING(id
))) {
1915 if (!AssignJSString(cx
, result
, JSID_TO_STRING(id
))) {
1918 } else if (JSID_IS_SYMBOL(id
)) {
1922 JS::RootedValue
nameVal(cx
, js::IdToValue(id
));
1923 if (!ConvertJSValueToString(cx
, nameVal
, eStringify
, eStringify
, result
)) {
1932 ConvertJSValueToByteString(JSContext
* cx
, JS::Handle
<JS::Value
> v
,
1933 bool nullable
, nsACString
& result
);
1935 template<typename T
>
1936 void DoTraceSequence(JSTracer
* trc
, FallibleTArray
<T
>& seq
);
1937 template<typename T
>
1938 void DoTraceSequence(JSTracer
* trc
, InfallibleTArray
<T
>& seq
);
1940 // Class for simple sequence arguments, only used internally by codegen.
1941 namespace binding_detail
{
1943 template<typename T
>
1944 class AutoSequence
: public AutoFallibleTArray
<T
, 16>
1947 AutoSequence() : AutoFallibleTArray
<T
, 16>()
1950 // Allow converting to const sequences as needed
1951 operator const Sequence
<T
>&() const {
1952 return *reinterpret_cast<const Sequence
<T
>*>(this);
1956 } // namespace binding_detail
1958 // Class used to trace sequences, with specializations for various
1960 template<typename T
,
1961 bool isDictionary
=IsBaseOf
<DictionaryBase
, T
>::value
,
1962 bool isTypedArray
=IsBaseOf
<AllTypedArraysBase
, T
>::value
,
1963 bool isOwningUnion
=IsBaseOf
<AllOwningUnionBase
, T
>::value
>
1964 class SequenceTracer
1966 explicit SequenceTracer() MOZ_DELETE
; // Should never be instantiated
1969 // sequence<object> or sequence<object?>
1971 class SequenceTracer
<JSObject
*, false, false, false>
1973 explicit SequenceTracer() MOZ_DELETE
; // Should never be instantiated
1976 static void TraceSequence(JSTracer
* trc
, JSObject
** objp
, JSObject
** end
) {
1977 for (; objp
!= end
; ++objp
) {
1978 JS_CallUnbarrieredObjectTracer(trc
, objp
, "sequence<object>");
1985 class SequenceTracer
<JS::Value
, false, false, false>
1987 explicit SequenceTracer() MOZ_DELETE
; // Should never be instantiated
1990 static void TraceSequence(JSTracer
* trc
, JS::Value
* valp
, JS::Value
* end
) {
1991 for (; valp
!= end
; ++valp
) {
1992 JS_CallUnbarrieredValueTracer(trc
, valp
, "sequence<any>");
1997 // sequence<sequence<T>>
1998 template<typename T
>
1999 class SequenceTracer
<Sequence
<T
>, false, false, false>
2001 explicit SequenceTracer() MOZ_DELETE
; // Should never be instantiated
2004 static void TraceSequence(JSTracer
* trc
, Sequence
<T
>* seqp
, Sequence
<T
>* end
) {
2005 for (; seqp
!= end
; ++seqp
) {
2006 DoTraceSequence(trc
, *seqp
);
2011 // sequence<sequence<T>> as return value
2012 template<typename T
>
2013 class SequenceTracer
<nsTArray
<T
>, false, false, false>
2015 explicit SequenceTracer() MOZ_DELETE
; // Should never be instantiated
2018 static void TraceSequence(JSTracer
* trc
, nsTArray
<T
>* seqp
, nsTArray
<T
>* end
) {
2019 for (; seqp
!= end
; ++seqp
) {
2020 DoTraceSequence(trc
, *seqp
);
2025 // sequence<someDictionary>
2026 template<typename T
>
2027 class SequenceTracer
<T
, true, false, false>
2029 explicit SequenceTracer() MOZ_DELETE
; // Should never be instantiated
2032 static void TraceSequence(JSTracer
* trc
, T
* dictp
, T
* end
) {
2033 for (; dictp
!= end
; ++dictp
) {
2034 dictp
->TraceDictionary(trc
);
2039 // sequence<SomeTypedArray>
2040 template<typename T
>
2041 class SequenceTracer
<T
, false, true, false>
2043 explicit SequenceTracer() MOZ_DELETE
; // Should never be instantiated
2046 static void TraceSequence(JSTracer
* trc
, T
* arrayp
, T
* end
) {
2047 for (; arrayp
!= end
; ++arrayp
) {
2048 arrayp
->TraceSelf(trc
);
2053 // sequence<SomeOwningUnion>
2054 template<typename T
>
2055 class SequenceTracer
<T
, false, false, true>
2057 explicit SequenceTracer() MOZ_DELETE
; // Should never be instantiated
2060 static void TraceSequence(JSTracer
* trc
, T
* arrayp
, T
* end
) {
2061 for (; arrayp
!= end
; ++arrayp
) {
2062 arrayp
->TraceUnion(trc
);
2067 // sequence<T?> with T? being a Nullable<T>
2068 template<typename T
>
2069 class SequenceTracer
<Nullable
<T
>, false, false, false>
2071 explicit SequenceTracer() MOZ_DELETE
; // Should never be instantiated
2074 static void TraceSequence(JSTracer
* trc
, Nullable
<T
>* seqp
,
2076 for (; seqp
!= end
; ++seqp
) {
2077 if (!seqp
->IsNull()) {
2078 // Pretend like we actually have a length-one sequence here so
2079 // we can do template instantiation correctly for T.
2080 T
& val
= seqp
->Value();
2082 SequenceTracer
<T
>::TraceSequence(trc
, ptr
, ptr
+1);
2088 // XXXbz It's not clear whether it's better to add a pldhash dependency here
2089 // (for PLDHashOperator) or add a BindingUtils.h dependency (for
2090 // SequenceTracer) to MozMap.h...
2091 template<typename T
>
2092 static PLDHashOperator
2093 TraceMozMapValue(T
* aValue
, void* aClosure
)
2095 JSTracer
* trc
= static_cast<JSTracer
*>(aClosure
);
2096 // Act like it's a one-element sequence to leverage all that infrastructure.
2097 SequenceTracer
<T
>::TraceSequence(trc
, aValue
, aValue
+ 1);
2098 return PL_DHASH_NEXT
;
2101 template<typename T
>
2102 void TraceMozMap(JSTracer
* trc
, MozMap
<T
>& map
)
2104 map
.EnumerateValues(TraceMozMapValue
<T
>, trc
);
2108 template<typename T
>
2109 class SequenceTracer
<MozMap
<T
>, false, false, false>
2111 explicit SequenceTracer() MOZ_DELETE
; // Should never be instantiated
2114 static void TraceSequence(JSTracer
* trc
, MozMap
<T
>* seqp
, MozMap
<T
>* end
) {
2115 for (; seqp
!= end
; ++seqp
) {
2116 seqp
->EnumerateValues(TraceMozMapValue
<T
>, trc
);
2121 template<typename T
>
2122 void DoTraceSequence(JSTracer
* trc
, FallibleTArray
<T
>& seq
)
2124 SequenceTracer
<T
>::TraceSequence(trc
, seq
.Elements(),
2125 seq
.Elements() + seq
.Length());
2128 template<typename T
>
2129 void DoTraceSequence(JSTracer
* trc
, InfallibleTArray
<T
>& seq
)
2131 SequenceTracer
<T
>::TraceSequence(trc
, seq
.Elements(),
2132 seq
.Elements() + seq
.Length());
2135 // Rooter class for sequences; this is what we mostly use in the codegen
2136 template<typename T
>
2137 class MOZ_STACK_CLASS SequenceRooter
: private JS::CustomAutoRooter
2140 SequenceRooter(JSContext
*aCx
, FallibleTArray
<T
>* aSequence
2141 MOZ_GUARD_OBJECT_NOTIFIER_PARAM
)
2142 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT
),
2143 mFallibleArray(aSequence
),
2144 mSequenceType(eFallibleArray
)
2148 SequenceRooter(JSContext
*aCx
, InfallibleTArray
<T
>* aSequence
2149 MOZ_GUARD_OBJECT_NOTIFIER_PARAM
)
2150 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT
),
2151 mInfallibleArray(aSequence
),
2152 mSequenceType(eInfallibleArray
)
2156 SequenceRooter(JSContext
*aCx
, Nullable
<nsTArray
<T
> >* aSequence
2157 MOZ_GUARD_OBJECT_NOTIFIER_PARAM
)
2158 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT
),
2159 mNullableArray(aSequence
),
2160 mSequenceType(eNullableArray
)
2171 virtual void trace(JSTracer
*trc
) MOZ_OVERRIDE
2173 if (mSequenceType
== eFallibleArray
) {
2174 DoTraceSequence(trc
, *mFallibleArray
);
2175 } else if (mSequenceType
== eInfallibleArray
) {
2176 DoTraceSequence(trc
, *mInfallibleArray
);
2178 MOZ_ASSERT(mSequenceType
== eNullableArray
);
2179 if (!mNullableArray
->IsNull()) {
2180 DoTraceSequence(trc
, mNullableArray
->Value());
2186 InfallibleTArray
<T
>* mInfallibleArray
;
2187 FallibleTArray
<T
>* mFallibleArray
;
2188 Nullable
<nsTArray
<T
> >* mNullableArray
;
2191 SequenceType mSequenceType
;
2194 // Rooter class for MozMap; this is what we mostly use in the codegen.
2195 template<typename T
>
2196 class MOZ_STACK_CLASS MozMapRooter
: private JS::CustomAutoRooter
2199 MozMapRooter(JSContext
*aCx
, MozMap
<T
>* aMozMap
2200 MOZ_GUARD_OBJECT_NOTIFIER_PARAM
)
2201 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT
),
2203 mMozMapType(eMozMap
)
2207 MozMapRooter(JSContext
*aCx
, Nullable
<MozMap
<T
>>* aMozMap
2208 MOZ_GUARD_OBJECT_NOTIFIER_PARAM
)
2209 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT
),
2210 mNullableMozMap(aMozMap
),
2211 mMozMapType(eNullableMozMap
)
2221 virtual void trace(JSTracer
*trc
) MOZ_OVERRIDE
2223 if (mMozMapType
== eMozMap
) {
2224 TraceMozMap(trc
, *mMozMap
);
2226 MOZ_ASSERT(mMozMapType
== eNullableMozMap
);
2227 if (!mNullableMozMap
->IsNull()) {
2228 TraceMozMap(trc
, mNullableMozMap
->Value());
2235 Nullable
<MozMap
<T
>>* mNullableMozMap
;
2238 MozMapType mMozMapType
;
2241 template<typename T
>
2242 class MOZ_STACK_CLASS RootedUnion
: public T
,
2243 private JS::CustomAutoRooter
2246 explicit RootedUnion(JSContext
* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM
) :
2248 JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT
)
2252 virtual void trace(JSTracer
*trc
) MOZ_OVERRIDE
2254 this->TraceUnion(trc
);
2258 template<typename T
>
2259 class MOZ_STACK_CLASS NullableRootedUnion
: public Nullable
<T
>,
2260 private JS::CustomAutoRooter
2263 explicit NullableRootedUnion(JSContext
* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM
) :
2265 JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT
)
2269 virtual void trace(JSTracer
*trc
) MOZ_OVERRIDE
2271 if (!this->IsNull()) {
2272 this->Value().TraceUnion(trc
);
2278 IdEquals(jsid id
, const char* string
)
2280 return JSID_IS_STRING(id
) &&
2281 JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id
), string
);
2285 AddStringToIDVector(JSContext
* cx
, JS::AutoIdVector
& vector
, const char* name
)
2287 return vector
.growBy(1) &&
2288 InternJSString(cx
, *(vector
[vector
.length() - 1]).address(), name
);
2291 // Implementation of the bits that XrayWrapper needs
2294 * This resolves indexed or named properties of obj.
2296 * wrapper is the Xray JS object.
2297 * obj is the target object of the Xray, a binding's instance object or a
2298 * interface or interface prototype object.
2301 XrayResolveOwnProperty(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
2302 JS::Handle
<JSObject
*> obj
,
2303 JS::Handle
<jsid
> id
,
2304 JS::MutableHandle
<JSPropertyDescriptor
> desc
,
2305 bool& cacheOnHolder
);
2308 * This resolves operations, attributes and constants of the interfaces for obj.
2310 * wrapper is the Xray JS object.
2311 * obj is the target object of the Xray, a binding's instance object or a
2312 * interface or interface prototype object.
2315 XrayResolveNativeProperty(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
2316 JS::Handle
<JSObject
*> obj
,
2317 JS::Handle
<jsid
> id
, JS::MutableHandle
<JSPropertyDescriptor
> desc
,
2318 bool& cacheOnHolder
);
2321 * Define a property on obj through an Xray wrapper.
2323 * wrapper is the Xray JS object.
2324 * obj is the target object of the Xray, a binding's instance object or a
2325 * interface or interface prototype object.
2326 * defined will be set to true if a property was set as a result of this call.
2329 XrayDefineProperty(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
2330 JS::Handle
<JSObject
*> obj
, JS::Handle
<jsid
> id
,
2331 JS::MutableHandle
<JSPropertyDescriptor
> desc
, bool* defined
);
2334 * This enumerates indexed or named properties of obj and operations, attributes
2335 * and constants of the interfaces for obj.
2337 * wrapper is the Xray JS object.
2338 * obj is the target object of the Xray, a binding's instance object or a
2339 * interface or interface prototype object.
2340 * flags are JSITER_* flags.
2343 XrayEnumerateProperties(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
2344 JS::Handle
<JSObject
*> obj
,
2345 unsigned flags
, JS::AutoIdVector
& props
);
2347 extern NativePropertyHooks sWorkerNativePropertyHooks
;
2349 // We use one constructor JSNative to represent all DOM interface objects (so
2350 // we can easily detect when we need to wrap them in an Xray wrapper). We store
2351 // the real JSNative in the mNative member of a JSNativeHolder in the
2352 // CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction object for a
2353 // specific interface object. We also store the NativeProperties in the
2355 // Note that some interface objects are not yet a JSFunction but a normal
2356 // JSObject with a DOMJSClass, those do not use these slots.
2359 CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT
= 0
2363 Constructor(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
2366 UseDOMXray(JSObject
* obj
)
2368 const js::Class
* clasp
= js::GetObjectClass(obj
);
2369 return IsDOMClass(clasp
) ||
2370 JS_IsNativeFunction(obj
, Constructor
) ||
2371 IsDOMIfaceAndProtoClass(clasp
);
2376 HasConstructor(JSObject
* obj
)
2378 return JS_IsNativeFunction(obj
, Constructor
) ||
2379 js::GetObjectClass(obj
)->construct
;
2383 // Transfer reference in ptr to smartPtr.
2386 Take(nsRefPtr
<T
>& smartPtr
, T
* ptr
)
2388 smartPtr
= dont_AddRef(ptr
);
2391 // Transfer ownership of ptr to smartPtr.
2394 Take(nsAutoPtr
<T
>& smartPtr
, T
* ptr
)
2400 MustInheritFromNonRefcountedDOMObject(NonRefcountedDOMObject
*)
2405 * This creates a JSString containing the value that the toString function for
2406 * obj should create according to the WebIDL specification, ignoring any
2407 * modifications by script. The value is prefixed with pre and postfixed with
2408 * post, unless this is called for an object that has a stringifier. It is
2409 * specifically for use by Xray code.
2411 * wrapper is the Xray JS object.
2412 * obj is the target object of the Xray, a binding's instance object or a
2413 * interface or interface prototype object.
2414 * v contains the JSString for the value if the function returns true.
2417 NativeToString(JSContext
* cx
, JS::Handle
<JSObject
*> wrapper
,
2418 JS::Handle
<JSObject
*> obj
,
2419 JS::MutableHandle
<JS::Value
> v
);
2421 HAS_MEMBER(JSBindingFinalized
)
2423 template<class T
, bool hasCallback
=HasJSBindingFinalizedMember
<T
>::Value
>
2424 struct JSBindingFinalized
2426 static void Finalized(T
* self
)
2432 struct JSBindingFinalized
<T
, true>
2434 static void Finalized(T
* self
)
2436 self
->JSBindingFinalized();
2440 // Helpers for creating a const version of a type.
2441 template<typename T
>
2442 const T
& Constify(T
& arg
)
2447 // Helper for turning (Owning)NonNull<T> into T&
2448 template<typename T
>
2449 T
& NonNullHelper(T
& aArg
)
2454 template<typename T
>
2455 T
& NonNullHelper(NonNull
<T
>& aArg
)
2460 template<typename T
>
2461 const T
& NonNullHelper(const NonNull
<T
>& aArg
)
2466 template<typename T
>
2467 T
& NonNullHelper(OwningNonNull
<T
>& aArg
)
2472 template<typename T
>
2473 const T
& NonNullHelper(const OwningNonNull
<T
>& aArg
)
2479 void NonNullHelper(NonNull
<binding_detail::FakeString
>& aArg
)
2481 // This overload is here to make sure that we never end up applying
2482 // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
2483 // try to, it should fail to compile, since presumably the caller will try to
2484 // use our nonexistent return value.
2488 void NonNullHelper(const NonNull
<binding_detail::FakeString
>& aArg
)
2490 // This overload is here to make sure that we never end up applying
2491 // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
2492 // try to, it should fail to compile, since presumably the caller will try to
2493 // use our nonexistent return value.
2497 void NonNullHelper(binding_detail::FakeString
& aArg
)
2499 // This overload is here to make sure that we never end up applying
2500 // NonNullHelper to a FakeString before we've constified it. If we
2501 // try to, it should fail to compile, since presumably the caller will try to
2502 // use our nonexistent return value.
2506 const nsAString
& NonNullHelper(const binding_detail::FakeString
& aArg
)
2511 // Reparent the wrapper of aObj to whatever its native now thinks its
2512 // parent should be.
2514 ReparentWrapper(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
);
2517 * Used to implement the hasInstance hook of an interface object.
2519 * instance should not be a security wrapper.
2522 InterfaceHasInstance(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
2523 JS::Handle
<JSObject
*> instance
,
2526 InterfaceHasInstance(JSContext
* cx
, JS::Handle
<JSObject
*> obj
, JS::MutableHandle
<JS::Value
> vp
,
2529 InterfaceHasInstance(JSContext
* cx
, int prototypeID
, int depth
,
2530 JS::Handle
<JSObject
*> instance
,
2533 // Helper for lenient getters/setters to report to console. If this
2534 // returns false, we couldn't even get a global.
2536 ReportLenientThisUnwrappingFailure(JSContext
* cx
, JSObject
* obj
);
2539 GetUnforgeableHolder(JSObject
* aGlobal
, prototypes::ID aId
)
2541 ProtoAndIfaceCache
& protoAndIfaceCache
= *GetProtoAndIfaceCache(aGlobal
);
2542 JSObject
* interfaceProto
= protoAndIfaceCache
.EntrySlotMustExist(aId
);
2543 return &js::GetReservedSlot(interfaceProto
,
2544 DOM_INTERFACE_PROTO_SLOTS_BASE
).toObject();
2547 // Given a JSObject* that represents the chrome side of a JS-implemented WebIDL
2548 // interface, get the nsPIDOMWindow corresponding to the content side, if any.
2549 // A false return means an exception was thrown.
2551 GetWindowForJSImplementedObject(JSContext
* cx
, JS::Handle
<JSObject
*> obj
,
2552 nsPIDOMWindow
** window
);
2555 ConstructJSImplementation(JSContext
* aCx
, const char* aContractId
,
2556 nsPIDOMWindow
* aWindow
,
2557 JS::MutableHandle
<JSObject
*> aObject
,
2560 already_AddRefed
<nsPIDOMWindow
>
2561 ConstructJSImplementation(JSContext
* aCx
, const char* aContractId
,
2562 const GlobalObject
& aGlobal
,
2563 JS::MutableHandle
<JSObject
*> aObject
,
2567 * Convert an nsCString to jsval, returning true on success.
2568 * These functions are intended for ByteString implementations.
2569 * As such, the string is not UTF-8 encoded. Any UTF8 strings passed to these
2570 * methods will be mangled.
2572 bool NonVoidByteStringToJsval(JSContext
*cx
, const nsACString
&str
,
2573 JS::MutableHandle
<JS::Value
> rval
);
2574 inline bool ByteStringToJsval(JSContext
*cx
, const nsACString
&str
,
2575 JS::MutableHandle
<JS::Value
> rval
)
2581 return NonVoidByteStringToJsval(cx
, str
, rval
);
2584 template<class T
, bool isISupports
=IsBaseOf
<nsISupports
, T
>::value
>
2585 struct PreserveWrapperHelper
2587 static void PreserveWrapper(T
* aObject
)
2589 aObject
->PreserveWrapper(aObject
, NS_CYCLE_COLLECTION_PARTICIPANT(T
));
2594 struct PreserveWrapperHelper
<T
, true>
2596 static void PreserveWrapper(T
* aObject
)
2598 aObject
->PreserveWrapper(reinterpret_cast<nsISupports
*>(aObject
));
2603 void PreserveWrapper(T
* aObject
)
2605 PreserveWrapperHelper
<T
>::PreserveWrapper(aObject
);
2608 template<class T
, bool isISupports
=IsBaseOf
<nsISupports
, T
>::value
>
2609 struct CastingAssertions
2611 static bool ToSupportsIsCorrect(T
*)
2615 static bool ToSupportsIsOnPrimaryInheritanceChain(T
*, nsWrapperCache
*)
2622 struct CastingAssertions
<T
, true>
2624 static bool ToSupportsIsCorrect(T
* aObject
)
2626 return ToSupports(aObject
) == reinterpret_cast<nsISupports
*>(aObject
);
2628 static bool ToSupportsIsOnPrimaryInheritanceChain(T
* aObject
,
2629 nsWrapperCache
* aCache
)
2631 return reinterpret_cast<void*>(aObject
) != aCache
;
2637 ToSupportsIsCorrect(T
* aObject
)
2639 return CastingAssertions
<T
>::ToSupportsIsCorrect(aObject
);
2644 ToSupportsIsOnPrimaryInheritanceChain(T
* aObject
, nsWrapperCache
* aCache
)
2646 return CastingAssertions
<T
>::ToSupportsIsOnPrimaryInheritanceChain(aObject
,
2650 template<class T
, template <typename
> class SmartPtr
,
2651 bool isISupports
=IsBaseOf
<nsISupports
, T
>::value
>
2652 class DeferredFinalizer
2654 typedef nsTArray
<SmartPtr
<T
> > SmartPtrArray
;
2657 AppendDeferredFinalizePointer(void* aData
, void* aObject
)
2659 SmartPtrArray
* pointers
= static_cast<SmartPtrArray
*>(aData
);
2661 pointers
= new SmartPtrArray();
2664 T
* self
= static_cast<T
*>(aObject
);
2666 SmartPtr
<T
>* defer
= pointers
->AppendElement();
2671 DeferredFinalize(uint32_t aSlice
, void* aData
)
2673 MOZ_ASSERT(aSlice
> 0, "nonsensical/useless call with aSlice == 0");
2674 SmartPtrArray
* pointers
= static_cast<SmartPtrArray
*>(aData
);
2675 uint32_t oldLen
= pointers
->Length();
2676 if (oldLen
< aSlice
) {
2679 uint32_t newLen
= oldLen
- aSlice
;
2680 pointers
->RemoveElementsAt(newLen
, aSlice
);
2690 AddForDeferredFinalization(T
* aObject
)
2692 cyclecollector::DeferredFinalize(AppendDeferredFinalizePointer
,
2693 DeferredFinalize
, aObject
);
2697 template<class T
, template <typename
> class SmartPtr
>
2698 class DeferredFinalizer
<T
, SmartPtr
, true>
2702 AddForDeferredFinalization(T
* aObject
)
2704 cyclecollector::DeferredFinalize(reinterpret_cast<nsISupports
*>(aObject
));
2708 template<class T
, template <typename
> class SmartPtr
>
2710 AddForDeferredFinalization(T
* aObject
)
2712 DeferredFinalizer
<T
, SmartPtr
>::AddForDeferredFinalization(aObject
);
2715 // This returns T's CC participant if it participates in CC or null if it
2716 // doesn't. This also returns null for classes that don't inherit from
2717 // nsISupports (QI should be used to get the participant for those).
2718 template<class T
, bool isISupports
=IsBaseOf
<nsISupports
, T
>::value
>
2719 class GetCCParticipant
2721 // Helper for GetCCParticipant for classes that participate in CC.
2723 static MOZ_CONSTEXPR nsCycleCollectionParticipant
*
2724 GetHelper(int, typename
U::NS_CYCLE_COLLECTION_INNERCLASS
* dummy
=nullptr)
2726 return T::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant();
2728 // Helper for GetCCParticipant for classes that don't participate in CC.
2730 static MOZ_CONSTEXPR nsCycleCollectionParticipant
*
2737 static MOZ_CONSTEXPR nsCycleCollectionParticipant
*
2740 // Passing int() here will try to call the GetHelper that takes an int as
2741 // its firt argument. If T doesn't participate in CC then substitution for
2742 // the second argument (with a default value) will fail and because of
2743 // SFINAE the next best match (the variant taking a double) will be called.
2744 return GetHelper
<T
>(int());
2749 class GetCCParticipant
<T
, true>
2752 static MOZ_CONSTEXPR nsCycleCollectionParticipant
*
2760 * Helper function for testing whether the given object comes from a
2764 IsInPrivilegedApp(JSContext
* aCx
, JSObject
* aObj
);
2767 * Helper function for testing whether the given object comes from a
2771 IsInCertifiedApp(JSContext
* aCx
, JSObject
* aObj
);
2774 FinalizeGlobal(JSFreeOp
* aFop
, JSObject
* aObj
);
2777 ResolveGlobal(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
,
2778 JS::Handle
<jsid
> aId
, JS::MutableHandle
<JSObject
*> aObjp
);
2781 EnumerateGlobal(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
);
2784 struct CreateGlobalOptions
2786 static MOZ_CONSTEXPR_VAR
ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind
=
2787 ProtoAndIfaceCache::NonWindowLike
;
2788 // Intl API is broken and makes JS_InitStandardClasses fail intermittently,
2790 static MOZ_CONSTEXPR_VAR
bool ForceInitStandardClassesToFalse
= true;
2791 static void TraceGlobal(JSTracer
* aTrc
, JSObject
* aObj
)
2793 mozilla::dom::TraceProtoAndIfaceCache(aTrc
, aObj
);
2795 static bool PostCreateGlobal(JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
)
2797 MOZ_ALWAYS_TRUE(TryPreserveWrapper(aGlobal
));
2804 struct CreateGlobalOptions
<nsGlobalWindow
>
2806 static MOZ_CONSTEXPR_VAR
ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind
=
2807 ProtoAndIfaceCache::WindowLike
;
2808 static MOZ_CONSTEXPR_VAR
bool ForceInitStandardClassesToFalse
= false;
2809 static void TraceGlobal(JSTracer
* aTrc
, JSObject
* aObj
);
2810 static bool PostCreateGlobal(JSContext
* aCx
, JS::Handle
<JSObject
*> aGlobal
);
2816 template <class T
, ProtoGetter GetProto
>
2818 CreateGlobal(JSContext
* aCx
, T
* aNative
, nsWrapperCache
* aCache
,
2819 const JSClass
* aClass
, JS::CompartmentOptions
& aOptions
,
2820 JSPrincipals
* aPrincipal
, bool aInitStandardClasses
,
2821 JS::MutableHandle
<JSObject
*> aGlobal
)
2823 aOptions
.setTrace(CreateGlobalOptions
<T
>::TraceGlobal
);
2825 aGlobal
.set(JS_NewGlobalObject(aCx
, aClass
, aPrincipal
,
2826 JS::DontFireOnNewGlobalHook
, aOptions
));
2828 NS_WARNING("Failed to create global");
2832 JSAutoCompartment
ac(aCx
, aGlobal
);
2835 js::SetReservedSlot(aGlobal
, DOM_OBJECT_SLOT
, PRIVATE_TO_JSVAL(aNative
));
2838 aCache
->SetIsDOMBinding();
2839 aCache
->SetWrapper(aGlobal
);
2841 dom::AllocateProtoAndIfaceCache(aGlobal
,
2842 CreateGlobalOptions
<T
>::ProtoAndIfaceCacheKind
);
2844 if (!CreateGlobalOptions
<T
>::PostCreateGlobal(aCx
, aGlobal
)) {
2849 if (aInitStandardClasses
&&
2850 !CreateGlobalOptions
<T
>::ForceInitStandardClassesToFalse
&&
2851 !JS_InitStandardClasses(aCx
, aGlobal
)) {
2852 NS_WARNING("Failed to init standard classes");
2856 JS::Handle
<JSObject
*> proto
= GetProto(aCx
, aGlobal
);
2857 if (!proto
|| !JS_SplicePrototype(aCx
, aGlobal
, proto
)) {
2858 NS_WARNING("Failed to set proto");
2866 * Holds a jsid that is initialized to an interned string, with conversion to
2869 class InternedStringId
2874 InternedStringId() : id(JSID_VOID
) {}
2876 bool init(JSContext
*cx
, const char *string
) {
2877 JSString
* str
= JS_InternString(cx
, string
);
2880 id
= INTERNED_STRING_TO_JSID(cx
, str
);
2884 operator const jsid
& () {
2888 operator JS::Handle
<jsid
> () {
2889 /* This is safe because we have interned the string. */
2890 return JS::Handle
<jsid
>::fromMarkedLocation(&id
);
2895 GenericBindingGetter(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
2898 GenericBindingSetter(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
2901 GenericBindingMethod(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
2904 GenericPromiseReturningBindingMethod(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
2907 StaticMethodPromiseWrapper(JSContext
* cx
, unsigned argc
, JS::Value
* vp
);
2909 // ConvertExceptionToPromise should only be called when we have an error
2910 // condition (e.g. returned false from a JSAPI method). Note that there may be
2911 // no exception on cx, in which case this is an uncatchable failure that will
2912 // simply be propagated. Otherwise this method will attempt to convert the
2913 // exception to a Promise rejected with the exception that it will store in
2916 // promiseScope should be the scope in which the Promise should be created.
2918 ConvertExceptionToPromise(JSContext
* cx
,
2919 JSObject
* promiseScope
,
2920 JS::MutableHandle
<JS::Value
> rval
);
2922 // While we wait for the outcome of spec discussions on whether properties for
2923 // DOM global objects live on the object or the prototype, we supply this one
2924 // place to switch the behaviour, so we can easily turn this off on branches.
2926 GlobalPropertiesAreOwn()
2933 AssertReturnTypeMatchesJitinfo(const JSJitInfo
* aJitinfo
,
2934 JS::Handle
<JS::Value
> aValue
);
2937 // Returns true if aObj's global has any of the permissions named in aPermissions
2938 // set to nsIPermissionManager::ALLOW_ACTION. aPermissions must be null-terminated.
2940 CheckPermissions(JSContext
* aCx
, JSObject
* aObj
, const char* const aPermissions
[]);
2942 //Returns true if page is being prerendered.
2944 CheckSafetyInPrerendering(JSContext
* aCx
, JSObject
* aObj
);
2947 CallerSubsumes(JSObject
* aObject
);
2949 MOZ_ALWAYS_INLINE
bool
2950 CallerSubsumes(JS::Handle
<JS::Value
> aValue
)
2952 if (!aValue
.isObject()) {
2955 return CallerSubsumes(&aValue
.toObject());
2960 WrappedJSToDictionary(nsISupports
* aObject
, T
& aDictionary
)
2962 nsCOMPtr
<nsIXPConnectWrappedJS
> wrappedObj
= do_QueryInterface(aObject
);
2970 JSContext
* cx
= jsapi
.cx();
2971 JS::Rooted
<JSObject
*> obj(cx
, wrappedObj
->GetJSObject());
2976 JSAutoCompartment
ac(cx
, obj
);
2977 JS::Rooted
<JS::Value
> v(cx
, OBJECT_TO_JSVAL(obj
));
2978 return aDictionary
.Init(cx
, v
);
2982 } // namespace mozilla
2984 #endif /* mozilla_dom_BindingUtils_h__ */