Bumping manifests a=b2g-bump
[gecko.git] / dom / bindings / BindingUtils.h
blob3e54fc67bb891e8c4a6f400189ab1c8ea8f9ed36
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"
40 class nsIJSID;
41 class nsPIDOMWindow;
43 extern nsresult
44 xpc_qsUnwrapArgImpl(JSContext* cx, JS::Handle<JS::Value> v, const nsIID& iid, void** ppArg,
45 nsISupports** ppArgRef, JS::MutableHandle<JS::Value> vp);
47 namespace mozilla {
48 namespace dom {
49 template<typename DataType> class MozMap;
51 struct SelfRef
53 SelfRef() : ptr(nullptr) {}
54 explicit SelfRef(nsISupports *p) : ptr(p) {}
55 ~SelfRef() { NS_IF_RELEASE(ptr); }
57 nsISupports* ptr;
60 /** Convert a jsval to an XPCOM pointer. */
61 template <class Interface, class StrongRefType>
62 inline nsresult
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,
69 vp);
70 *ppArgRef = static_cast<StrongRefType*>(argRef);
71 return rv;
74 inline const ErrNum
75 GetInvalidThisErrorForMethod(bool aSecurityError)
77 return aSecurityError ? MSG_METHOD_THIS_UNWRAPPING_DENIED :
78 MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
81 inline const ErrNum
82 GetInvalidThisErrorForGetter(bool aSecurityError)
84 return aSecurityError ? MSG_GETTER_THIS_UNWRAPPING_DENIED :
85 MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
88 inline const ErrNum
89 GetInvalidThisErrorForSetter(bool aSecurityError)
91 return aSecurityError ? MSG_SETTER_THIS_UNWRAPPING_DENIED :
92 MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
95 bool
96 ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
97 const ErrNum aErrorNumber,
98 const char* aInterfaceName);
100 bool
101 ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
102 const ErrNum aErrorNumber,
103 prototypes::ID aProtoId);
105 inline bool
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);
113 return false;
115 if (rv.IsJSException()) {
116 if (reportJSContentExceptions) {
117 rv.ReportJSExceptionFromJSImplementation(cx);
118 } else {
119 rv.ReportJSException(cx);
121 return false;
123 if (rv.IsNotEnoughArgsError()) {
124 rv.ReportNotEnoughArgsError(cx, ifaceName, memberName);
125 return false;
127 return Throw(cx, rv.ErrorCode());
130 // Returns true if the JSClass is used for DOM objects.
131 inline bool
132 IsDOMClass(const JSClass* clasp)
134 return clasp->flags & JSCLASS_IS_DOMJSCLASS;
137 inline bool
138 IsDOMClass(const js::Class* clasp)
140 return IsDOMClass(Jsvalify(clasp));
143 // Return true if the JSClass is used for non-proxy DOM objects.
144 inline bool
145 IsNonProxyDOMClass(const js::Class* clasp)
147 return IsDOMClass(clasp) && !clasp->isProxy();
150 inline bool
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.
158 inline bool
159 IsDOMIfaceAndProtoClass(const JSClass* clasp)
161 return clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS;
164 inline bool
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");
173 template <class T>
174 inline T*
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);
191 return nullptr;
194 inline nsISupports*
195 UnwrapDOMObjectToISupports(JSObject* aObject)
197 const DOMJSClass* clasp = GetDOMClass(aObject);
198 if (!clasp || !clasp->mDOMObjectIsISupports) {
199 return nullptr;
202 return UnwrapDOMObject<nsISupports>(aObject);
205 inline bool
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,
222 uint32_t protoDepth)
224 /* First check to see whether we have a DOM object */
225 const DOMJSClass* domClass = GetDOMClass(obj);
226 if (!domClass) {
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);
234 if (!obj) {
235 return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
237 MOZ_ASSERT(!js::IsWrapper(obj));
238 domClass = GetDOMClass(obj);
239 if (!domClass) {
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);
250 return NS_OK;
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);
265 inline bool
266 IsNotDateOrRegExp(JSContext* cx, JS::Handle<JSObject*> obj)
268 MOZ_ASSERT(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>
311 public:
312 JSObject* EntrySlotIfExists(size_t i) {
313 return (*this)[i];
316 JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
317 return (*this)[i];
320 JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
321 MOZ_ASSERT((*this)[i]);
322 return (*this)[i];
325 void Trace(JSTracer* aTracer) {
326 for (size_t i = 0; i < ArrayLength(*this); ++i) {
327 if ((*this)[i]) {
328 JS_CallObjectTracer(aTracer, &(*this)[i], "protoAndIfaceCache[i]");
333 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
334 return aMallocSizeOf(this);
338 class PageTableCache
340 public:
341 PageTableCache() {
342 memset(&mPages, 0, sizeof(mPages));
345 ~PageTableCache() {
346 for (size_t i = 0; i < ArrayLength(mPages); ++i) {
347 delete 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];
356 if (!p) {
357 return nullptr;
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];
367 if (!p) {
368 p = new Page;
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];
379 MOZ_ASSERT(p);
380 return (*p)[leafIndex];
383 void Trace(JSTracer* trc) {
384 for (size_t i = 0; i < ArrayLength(mPages); ++i) {
385 Page* p = mPages[i];
386 if (p) {
387 for (size_t j = 0; j < ArrayLength(*p); ++j) {
388 if ((*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]);
401 return n;
404 private:
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;
412 public:
413 enum Kind {
414 WindowLike,
415 NonWindowLike
418 explicit ProtoAndIfaceCache(Kind aKind) : mKind(aKind) {
419 MOZ_COUNT_CTOR(ProtoAndIfaceCache);
420 if (aKind == WindowLike) {
421 mArrayCache = new ArrayCache();
422 } else {
423 mPageTableCache = new PageTableCache();
427 ~ProtoAndIfaceCache() {
428 if (mKind == WindowLike) {
429 delete mArrayCache;
430 } else {
431 delete mPageTableCache;
433 MOZ_COUNT_DTOR(ProtoAndIfaceCache);
436 #define FORWARD_OPERATION(opName, args) \
437 do { \
438 if (mKind == WindowLike) { \
439 return mArrayCache->opName args; \
440 } else { \
441 return mPageTableCache->opName args; \
443 } while(0)
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));
466 return n;
468 #undef FORWARD_OPERATION
470 private:
471 union {
472 ArrayCache *mArrayCache;
473 PageTableCache *mPageTableCache;
475 Kind mKind;
478 inline void
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));
490 #ifdef DEBUG
491 void
492 VerifyTraceProtoAndIfaceCacheCalled(JSTracer *trc, void **thingp,
493 JSGCTraceKind kind);
495 struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JSTracer
497 bool ok;
499 explicit VerifyTraceProtoAndIfaceCacheCalledTracer(JSRuntime *rt)
500 : JSTracer(rt, VerifyTraceProtoAndIfaceCacheCalled), ok(false)
503 #endif
505 inline void
506 TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
508 MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
510 #ifdef DEBUG
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;
515 return;
517 #endif
519 if (!HasProtoAndIfaceCache(obj))
520 return;
521 ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
522 protoAndIfaceCache->Trace(trc);
525 inline void
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.
538 bool
539 DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
540 const ConstantSpec* cs);
542 struct JSNativeHolder
544 JSNative mNative;
545 const NativePropertyHooks* mPropertyHooks;
548 struct NamedConstructor
550 const char* mName;
551 const JSNativeHolder mHolder;
552 unsigned mNargs;
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
560 * prototype object
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
565 * object.
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
568 * vice versa.
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
591 * underlying global.
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.
598 void
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.
623 bool
624 DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
625 const NativeProperties* properties,
626 const NativeProperties* chromeOnlyProperties);
629 * Define the unforgeable methods on an object.
631 bool
632 DefineUnforgeableMethods(JSContext* cx, JS::Handle<JSObject*> obj,
633 const Prefable<const JSFunctionSpec>* props);
636 * Define the unforgeable attributes on an object.
638 bool
639 DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
640 const Prefable<const JSPropertySpec>* props);
642 bool
643 DefineWebIDLBindingUnforgeablePropertiesOnXPCObject(JSContext* cx,
644 JS::Handle<JSObject*> obj,
645 const NativeProperties* properties);
647 bool
648 DefineWebIDLBindingPropertiesOnXPCObject(JSContext* cx,
649 JS::Handle<JSObject*> obj,
650 const NativeProperties* properties);
652 #ifdef _MSC_VER
653 #define HAS_MEMBER_CHECK(_name) \
654 template<typename V> static yes& Check(char (*)[(&V::_name == 0) + 1])
655 #else
656 #define HAS_MEMBER_CHECK(_name) \
657 template<typename V> static yes& Check(char (*)[sizeof(&V::_name) + 1])
658 #endif
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(...); \
668 public: \
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.
676 template<typename T>
677 struct HasWrapObject
679 private:
680 typedef char yes[1];
681 typedef char no[2];
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(...);
688 public:
689 static bool const Value = HasWrapObjectMember<T>::Value &&
690 sizeof(Check<T>(nullptr)) == sizeof(yes);
693 #ifdef DEBUG
694 template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
695 struct
696 CheckWrapperCacheCast
698 static bool Check()
700 return reinterpret_cast<uintptr_t>(
701 static_cast<nsWrapperCache*>(
702 reinterpret_cast<T*>(1))) == 1;
705 template <class T>
706 struct
707 CheckWrapperCacheCast<T, true>
709 static bool Check()
711 return true;
714 #endif
716 MOZ_ALWAYS_INLINE bool
717 CouldBeDOMBinding(void*)
719 return true;
722 MOZ_ALWAYS_INLINE bool
723 CouldBeDOMBinding(nsWrapperCache* aCache)
725 return aCache->IsDOMBinding();
728 inline bool
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);
734 if (!obj) {
735 return false;
738 rval.set(JS::ObjectValue(*obj));
741 return true;
744 // Make sure to wrap the given string value into the right compartment, as
745 // needed.
746 MOZ_ALWAYS_INLINE
747 bool
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);
755 return true;
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.
760 MOZ_ALWAYS_INLINE
761 bool
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
784 MOZ_ALWAYS_INLINE
785 bool
786 MaybeWrapObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
788 MOZ_ASSERT(rval.isObjectOrNull());
789 if (rval.isNull()) {
790 return true;
792 return MaybeWrapObjectValue(cx, rval);
795 // Wrapping for objects that are known to not be DOM or XPConnect objects
796 MOZ_ALWAYS_INLINE
797 bool
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)) {
807 return true;
809 return JS_WrapValue(cx, rval);
812 // Like MaybeWrapNonDOMObjectValue but allows null
813 MOZ_ALWAYS_INLINE
814 bool
815 MaybeWrapNonDOMObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
817 MOZ_ASSERT(rval.isObjectOrNull());
818 if (rval.isNull()) {
819 return true;
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()) {
835 return true;
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.
846 template <class T>
847 MOZ_ALWAYS_INLINE bool
848 WrapNewBindingObject(JSContext* cx, T* value, JS::MutableHandle<JS::Value> rval)
850 MOZ_ASSERT(value);
851 JSObject* obj = value->GetWrapperPreserveColor();
852 // We can get rid of this when we remove support for hasXPConnectImpls.
853 bool couldBeDOMBinding = CouldBeDOMBinding(value);
854 if (obj) {
855 JS::ExposeObjectToActiveJS(obj);
856 } else {
857 // Inline this here while we have non-dom objects in wrapper caches.
858 if (!couldBeDOMBinding) {
859 return false;
862 obj = value->WrapObject(cx);
863 if (!obj) {
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.
867 return false;
871 #ifdef DEBUG
872 const DOMJSClass* clasp = GetDOMClass(obj);
873 // clasp can be null if the cache contained a non-DOM object.
874 if (clasp) {
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());
885 #endif
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.
904 template <class T>
905 inline bool
906 WrapNewBindingNonWrapperCachedObject(JSContext* cx,
907 JS::Handle<JSObject*> scopeArg,
908 T* value,
909 JS::MutableHandle<JS::Value> rval)
911 MOZ_ASSERT(value);
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);
924 if (!scope)
925 return false;
926 ac.emplace(cx, scope);
929 MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
930 obj = value->WrapObject(cx);
933 if (!obj) {
934 return false;
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
947 template <class T>
948 inline bool
949 WrapNewBindingNonWrapperCachedOwnedObject(JSContext* cx,
950 JS::Handle<JSObject*> scopeArg,
951 nsAutoPtr<T>& value,
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.
956 if (!value) {
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);
971 if (!scope)
972 return 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);
980 if (tookOwnership) {
981 value.forget();
985 if (!obj) {
986 return false;
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>
997 inline bool
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.
1007 bool
1008 NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
1009 JS::Handle<JSObject*> aScope,
1010 JS::MutableHandle<JS::Value> aRetval,
1011 xpcObjectHelper& aHelper,
1012 const nsIID* aIID,
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.
1019 template <class T>
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)) {
1025 return false;
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.
1035 HAS_MEMBER(get)
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);
1047 template <class T>
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);
1057 template<class T>
1058 inline bool
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>
1066 inline bool
1067 EnumValueNotFound(JSContext* cx, JSString* str, const char* type,
1068 const char* sourceDescription)
1070 return false;
1073 template<>
1074 inline bool
1075 EnumValueNotFound<false>(JSContext* cx, JSString* str, const char* type,
1076 const char* sourceDescription)
1078 // TODO: Log a warning to the console.
1079 return true;
1082 template<>
1083 inline bool
1084 EnumValueNotFound<true>(JSContext* cx, JSString* str, const char* type,
1085 const char* sourceDescription)
1087 JSAutoByteString deflated(cx, str);
1088 if (!deflated) {
1089 return false;
1091 return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
1092 deflated.ptr(), type);
1095 template<typename CharT>
1096 inline int
1097 FindEnumStringIndexImpl(const CharT* chars, size_t length, const EnumEntry* values)
1099 int i = 0;
1100 for (const EnumEntry* value = values; value->value; ++value, ++i) {
1101 if (length != value->length) {
1102 continue;
1105 bool equal = true;
1106 const char* val = value->value;
1107 for (size_t j = 0; j != length; ++j) {
1108 if (unsigned(val[j]) != unsigned(chars[j])) {
1109 equal = false;
1110 break;
1114 if (equal) {
1115 return i;
1119 return -1;
1122 template<bool InvalidValueFatal>
1123 inline int
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);
1129 if (!str) {
1130 *ok = false;
1131 return 0;
1133 JS::Anchor<JSString*> anchor(str);
1136 int index;
1137 size_t length;
1138 JS::AutoCheckCannotGC nogc;
1139 if (js::StringHasLatin1Chars(str)) {
1140 const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str,
1141 &length);
1142 if (!chars) {
1143 *ok = false;
1144 return 0;
1146 index = FindEnumStringIndexImpl(chars, length, values);
1147 } else {
1148 const jschar* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, str,
1149 &length);
1150 if (!chars) {
1151 *ok = false;
1152 return 0;
1154 index = FindEnumStringIndexImpl(chars, length, values);
1156 if (index >= 0) {
1157 *ok = true;
1158 return index;
1162 *ok = EnumValueNotFound<InvalidValueFatal>(cx, str, type, sourceDescription);
1163 return -1;
1166 inline nsWrapperCache*
1167 GetWrapperCache(const ParentObject& aParentObject)
1169 return aParentObject.mWrapperCache;
1172 template<class T>
1173 inline T*
1174 GetParentPointer(T* aObject)
1176 return aObject;
1179 inline nsISupports*
1180 GetParentPointer(const ParentObject& aObject)
1182 return aObject.mObject;
1185 template <typename T>
1186 inline bool
1187 GetUseXBLScope(T* aParentObject)
1189 return false;
1192 inline bool
1193 GetUseXBLScope(const ParentObject& aParentObject)
1195 return aParentObject.mUseXBLScope;
1198 template<class T>
1199 inline void
1200 ClearWrapper(T* p, nsWrapperCache* cache)
1202 cache->ClearWrapper();
1205 template<class T>
1206 inline void
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.
1222 bool
1223 TryPreserveWrapper(JSObject* obj);
1225 // Can only be called with a DOM JSClass.
1226 bool
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.
1232 bool
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
1238 bool
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".
1246 template<class T>
1247 inline bool
1248 WrapObject(JSContext* cx, T* p, nsWrapperCache* cache, const nsIID* iid,
1249 JS::MutableHandle<JS::Value> rval)
1251 if (xpc_FastGetCachedWrapper(cx, cache, rval))
1252 return true;
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.
1260 template<>
1261 inline bool
1262 WrapObject<nsIVariant>(JSContext* cx, nsIVariant* p,
1263 nsWrapperCache* cache, const nsIID* iid,
1264 JS::MutableHandle<JS::Value> rval)
1266 MOZ_ASSERT(iid);
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".
1274 template<class T>
1275 inline bool
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.
1285 template<class T>
1286 inline bool
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
1293 template<class T>
1294 inline bool
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
1302 template<class T>
1303 inline bool
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
1311 template<class T>
1312 inline bool
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
1320 template<class T>
1321 inline bool
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.
1329 template<>
1330 inline bool
1331 WrapObject<JSObject>(JSContext* cx, JSObject* p,
1332 JS::MutableHandle<JS::Value> rval)
1334 rval.set(JS::ObjectOrNullValue(p));
1335 return true;
1338 inline bool
1339 WrapObject(JSContext* cx, JSObject& p, JS::MutableHandle<JS::Value> rval)
1341 rval.set(JS::ObjectValue(p));
1342 return true;
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() :
1358 nullptr;
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)
1368 return nullptr;
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)
1390 MOZ_ASSERT(cache);
1392 JSObject* obj;
1393 if ((obj = cache->GetWrapper())) {
1394 return obj;
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);
1400 } else {
1401 obj = parent->WrapObject(cx);
1404 return obj;
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)
1415 JSObject* obj;
1416 if (cache && (obj = cache->GetWrapper())) {
1417 #ifdef DEBUG
1418 NS_ASSERTION(WrapNativeISupportsParent(cx, parent, cache) == obj,
1419 "Unexpected object in nsWrapperCache");
1420 #endif
1421 return obj;
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)
1434 if (!p) {
1435 return JS::CurrentGlobalOrNull(cx);
1438 JSObject* parent = WrapNativeParentHelper<T>::Wrap(cx, p, cache);
1439 if (!useXBLScope) {
1440 return parent;
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)) {
1447 return 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))) {
1454 return nullptr;
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);
1494 return
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)
1505 MOZ_CRASH();
1506 return nullptr;
1510 MOZ_ALWAYS_INLINE
1511 JSObject* GetJSObjectFromCallback(CallbackObject* callback)
1513 return callback->Callback();
1516 MOZ_ALWAYS_INLINE
1517 JSObject* GetJSObjectFromCallback(void* noncallback)
1519 return nullptr;
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));
1530 if (!obj) {
1531 // WrapNativeParent is a bit of a Swiss army knife that will
1532 // wrap anything for us.
1533 obj = WrapNativeParent(cx, p);
1534 if (!obj) {
1535 return nullptr;
1539 // But all that won't necessarily put things in the compartment of cx.
1540 if (!JS_WrapObject(cx, &obj)) {
1541 return nullptr;
1544 return obj;
1548 * This specialized function simply wraps a JS::Rooted<> since
1549 * WrapNativeParent() is not applicable for JS objects.
1551 template<>
1552 inline JSObject*
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)) {
1559 return nullptr;
1562 return 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);
1577 template <class T>
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);
1587 template<class T>
1588 inline bool
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.
1597 template<class T>
1598 inline bool
1599 WrapNewBindingObject(JSContext* cx, JS::Handle<JSObject*> scope, T& value,
1600 JS::MutableHandle<JS::Value> rval)
1602 return WrapNewBindingObject(cx, value, rval);
1605 template <class T>
1606 inline JSObject*
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
1614 // that.
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());
1624 template <class T>
1625 struct GetCallbackFromCallbackObjectHelper<T, false>
1627 static inline JSObject* Get(T& aObj)
1629 return GetCallbackFromCallbackObject(&aObj);
1633 template<class T>
1634 inline JSObject*
1635 GetCallbackFromCallbackObject(T& aObj)
1637 return GetCallbackFromCallbackObjectHelper<T>::Get(aObj);
1640 static inline bool
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);
1645 return true;
1647 return false;
1650 // Spec needs a name property
1651 template <typename Spec>
1652 static bool
1653 InitIds(JSContext* cx, const Prefable<Spec>* prefableSpecs, jsid* ids)
1655 MOZ_ASSERT(prefableSpecs);
1656 MOZ_ASSERT(prefableSpecs->specs);
1657 do {
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;
1661 do {
1662 if (!InternJSString(cx, *ids, spec->name)) {
1663 return false;
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.
1669 *ids = JSID_VOID;
1670 ++ids;
1671 } while ((++prefableSpecs)->specs);
1673 return true;
1676 bool
1677 QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
1679 template <class T>
1680 struct
1681 WantsQueryInterface
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);
1691 void
1692 GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
1693 nsWrapperCache* aCache, nsIJSID* aIID,
1694 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError);
1696 template<class T>
1697 void
1698 GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID,
1699 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
1701 GetInterfaceImpl(aCx, aThis, aThis, aIID, aRetval, aError);
1704 bool
1705 UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp);
1707 bool
1708 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
1710 bool
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.
1715 bool
1716 GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
1717 JS::Handle<jsid> id, bool* found,
1718 JS::Value* vp);
1720 bool
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.
1729 bool
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.
1739 struct FakeString {
1740 FakeString() :
1741 mFlags(nsString::F_TERMINATED)
1745 ~FakeString() {
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);
1754 mLength = aLength;
1757 void Truncate() {
1758 MOZ_ASSERT(mFlags == nsString::F_TERMINATED);
1759 mData = nsString::char_traits::sEmptyBuffer;
1760 mLength = 0;
1763 void SetIsVoid(bool aValue) {
1764 MOZ_ASSERT(aValue,
1765 "We don't support SetIsVoid(false) on FakeString!");
1766 Truncate();
1767 mFlags |= nsString::F_VOIDED;
1770 const nsString::char_type* Data() const
1772 return mData;
1775 nsString::char_type* BeginWriting()
1777 return mData;
1780 nsString::size_type Length() const
1782 return mLength;
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);
1790 } else {
1791 nsStringBuffer *buf = nsStringBuffer::Alloc((aLength + 1) * sizeof(nsString::char_type)).take();
1792 if (MOZ_UNLIKELY(!buf)) {
1793 return false;
1796 SetData(static_cast<nsString::char_type*>(buf->Data()));
1797 mFlags = nsString::F_SHARED | nsString::F_TERMINATED;
1799 mLength = aLength;
1800 mData[mLength] = char16_t(0);
1801 return true;
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);
1818 private:
1819 nsString::char_type* mData;
1820 nsString::size_type mLength;
1821 uint32_t mFlags;
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 {
1840 public:
1841 static void StaticAsserts() {
1842 static_assert(offsetof(FakeString, mInlineStorage) ==
1843 sizeof(nsString),
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 {
1861 eStringify,
1862 eEmpty,
1863 eNull
1866 template<typename T>
1867 static inline bool
1868 ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
1869 StringificationBehavior nullBehavior,
1870 StringificationBehavior undefinedBehavior,
1871 T& result)
1873 JSString *s;
1874 if (v.isString()) {
1875 s = v.toString();
1876 } else {
1877 StringificationBehavior behavior;
1878 if (v.isNull()) {
1879 behavior = nullBehavior;
1880 } else if (v.isUndefined()) {
1881 behavior = undefinedBehavior;
1882 } else {
1883 behavior = eStringify;
1886 if (behavior != eStringify) {
1887 if (behavior == eEmpty) {
1888 result.Truncate();
1889 } else {
1890 result.SetIsVoid(true);
1892 return true;
1895 s = JS::ToString(cx, v);
1896 if (!s) {
1897 return false;
1901 return AssignJSString(cx, result, s);
1904 void
1905 NormalizeScalarValueString(JSContext* aCx, nsAString& aString);
1907 void
1908 NormalizeScalarValueString(JSContext* aCx, binding_detail::FakeString& aString);
1910 template<typename T>
1911 inline bool
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))) {
1916 return false;
1918 } else if (JSID_IS_SYMBOL(id)) {
1919 isSymbol = true;
1920 return true;
1921 } else {
1922 JS::RootedValue nameVal(cx, js::IdToValue(id));
1923 if (!ConvertJSValueToString(cx, nameVal, eStringify, eStringify, result)) {
1924 return false;
1927 isSymbol = false;
1928 return true;
1931 bool
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>
1946 public:
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
1959 // sequence types.
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?>
1970 template<>
1971 class SequenceTracer<JSObject*, false, false, false>
1973 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1975 public:
1976 static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
1977 for (; objp != end; ++objp) {
1978 JS_CallUnbarrieredObjectTracer(trc, objp, "sequence<object>");
1983 // sequence<any>
1984 template<>
1985 class SequenceTracer<JS::Value, false, false, false>
1987 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1989 public:
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
2003 public:
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
2017 public:
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
2031 public:
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
2045 public:
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
2059 public:
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
2073 public:
2074 static void TraceSequence(JSTracer* trc, Nullable<T>* seqp,
2075 Nullable<T>* end) {
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();
2081 T* ptr = &val;
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);
2107 // sequence<MozMap>
2108 template<typename T>
2109 class SequenceTracer<MozMap<T>, false, false, false>
2111 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
2113 public:
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
2139 public:
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)
2164 private:
2165 enum SequenceType {
2166 eInfallibleArray,
2167 eFallibleArray,
2168 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);
2177 } else {
2178 MOZ_ASSERT(mSequenceType == eNullableArray);
2179 if (!mNullableArray->IsNull()) {
2180 DoTraceSequence(trc, mNullableArray->Value());
2185 union {
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
2198 public:
2199 MozMapRooter(JSContext *aCx, MozMap<T>* aMozMap
2200 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2201 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2202 mMozMap(aMozMap),
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)
2215 private:
2216 enum MozMapType {
2217 eMozMap,
2218 eNullableMozMap
2221 virtual void trace(JSTracer *trc) MOZ_OVERRIDE
2223 if (mMozMapType == eMozMap) {
2224 TraceMozMap(trc, *mMozMap);
2225 } else {
2226 MOZ_ASSERT(mMozMapType == eNullableMozMap);
2227 if (!mNullableMozMap->IsNull()) {
2228 TraceMozMap(trc, mNullableMozMap->Value());
2233 union {
2234 MozMap<T>* mMozMap;
2235 Nullable<MozMap<T>>* mNullableMozMap;
2238 MozMapType mMozMapType;
2241 template<typename T>
2242 class MOZ_STACK_CLASS RootedUnion : public T,
2243 private JS::CustomAutoRooter
2245 public:
2246 explicit RootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
2247 T(),
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
2262 public:
2263 explicit NullableRootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
2264 Nullable<T>(),
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);
2277 inline bool
2278 IdEquals(jsid id, const char* string)
2280 return JSID_IS_STRING(id) &&
2281 JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
2284 inline bool
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.
2300 bool
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.
2314 bool
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.
2328 bool
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.
2342 bool
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
2354 // JSNativeHolder.
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.
2358 enum {
2359 CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT = 0
2362 bool
2363 Constructor(JSContext* cx, unsigned argc, JS::Value* vp);
2365 inline bool
2366 UseDOMXray(JSObject* obj)
2368 const js::Class* clasp = js::GetObjectClass(obj);
2369 return IsDOMClass(clasp) ||
2370 JS_IsNativeFunction(obj, Constructor) ||
2371 IsDOMIfaceAndProtoClass(clasp);
2374 #ifdef DEBUG
2375 inline bool
2376 HasConstructor(JSObject* obj)
2378 return JS_IsNativeFunction(obj, Constructor) ||
2379 js::GetObjectClass(obj)->construct;
2381 #endif
2383 // Transfer reference in ptr to smartPtr.
2384 template<class T>
2385 inline void
2386 Take(nsRefPtr<T>& smartPtr, T* ptr)
2388 smartPtr = dont_AddRef(ptr);
2391 // Transfer ownership of ptr to smartPtr.
2392 template<class T>
2393 inline void
2394 Take(nsAutoPtr<T>& smartPtr, T* ptr)
2396 smartPtr = ptr;
2399 inline void
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.
2416 bool
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)
2431 template<class T>
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)
2444 return arg;
2447 // Helper for turning (Owning)NonNull<T> into T&
2448 template<typename T>
2449 T& NonNullHelper(T& aArg)
2451 return aArg;
2454 template<typename T>
2455 T& NonNullHelper(NonNull<T>& aArg)
2457 return aArg;
2460 template<typename T>
2461 const T& NonNullHelper(const NonNull<T>& aArg)
2463 return aArg;
2466 template<typename T>
2467 T& NonNullHelper(OwningNonNull<T>& aArg)
2469 return aArg;
2472 template<typename T>
2473 const T& NonNullHelper(const OwningNonNull<T>& aArg)
2475 return aArg;
2478 inline
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.
2487 inline
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.
2496 inline
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.
2505 MOZ_ALWAYS_INLINE
2506 const nsAString& NonNullHelper(const binding_detail::FakeString& aArg)
2508 return aArg;
2511 // Reparent the wrapper of aObj to whatever its native now thinks its
2512 // parent should be.
2513 nsresult
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.
2521 bool
2522 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
2523 JS::Handle<JSObject*> instance,
2524 bool* bp);
2525 bool
2526 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp,
2527 bool* bp);
2528 bool
2529 InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
2530 JS::Handle<JSObject*> instance,
2531 bool* bp);
2533 // Helper for lenient getters/setters to report to console. If this
2534 // returns false, we couldn't even get a global.
2535 bool
2536 ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj);
2538 inline JSObject*
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.
2550 bool
2551 GetWindowForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
2552 nsPIDOMWindow** window);
2554 void
2555 ConstructJSImplementation(JSContext* aCx, const char* aContractId,
2556 nsPIDOMWindow* aWindow,
2557 JS::MutableHandle<JSObject*> aObject,
2558 ErrorResult& aRv);
2560 already_AddRefed<nsPIDOMWindow>
2561 ConstructJSImplementation(JSContext* aCx, const char* aContractId,
2562 const GlobalObject& aGlobal,
2563 JS::MutableHandle<JSObject*> aObject,
2564 ErrorResult& aRv);
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)
2577 if (str.IsVoid()) {
2578 rval.setNull();
2579 return true;
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));
2593 template<class T>
2594 struct PreserveWrapperHelper<T, true>
2596 static void PreserveWrapper(T* aObject)
2598 aObject->PreserveWrapper(reinterpret_cast<nsISupports*>(aObject));
2602 template<class T>
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*)
2613 return true;
2615 static bool ToSupportsIsOnPrimaryInheritanceChain(T*, nsWrapperCache*)
2617 return true;
2621 template<class T>
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;
2635 template<class T>
2636 bool
2637 ToSupportsIsCorrect(T* aObject)
2639 return CastingAssertions<T>::ToSupportsIsCorrect(aObject);
2642 template<class T>
2643 bool
2644 ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache)
2646 return CastingAssertions<T>::ToSupportsIsOnPrimaryInheritanceChain(aObject,
2647 aCache);
2650 template<class T, template <typename> class SmartPtr,
2651 bool isISupports=IsBaseOf<nsISupports, T>::value>
2652 class DeferredFinalizer
2654 typedef nsTArray<SmartPtr<T> > SmartPtrArray;
2656 static void*
2657 AppendDeferredFinalizePointer(void* aData, void* aObject)
2659 SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
2660 if (!pointers) {
2661 pointers = new SmartPtrArray();
2664 T* self = static_cast<T*>(aObject);
2666 SmartPtr<T>* defer = pointers->AppendElement();
2667 Take(*defer, self);
2668 return pointers;
2670 static bool
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) {
2677 aSlice = oldLen;
2679 uint32_t newLen = oldLen - aSlice;
2680 pointers->RemoveElementsAt(newLen, aSlice);
2681 if (newLen == 0) {
2682 delete pointers;
2683 return true;
2685 return false;
2688 public:
2689 static void
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>
2700 public:
2701 static void
2702 AddForDeferredFinalization(T* aObject)
2704 cyclecollector::DeferredFinalize(reinterpret_cast<nsISupports*>(aObject));
2708 template<class T, template <typename> class SmartPtr>
2709 static void
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.
2722 template<class U>
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.
2729 template<class U>
2730 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2731 GetHelper(double)
2733 return nullptr;
2736 public:
2737 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2738 Get()
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());
2748 template<class T>
2749 class GetCCParticipant<T, true>
2751 public:
2752 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2753 Get()
2755 return nullptr;
2760 * Helper function for testing whether the given object comes from a
2761 * privileged app.
2763 bool
2764 IsInPrivilegedApp(JSContext* aCx, JSObject* aObj);
2767 * Helper function for testing whether the given object comes from a
2768 * certified app.
2770 bool
2771 IsInCertifiedApp(JSContext* aCx, JSObject* aObj);
2773 void
2774 FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
2776 bool
2777 ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
2778 JS::Handle<jsid> aId, JS::MutableHandle<JSObject*> aObjp);
2780 bool
2781 EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj);
2783 template <class T>
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,
2789 // see bug 934889.
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));
2799 return true;
2803 template <>
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);
2813 nsresult
2814 RegisterDOMNames();
2816 template <class T, ProtoGetter GetProto>
2817 bool
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));
2827 if (!aGlobal) {
2828 NS_WARNING("Failed to create global");
2829 return false;
2832 JSAutoCompartment ac(aCx, aGlobal);
2835 js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aNative));
2836 NS_ADDREF(aNative);
2838 aCache->SetIsDOMBinding();
2839 aCache->SetWrapper(aGlobal);
2841 dom::AllocateProtoAndIfaceCache(aGlobal,
2842 CreateGlobalOptions<T>::ProtoAndIfaceCacheKind);
2844 if (!CreateGlobalOptions<T>::PostCreateGlobal(aCx, aGlobal)) {
2845 return false;
2849 if (aInitStandardClasses &&
2850 !CreateGlobalOptions<T>::ForceInitStandardClassesToFalse &&
2851 !JS_InitStandardClasses(aCx, aGlobal)) {
2852 NS_WARNING("Failed to init standard classes");
2853 return false;
2856 JS::Handle<JSObject*> proto = GetProto(aCx, aGlobal);
2857 if (!proto || !JS_SplicePrototype(aCx, aGlobal, proto)) {
2858 NS_WARNING("Failed to set proto");
2859 return false;
2862 return true;
2866 * Holds a jsid that is initialized to an interned string, with conversion to
2867 * Handle<jsid>.
2869 class InternedStringId
2871 jsid id;
2873 public:
2874 InternedStringId() : id(JSID_VOID) {}
2876 bool init(JSContext *cx, const char *string) {
2877 JSString* str = JS_InternString(cx, string);
2878 if (!str)
2879 return false;
2880 id = INTERNED_STRING_TO_JSID(cx, str);
2881 return true;
2884 operator const jsid& () {
2885 return id;
2888 operator JS::Handle<jsid> () {
2889 /* This is safe because we have interned the string. */
2890 return JS::Handle<jsid>::fromMarkedLocation(&id);
2894 bool
2895 GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp);
2897 bool
2898 GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp);
2900 bool
2901 GenericBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp);
2903 bool
2904 GenericPromiseReturningBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp);
2906 bool
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
2914 // rval.
2916 // promiseScope should be the scope in which the Promise should be created.
2917 bool
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.
2925 inline bool
2926 GlobalPropertiesAreOwn()
2928 return true;
2931 #ifdef DEBUG
2932 void
2933 AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
2934 JS::Handle<JS::Value> aValue);
2935 #endif
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.
2939 bool
2940 CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
2942 //Returns true if page is being prerendered.
2943 bool
2944 CheckSafetyInPrerendering(JSContext* aCx, JSObject* aObj);
2946 bool
2947 CallerSubsumes(JSObject* aObject);
2949 MOZ_ALWAYS_INLINE bool
2950 CallerSubsumes(JS::Handle<JS::Value> aValue)
2952 if (!aValue.isObject()) {
2953 return true;
2955 return CallerSubsumes(&aValue.toObject());
2958 template<class T>
2959 inline bool
2960 WrappedJSToDictionary(nsISupports* aObject, T& aDictionary)
2962 nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
2963 if (!wrappedObj) {
2964 return false;
2967 AutoJSAPI jsapi;
2968 jsapi.Init();
2970 JSContext* cx = jsapi.cx();
2971 JS::Rooted<JSObject*> obj(cx, wrappedObj->GetJSObject());
2972 if (!obj) {
2973 return false;
2976 JSAutoCompartment ac(cx, obj);
2977 JS::Rooted<JS::Value> v(cx, OBJECT_TO_JSVAL(obj));
2978 return aDictionary.Init(cx, v);
2981 } // namespace dom
2982 } // namespace mozilla
2984 #endif /* mozilla_dom_BindingUtils_h__ */