Bumping manifests a=b2g-bump
[gecko.git] / dom / bindings / BindingUtils.h
blobcc80ade1a42a9c77d522b0254ce3dc37148057d4
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 "mozilla/CycleCollectedJSRuntime.h"
29 #include "nsCycleCollector.h"
30 #include "nsIXPConnect.h"
31 #include "nsJSUtils.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 namespace mozilla {
44 namespace dom {
45 template<typename DataType> class MozMap;
47 struct SelfRef
49 SelfRef() : ptr(nullptr) {}
50 explicit SelfRef(nsISupports *p) : ptr(p) {}
51 ~SelfRef() { NS_IF_RELEASE(ptr); }
53 nsISupports* ptr;
56 nsresult
57 UnwrapArgImpl(JS::Handle<JSObject*> src, const nsIID& iid, void** ppArg);
59 /** Convert a jsval to an XPCOM pointer. */
60 template <class Interface>
61 inline nsresult
62 UnwrapArg(JS::Handle<JSObject*> src, Interface** ppArg)
64 return UnwrapArgImpl(src, NS_GET_TEMPLATE_IID(Interface),
65 reinterpret_cast<void**>(ppArg));
68 inline const ErrNum
69 GetInvalidThisErrorForMethod(bool aSecurityError)
71 return aSecurityError ? MSG_METHOD_THIS_UNWRAPPING_DENIED :
72 MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
75 inline const ErrNum
76 GetInvalidThisErrorForGetter(bool aSecurityError)
78 return aSecurityError ? MSG_GETTER_THIS_UNWRAPPING_DENIED :
79 MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
82 inline const ErrNum
83 GetInvalidThisErrorForSetter(bool aSecurityError)
85 return aSecurityError ? MSG_SETTER_THIS_UNWRAPPING_DENIED :
86 MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
89 bool
90 ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
91 const ErrNum aErrorNumber,
92 const char* aInterfaceName);
94 bool
95 ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
96 const ErrNum aErrorNumber,
97 prototypes::ID aProtoId);
99 inline bool
100 ThrowMethodFailedWithDetails(JSContext* cx, ErrorResult& rv,
101 const char* ifaceName,
102 const char* memberName,
103 bool reportJSContentExceptions = false)
105 if (rv.IsTypeError()) {
106 rv.ReportTypeError(cx);
107 return false;
109 if (rv.IsJSException()) {
110 if (reportJSContentExceptions) {
111 rv.ReportJSExceptionFromJSImplementation(cx);
112 } else {
113 rv.ReportJSException(cx);
115 return false;
117 if (rv.IsNotEnoughArgsError()) {
118 rv.ReportNotEnoughArgsError(cx, ifaceName, memberName);
119 return false;
121 return Throw(cx, rv.ErrorCode());
124 // Returns true if the JSClass is used for DOM objects.
125 inline bool
126 IsDOMClass(const JSClass* clasp)
128 return clasp->flags & JSCLASS_IS_DOMJSCLASS;
131 inline bool
132 IsDOMClass(const js::Class* clasp)
134 return IsDOMClass(Jsvalify(clasp));
137 // Return true if the JSClass is used for non-proxy DOM objects.
138 inline bool
139 IsNonProxyDOMClass(const js::Class* clasp)
141 return IsDOMClass(clasp) && !clasp->isProxy();
144 inline bool
145 IsNonProxyDOMClass(const JSClass* clasp)
147 return IsNonProxyDOMClass(js::Valueify(clasp));
150 // Returns true if the JSClass is used for DOM interface and interface
151 // prototype objects.
152 inline bool
153 IsDOMIfaceAndProtoClass(const JSClass* clasp)
155 return clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS;
158 inline bool
159 IsDOMIfaceAndProtoClass(const js::Class* clasp)
161 return IsDOMIfaceAndProtoClass(Jsvalify(clasp));
164 static_assert(DOM_OBJECT_SLOT == 0,
165 "DOM_OBJECT_SLOT doesn't match the proxy private slot. "
166 "Expect bad things");
167 template <class T>
168 inline T*
169 UnwrapDOMObject(JSObject* obj)
171 MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
172 "Don't pass non-DOM objects to this function");
174 JS::Value val = js::GetReservedOrProxyPrivateSlot(obj, DOM_OBJECT_SLOT);
175 return static_cast<T*>(val.toPrivate());
178 template <class T>
179 inline T*
180 UnwrapPossiblyNotInitializedDOMObject(JSObject* obj)
182 // This is used by the OjectMoved JSClass hook which can be called before
183 // JS_NewObject has returned and so before we have a chance to set
184 // DOM_OBJECT_SLOT to anything useful.
186 MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
187 "Don't pass non-DOM objects to this function");
189 JS::Value val = js::GetReservedOrProxyPrivateSlot(obj, DOM_OBJECT_SLOT);
190 if (val.isUndefined()) {
191 return nullptr;
193 return static_cast<T*>(val.toPrivate());
196 inline const DOMJSClass*
197 GetDOMClass(const js::Class* clasp)
199 return IsDOMClass(clasp) ? DOMJSClass::FromJSClass(clasp) : nullptr;
202 inline const DOMJSClass*
203 GetDOMClass(JSObject* obj)
205 return GetDOMClass(js::GetObjectClass(obj));
208 inline nsISupports*
209 UnwrapDOMObjectToISupports(JSObject* aObject)
211 const DOMJSClass* clasp = GetDOMClass(aObject);
212 if (!clasp || !clasp->mDOMObjectIsISupports) {
213 return nullptr;
216 return UnwrapDOMObject<nsISupports>(aObject);
219 inline bool
220 IsDOMObject(JSObject* obj)
222 return IsDOMClass(js::GetObjectClass(obj));
225 #define UNWRAP_OBJECT(Interface, obj, value) \
226 mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface, \
227 mozilla::dom::Interface##Binding::NativeType>(obj, value)
229 // Some callers don't want to set an exception when unwrapping fails
230 // (for example, overload resolution uses unwrapping to tell what sort
231 // of thing it's looking at).
232 // U must be something that a T* can be assigned to (e.g. T* or an nsRefPtr<T>).
233 template <class T, typename U>
234 MOZ_ALWAYS_INLINE nsresult
235 UnwrapObject(JSObject* obj, U& value, prototypes::ID protoID,
236 uint32_t protoDepth)
238 /* First check to see whether we have a DOM object */
239 const DOMJSClass* domClass = GetDOMClass(obj);
240 if (!domClass) {
241 /* Maybe we have a security wrapper or outer window? */
242 if (!js::IsWrapper(obj)) {
243 /* Not a DOM object, not a wrapper, just bail */
244 return NS_ERROR_XPC_BAD_CONVERT_JS;
247 obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
248 if (!obj) {
249 return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
251 MOZ_ASSERT(!js::IsWrapper(obj));
252 domClass = GetDOMClass(obj);
253 if (!domClass) {
254 /* We don't have a DOM object */
255 return NS_ERROR_XPC_BAD_CONVERT_JS;
259 /* This object is a DOM object. Double-check that it is safely
260 castable to T by checking whether it claims to inherit from the
261 class identified by protoID. */
262 if (domClass->mInterfaceChain[protoDepth] == protoID) {
263 value = UnwrapDOMObject<T>(obj);
264 return NS_OK;
267 /* It's the wrong sort of DOM object */
268 return NS_ERROR_XPC_BAD_CONVERT_JS;
271 template <prototypes::ID PrototypeID, class T, typename U>
272 MOZ_ALWAYS_INLINE nsresult
273 UnwrapObject(JSObject* obj, U& value)
275 return UnwrapObject<T>(obj, value, PrototypeID,
276 PrototypeTraits<PrototypeID>::Depth);
279 inline bool
280 IsNotDateOrRegExp(JSContext* cx, JS::Handle<JSObject*> obj)
282 MOZ_ASSERT(obj);
283 return !JS_ObjectIsDate(cx, obj) && !JS_ObjectIsRegExp(cx, obj);
286 MOZ_ALWAYS_INLINE bool
287 IsObjectValueConvertibleToDictionary(JSContext* cx,
288 JS::Handle<JS::Value> objVal)
290 JS::Rooted<JSObject*> obj(cx, &objVal.toObject());
291 return IsNotDateOrRegExp(cx, obj);
294 MOZ_ALWAYS_INLINE bool
295 IsConvertibleToDictionary(JSContext* cx, JS::Handle<JS::Value> val)
297 return val.isNullOrUndefined() ||
298 (val.isObject() && IsObjectValueConvertibleToDictionary(cx, val));
301 MOZ_ALWAYS_INLINE bool
302 IsConvertibleToCallbackInterface(JSContext* cx, JS::Handle<JSObject*> obj)
304 return IsNotDateOrRegExp(cx, obj);
307 // The items in the protoAndIfaceCache are indexed by the prototypes::id::ID,
308 // constructors::id::ID and namedpropertiesobjects::id::ID enums, in that order.
309 // The end of the prototype objects should be the start of the interface
310 // objects, and the end of the interface objects should be the start of the
311 // named properties objects.
312 static_assert((size_t)constructors::id::_ID_Start ==
313 (size_t)prototypes::id::_ID_Count &&
314 (size_t)namedpropertiesobjects::id::_ID_Start ==
315 (size_t)constructors::id::_ID_Count,
316 "Overlapping or discontiguous indexes.");
317 const size_t kProtoAndIfaceCacheCount = namedpropertiesobjects::id::_ID_Count;
319 class ProtoAndIfaceCache
321 // The caching strategy we use depends on what sort of global we're dealing
322 // with. For a window-like global, we want everything to be as fast as
323 // possible, so we use a flat array, indexed by prototype/constructor ID.
324 // For everything else (e.g. globals for JSMs), space is more important than
325 // speed, so we use a two-level lookup table.
327 class ArrayCache : public Array<JS::Heap<JSObject*>, kProtoAndIfaceCacheCount>
329 public:
330 JSObject* EntrySlotIfExists(size_t i) {
331 return (*this)[i];
334 JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
335 return (*this)[i];
338 JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
339 MOZ_ASSERT((*this)[i]);
340 return (*this)[i];
343 void Trace(JSTracer* aTracer) {
344 for (size_t i = 0; i < ArrayLength(*this); ++i) {
345 if ((*this)[i]) {
346 JS_CallObjectTracer(aTracer, &(*this)[i], "protoAndIfaceCache[i]");
351 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
352 return aMallocSizeOf(this);
356 class PageTableCache
358 public:
359 PageTableCache() {
360 memset(&mPages, 0, sizeof(mPages));
363 ~PageTableCache() {
364 for (size_t i = 0; i < ArrayLength(mPages); ++i) {
365 delete mPages[i];
369 JSObject* EntrySlotIfExists(size_t i) {
370 MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
371 size_t pageIndex = i / kPageSize;
372 size_t leafIndex = i % kPageSize;
373 Page* p = mPages[pageIndex];
374 if (!p) {
375 return nullptr;
377 return (*p)[leafIndex];
380 JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
381 MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
382 size_t pageIndex = i / kPageSize;
383 size_t leafIndex = i % kPageSize;
384 Page* p = mPages[pageIndex];
385 if (!p) {
386 p = new Page;
387 mPages[pageIndex] = p;
389 return (*p)[leafIndex];
392 JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
393 MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
394 size_t pageIndex = i / kPageSize;
395 size_t leafIndex = i % kPageSize;
396 Page* p = mPages[pageIndex];
397 MOZ_ASSERT(p);
398 return (*p)[leafIndex];
401 void Trace(JSTracer* trc) {
402 for (size_t i = 0; i < ArrayLength(mPages); ++i) {
403 Page* p = mPages[i];
404 if (p) {
405 for (size_t j = 0; j < ArrayLength(*p); ++j) {
406 if ((*p)[j]) {
407 JS_CallObjectTracer(trc, &(*p)[j], "protoAndIfaceCache[i]");
414 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
415 size_t n = aMallocSizeOf(this);
416 for (size_t i = 0; i < ArrayLength(mPages); ++i) {
417 n += aMallocSizeOf(mPages[i]);
419 return n;
422 private:
423 static const size_t kPageSize = 16;
424 typedef Array<JS::Heap<JSObject*>, kPageSize> Page;
425 static const size_t kNPages = kProtoAndIfaceCacheCount / kPageSize +
426 size_t(bool(kProtoAndIfaceCacheCount % kPageSize));
427 Array<Page*, kNPages> mPages;
430 public:
431 enum Kind {
432 WindowLike,
433 NonWindowLike
436 explicit ProtoAndIfaceCache(Kind aKind) : mKind(aKind) {
437 MOZ_COUNT_CTOR(ProtoAndIfaceCache);
438 if (aKind == WindowLike) {
439 mArrayCache = new ArrayCache();
440 } else {
441 mPageTableCache = new PageTableCache();
445 ~ProtoAndIfaceCache() {
446 if (mKind == WindowLike) {
447 delete mArrayCache;
448 } else {
449 delete mPageTableCache;
451 MOZ_COUNT_DTOR(ProtoAndIfaceCache);
454 #define FORWARD_OPERATION(opName, args) \
455 do { \
456 if (mKind == WindowLike) { \
457 return mArrayCache->opName args; \
458 } else { \
459 return mPageTableCache->opName args; \
461 } while(0)
463 JSObject* EntrySlotIfExists(size_t i) {
464 FORWARD_OPERATION(EntrySlotIfExists, (i));
467 JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
468 FORWARD_OPERATION(EntrySlotOrCreate, (i));
471 JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
472 FORWARD_OPERATION(EntrySlotMustExist, (i));
475 void Trace(JSTracer *aTracer) {
476 FORWARD_OPERATION(Trace, (aTracer));
479 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
480 size_t n = aMallocSizeOf(this);
481 n += (mKind == WindowLike
482 ? mArrayCache->SizeOfIncludingThis(aMallocSizeOf)
483 : mPageTableCache->SizeOfIncludingThis(aMallocSizeOf));
484 return n;
486 #undef FORWARD_OPERATION
488 private:
489 union {
490 ArrayCache *mArrayCache;
491 PageTableCache *mPageTableCache;
493 Kind mKind;
496 inline void
497 AllocateProtoAndIfaceCache(JSObject* obj, ProtoAndIfaceCache::Kind aKind)
499 MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
500 MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
502 ProtoAndIfaceCache* protoAndIfaceCache = new ProtoAndIfaceCache(aKind);
504 js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
505 JS::PrivateValue(protoAndIfaceCache));
508 #ifdef DEBUG
509 void
510 VerifyTraceProtoAndIfaceCacheCalled(JSTracer *trc, void **thingp,
511 JSGCTraceKind kind);
513 struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JSTracer
515 bool ok;
517 explicit VerifyTraceProtoAndIfaceCacheCalledTracer(JSRuntime *rt)
518 : JSTracer(rt, VerifyTraceProtoAndIfaceCacheCalled), ok(false)
521 #endif
523 inline void
524 TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
526 MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
528 #ifdef DEBUG
529 if (trc->callback == VerifyTraceProtoAndIfaceCacheCalled) {
530 // We don't do anything here, we only want to verify that
531 // TraceProtoAndIfaceCache was called.
532 static_cast<VerifyTraceProtoAndIfaceCacheCalledTracer*>(trc)->ok = true;
533 return;
535 #endif
537 if (!HasProtoAndIfaceCache(obj))
538 return;
539 ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
540 protoAndIfaceCache->Trace(trc);
543 inline void
544 DestroyProtoAndIfaceCache(JSObject* obj)
546 MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
548 ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
550 delete protoAndIfaceCache;
554 * Add constants to an object.
556 bool
557 DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
558 const ConstantSpec* cs);
560 struct JSNativeHolder
562 JSNative mNative;
563 const NativePropertyHooks* mPropertyHooks;
566 struct NamedConstructor
568 const char* mName;
569 const JSNativeHolder mHolder;
570 unsigned mNargs;
574 * Create a DOM interface object (if constructorClass is non-null) and/or a
575 * DOM interface prototype object (if protoClass is non-null).
577 * global is used as the parent of the interface object and the interface
578 * prototype object
579 * protoProto is the prototype to use for the interface prototype object.
580 * interfaceProto is the prototype to use for the interface object.
581 * protoClass is the JSClass to use for the interface prototype object.
582 * This is null if we should not create an interface prototype
583 * object.
584 * protoCache a pointer to a JSObject pointer where we should cache the
585 * interface prototype object. This must be null if protoClass is and
586 * vice versa.
587 * constructorClass is the JSClass to use for the interface object.
588 * This is null if we should not create an interface object or
589 * if it should be a function object.
590 * constructor holds the JSNative to back the interface object which should be a
591 * Function, unless constructorClass is non-null in which case it is
592 * ignored. If this is null and constructorClass is also null then
593 * we should not create an interface object at all.
594 * ctorNargs is the length of the constructor function; 0 if no constructor
595 * constructorCache a pointer to a JSObject pointer where we should cache the
596 * interface object. This must be null if both constructorClass
597 * and constructor are null, and non-null otherwise.
598 * properties contains the methods, attributes and constants to be defined on
599 * objects in any compartment.
600 * chromeProperties contains the methods, attributes and constants to be defined
601 * on objects in chrome compartments. This must be null if the
602 * interface doesn't have any ChromeOnly properties or if the
603 * object is being created in non-chrome compartment.
604 * defineOnGlobal controls whether properties should be defined on the given
605 * global for the interface object (if any) and named
606 * constructors (if any) for this interface. This can be
607 * false in situations where we want the properties to only
608 * appear on privileged Xrays but not on the unprivileged
609 * underlying global.
611 * At least one of protoClass, constructorClass or constructor should be
612 * non-null. If constructorClass or constructor are non-null, the resulting
613 * interface object will be defined on the given global with property name
614 * |name|, which must also be non-null.
616 void
617 CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
618 JS::Handle<JSObject*> protoProto,
619 const js::Class* protoClass, JS::Heap<JSObject*>* protoCache,
620 JS::Handle<JSObject*> interfaceProto,
621 const js::Class* constructorClass, const JSNativeHolder* constructor,
622 unsigned ctorNargs, const NamedConstructor* namedConstructors,
623 JS::Heap<JSObject*>* constructorCache,
624 const NativeProperties* regularProperties,
625 const NativeProperties* chromeOnlyProperties,
626 const char* name, bool defineOnGlobal);
629 * Define the properties (regular and chrome-only) on obj.
631 * obj the object to instal the properties on. This should be the interface
632 * prototype object for regular interfaces and the instance object for
633 * interfaces marked with Global.
634 * properties contains the methods, attributes and constants to be defined on
635 * objects in any compartment.
636 * chromeProperties contains the methods, attributes and constants to be defined
637 * on objects in chrome compartments. This must be null if the
638 * interface doesn't have any ChromeOnly properties or if the
639 * object is being created in non-chrome compartment.
641 bool
642 DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
643 const NativeProperties* properties,
644 const NativeProperties* chromeOnlyProperties);
647 * Define the unforgeable methods on an object.
649 bool
650 DefineUnforgeableMethods(JSContext* cx, JS::Handle<JSObject*> obj,
651 const Prefable<const JSFunctionSpec>* props);
654 * Define the unforgeable attributes on an object.
656 bool
657 DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
658 const Prefable<const JSPropertySpec>* props);
660 bool
661 DefineWebIDLBindingUnforgeablePropertiesOnXPCObject(JSContext* cx,
662 JS::Handle<JSObject*> obj,
663 const NativeProperties* properties);
665 bool
666 DefineWebIDLBindingPropertiesOnXPCObject(JSContext* cx,
667 JS::Handle<JSObject*> obj,
668 const NativeProperties* properties);
670 #ifdef _MSC_VER
671 #define HAS_MEMBER_CHECK(_name) \
672 template<typename V> static yes& Check(char (*)[(&V::_name == 0) + 1])
673 #else
674 #define HAS_MEMBER_CHECK(_name) \
675 template<typename V> static yes& Check(char (*)[sizeof(&V::_name) + 1])
676 #endif
678 #define HAS_MEMBER(_name) \
679 template<typename T> \
680 class Has##_name##Member { \
681 typedef char yes[1]; \
682 typedef char no[2]; \
683 HAS_MEMBER_CHECK(_name); \
684 template<typename V> static no& Check(...); \
686 public: \
687 static bool const Value = sizeof(Check<T>(nullptr)) == sizeof(yes); \
690 HAS_MEMBER(WrapObject)
692 // HasWrapObject<T>::Value will be true if T has a WrapObject member but it's
693 // not nsWrapperCache::WrapObject.
694 template<typename T>
695 struct HasWrapObject
697 private:
698 typedef char yes[1];
699 typedef char no[2];
700 typedef JSObject* (nsWrapperCache::*WrapObject)(JSContext*,
701 JS::Handle<JSObject*>);
702 template<typename U, U> struct SFINAE;
703 template <typename V> static no& Check(SFINAE<WrapObject, &V::WrapObject>*);
704 template <typename V> static yes& Check(...);
706 public:
707 static bool const Value = HasWrapObjectMember<T>::Value &&
708 sizeof(Check<T>(nullptr)) == sizeof(yes);
711 #ifdef DEBUG
712 template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
713 struct
714 CheckWrapperCacheCast
716 static bool Check()
718 return reinterpret_cast<uintptr_t>(
719 static_cast<nsWrapperCache*>(
720 reinterpret_cast<T*>(1))) == 1;
723 template <class T>
724 struct
725 CheckWrapperCacheCast<T, true>
727 static bool Check()
729 return true;
732 #endif
734 MOZ_ALWAYS_INLINE bool
735 CouldBeDOMBinding(void*)
737 return true;
740 MOZ_ALWAYS_INLINE bool
741 CouldBeDOMBinding(nsWrapperCache* aCache)
743 return aCache->IsDOMBinding();
746 inline bool
747 TryToOuterize(JSContext* cx, JS::MutableHandle<JS::Value> rval)
749 if (js::IsInnerObject(&rval.toObject())) {
750 JS::Rooted<JSObject*> obj(cx, &rval.toObject());
751 obj = JS_ObjectToOuterObject(cx, obj);
752 if (!obj) {
753 return false;
756 rval.set(JS::ObjectValue(*obj));
759 return true;
762 // Make sure to wrap the given string value into the right compartment, as
763 // needed.
764 MOZ_ALWAYS_INLINE
765 bool
766 MaybeWrapStringValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
768 MOZ_ASSERT(rval.isString());
769 JSString* str = rval.toString();
770 if (JS::GetTenuredGCThingZone(str) != js::GetContextZone(cx)) {
771 return JS_WrapValue(cx, rval);
773 return true;
776 // Make sure to wrap the given object value into the right compartment as
777 // needed. This will work correctly, but possibly slowly, on all objects.
778 MOZ_ALWAYS_INLINE
779 bool
780 MaybeWrapObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
782 MOZ_ASSERT(rval.isObject());
784 // Cross-compartment always requires wrapping.
785 JSObject* obj = &rval.toObject();
786 if (js::GetObjectCompartment(obj) != js::GetContextCompartment(cx)) {
787 return JS_WrapValue(cx, rval);
790 // We're same-compartment, but even then we might need to wrap
791 // objects specially. Check for that.
792 if (IsDOMObject(obj)) {
793 return TryToOuterize(cx, rval);
796 // It's not a WebIDL object. But it might be an XPConnect one, in which case
797 // we may need to outerize here, so make sure to call JS_WrapValue.
798 return JS_WrapValue(cx, rval);
801 // Like MaybeWrapObjectValue, but also allows null
802 MOZ_ALWAYS_INLINE
803 bool
804 MaybeWrapObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
806 MOZ_ASSERT(rval.isObjectOrNull());
807 if (rval.isNull()) {
808 return true;
810 return MaybeWrapObjectValue(cx, rval);
813 // Wrapping for objects that are known to not be DOM or XPConnect objects
814 MOZ_ALWAYS_INLINE
815 bool
816 MaybeWrapNonDOMObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
818 MOZ_ASSERT(rval.isObject());
819 MOZ_ASSERT(!GetDOMClass(&rval.toObject()));
820 MOZ_ASSERT(!(js::GetObjectClass(&rval.toObject())->flags &
821 JSCLASS_PRIVATE_IS_NSISUPPORTS));
823 JSObject* obj = &rval.toObject();
824 if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) {
825 return true;
827 return JS_WrapValue(cx, rval);
830 // Like MaybeWrapNonDOMObjectValue but allows null
831 MOZ_ALWAYS_INLINE
832 bool
833 MaybeWrapNonDOMObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
835 MOZ_ASSERT(rval.isObjectOrNull());
836 if (rval.isNull()) {
837 return true;
839 return MaybeWrapNonDOMObjectValue(cx, rval);
842 // If rval is a gcthing and is not in the compartment of cx, wrap rval
843 // into the compartment of cx (typically by replacing it with an Xray or
844 // cross-compartment wrapper around the original object).
845 MOZ_ALWAYS_INLINE bool
846 MaybeWrapValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
848 if (rval.isString()) {
849 return MaybeWrapStringValue(cx, rval);
852 if (!rval.isObject()) {
853 return true;
856 return MaybeWrapObjectValue(cx, rval);
859 namespace binding_detail {
860 enum GetOrCreateReflectorWrapBehavior {
861 eWrapIntoContextCompartment,
862 eDontWrapIntoContextCompartment
865 template <class T>
866 struct TypeNeedsOuterization
868 // We only need to outerize Window objects, so anything inheriting from
869 // nsGlobalWindow (which inherits from EventTarget itself).
870 static const bool value =
871 IsBaseOf<nsGlobalWindow, T>::value || IsSame<EventTarget, T>::value;
874 template <class T, GetOrCreateReflectorWrapBehavior wrapBehavior>
875 MOZ_ALWAYS_INLINE bool
876 DoGetOrCreateDOMReflector(JSContext* cx, T* value,
877 JS::MutableHandle<JS::Value> rval)
879 MOZ_ASSERT(value);
880 JSObject* obj = value->GetWrapperPreserveColor();
881 // We can get rid of this when we remove support for hasXPConnectImpls.
882 bool couldBeDOMBinding = CouldBeDOMBinding(value);
883 if (obj) {
884 JS::ExposeObjectToActiveJS(obj);
885 } else {
886 // Inline this here while we have non-dom objects in wrapper caches.
887 if (!couldBeDOMBinding) {
888 return false;
891 obj = value->WrapObject(cx);
892 if (!obj) {
893 // At this point, obj is null, so just return false.
894 // Callers seem to be testing JS_IsExceptionPending(cx) to
895 // figure out whether WrapObject() threw.
896 return false;
900 #ifdef DEBUG
901 const DOMJSClass* clasp = GetDOMClass(obj);
902 // clasp can be null if the cache contained a non-DOM object.
903 if (clasp) {
904 // Some sanity asserts about our object. Specifically:
905 // 1) If our class claims we're nsISupports, we better be nsISupports
906 // XXXbz ideally, we could assert that reinterpret_cast to nsISupports
907 // does the right thing, but I don't see a way to do it. :(
908 // 2) If our class doesn't claim we're nsISupports we better be
909 // reinterpret_castable to nsWrapperCache.
910 MOZ_ASSERT(clasp, "What happened here?");
911 MOZ_ASSERT_IF(clasp->mDOMObjectIsISupports, (IsBaseOf<nsISupports, T>::value));
912 MOZ_ASSERT(CheckWrapperCacheCast<T>::Check());
914 #endif
916 rval.set(JS::ObjectValue(*obj));
918 bool sameCompartment =
919 js::GetObjectCompartment(obj) == js::GetContextCompartment(cx);
920 if (sameCompartment && couldBeDOMBinding) {
921 return TypeNeedsOuterization<T>::value ? TryToOuterize(cx, rval) : true;
924 if (wrapBehavior == eDontWrapIntoContextCompartment) {
925 if (TypeNeedsOuterization<T>::value) {
926 JSAutoCompartment ac(cx, obj);
927 return TryToOuterize(cx, rval);
930 return true;
933 return JS_WrapValue(cx, rval);
935 } // namespace binding_detail
937 // Create a JSObject wrapping "value", if there isn't one already, and store it
938 // in rval. "value" must be a concrete class that implements a
939 // GetWrapperPreserveColor() which can return its existing wrapper, if any, and
940 // a WrapObject() which will try to create a wrapper. Typically, this is done by
941 // having "value" inherit from nsWrapperCache.
943 // The value stored in rval will be ready to be exposed to whatever JS
944 // is running on cx right now. In particular, it will be in the
945 // compartment of cx, and outerized as needed.
946 template <class T>
947 MOZ_ALWAYS_INLINE bool
948 GetOrCreateDOMReflector(JSContext* cx, T* value,
949 JS::MutableHandle<JS::Value> rval)
951 using namespace binding_detail;
952 return DoGetOrCreateDOMReflector<T, eWrapIntoContextCompartment>(cx, value,
953 rval);
956 // Like GetOrCreateDOMReflector but doesn't wrap into the context compartment,
957 // and hence does not actually require cx to be in a compartment.
958 template <class T>
959 MOZ_ALWAYS_INLINE bool
960 GetOrCreateDOMReflectorNoWrap(JSContext* cx, T* value,
961 JS::MutableHandle<JS::Value> rval)
963 using namespace binding_detail;
964 return DoGetOrCreateDOMReflector<T, eDontWrapIntoContextCompartment>(cx,
965 value,
966 rval);
969 // Create a JSObject wrapping "value", for cases when "value" is a
970 // non-wrapper-cached object using WebIDL bindings. "value" must implement a
971 // WrapObject() method taking a JSContext and a scope.
972 template <class T>
973 inline bool
974 WrapNewBindingNonWrapperCachedObject(JSContext* cx,
975 JS::Handle<JSObject*> scopeArg,
976 T* value,
977 JS::MutableHandle<JS::Value> rval)
979 MOZ_ASSERT(value);
980 // We try to wrap in the compartment of the underlying object of "scope"
981 JS::Rooted<JSObject*> obj(cx);
983 // scope for the JSAutoCompartment so that we restore the compartment
984 // before we call JS_WrapValue.
985 Maybe<JSAutoCompartment> ac;
986 // Maybe<Handle> doesn't so much work, and in any case, adding
987 // more Maybe (one for a Rooted and one for a Handle) adds more
988 // code (and branches!) than just adding a single rooted.
989 JS::Rooted<JSObject*> scope(cx, scopeArg);
990 if (js::IsWrapper(scope)) {
991 scope = js::CheckedUnwrap(scope, /* stopAtOuter = */ false);
992 if (!scope)
993 return false;
994 ac.emplace(cx, scope);
997 MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
998 obj = value->WrapObject(cx);
1001 if (!obj) {
1002 return false;
1005 // We can end up here in all sorts of compartments, per above. Make
1006 // sure to JS_WrapValue!
1007 rval.set(JS::ObjectValue(*obj));
1008 return JS_WrapValue(cx, rval);
1011 // Create a JSObject wrapping "value", for cases when "value" is a
1012 // non-wrapper-cached owned object using WebIDL bindings. "value" must implement a
1013 // WrapObject() method taking a JSContext, a scope, and a boolean outparam that
1014 // is true if the JSObject took ownership
1015 template <class T>
1016 inline bool
1017 WrapNewBindingNonWrapperCachedOwnedObject(JSContext* cx,
1018 JS::Handle<JSObject*> scopeArg,
1019 nsAutoPtr<T>& value,
1020 JS::MutableHandle<JS::Value> rval)
1022 // We do a runtime check on value, because otherwise we might in
1023 // fact end up wrapping a null and invoking methods on it later.
1024 if (!value) {
1025 NS_RUNTIMEABORT("Don't try to wrap null objects");
1027 // We try to wrap in the compartment of the underlying object of "scope"
1028 JS::Rooted<JSObject*> obj(cx);
1030 // scope for the JSAutoCompartment so that we restore the compartment
1031 // before we call JS_WrapValue.
1032 Maybe<JSAutoCompartment> ac;
1033 // Maybe<Handle> doesn't so much work, and in any case, adding
1034 // more Maybe (one for a Rooted and one for a Handle) adds more
1035 // code (and branches!) than just adding a single rooted.
1036 JS::Rooted<JSObject*> scope(cx, scopeArg);
1037 if (js::IsWrapper(scope)) {
1038 scope = js::CheckedUnwrap(scope, /* stopAtOuter = */ false);
1039 if (!scope)
1040 return false;
1041 ac.emplace(cx, scope);
1044 bool tookOwnership = false;
1045 MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
1046 obj = value->WrapObject(cx, &tookOwnership);
1047 MOZ_ASSERT_IF(obj, tookOwnership);
1048 if (tookOwnership) {
1049 value.forget();
1053 if (!obj) {
1054 return false;
1057 // We can end up here in all sorts of compartments, per above. Make
1058 // sure to JS_WrapValue!
1059 rval.set(JS::ObjectValue(*obj));
1060 return JS_WrapValue(cx, rval);
1063 // Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr).
1064 template <template <typename> class SmartPtr, typename T>
1065 inline bool
1066 WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
1067 const SmartPtr<T>& value,
1068 JS::MutableHandle<JS::Value> rval)
1070 return WrapNewBindingNonWrapperCachedObject(cx, scope, value.get(), rval);
1073 // Only set allowNativeWrapper to false if you really know you need it, if in
1074 // doubt use true. Setting it to false disables security wrappers.
1075 bool
1076 NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
1077 JS::Handle<JSObject*> aScope,
1078 JS::MutableHandle<JS::Value> aRetval,
1079 xpcObjectHelper& aHelper,
1080 const nsIID* aIID,
1081 bool aAllowNativeWrapper);
1084 * A method to handle new-binding wrap failure, by possibly falling back to
1085 * wrapping as a non-new-binding object.
1087 template <class T>
1088 MOZ_ALWAYS_INLINE bool
1089 HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
1090 T* value, JS::MutableHandle<JS::Value> rval)
1092 if (JS_IsExceptionPending(cx)) {
1093 return false;
1096 qsObjectHelper helper(value, GetWrapperCache(value));
1097 return NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval,
1098 helper, nullptr, true);
1101 // Helper for calling HandleNewBindingWrappingFailure with smart pointers
1102 // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
1103 HAS_MEMBER(get)
1105 template <class T, bool isSmartPtr=HasgetMember<T>::Value>
1106 struct HandleNewBindingWrappingFailureHelper
1108 static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
1109 const T& value, JS::MutableHandle<JS::Value> rval)
1111 return HandleNewBindingWrappingFailure(cx, scope, value.get(), rval);
1115 template <class T>
1116 struct HandleNewBindingWrappingFailureHelper<T, false>
1118 static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope, T& value,
1119 JS::MutableHandle<JS::Value> rval)
1121 return HandleNewBindingWrappingFailure(cx, scope, &value, rval);
1125 template<class T>
1126 inline bool
1127 HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
1128 T& value, JS::MutableHandle<JS::Value> rval)
1130 return HandleNewBindingWrappingFailureHelper<T>::Wrap(cx, scope, value, rval);
1133 template<bool Fatal>
1134 inline bool
1135 EnumValueNotFound(JSContext* cx, JSString* str, const char* type,
1136 const char* sourceDescription)
1138 return false;
1141 template<>
1142 inline bool
1143 EnumValueNotFound<false>(JSContext* cx, JSString* str, const char* type,
1144 const char* sourceDescription)
1146 // TODO: Log a warning to the console.
1147 return true;
1150 template<>
1151 inline bool
1152 EnumValueNotFound<true>(JSContext* cx, JSString* str, const char* type,
1153 const char* sourceDescription)
1155 JSAutoByteString deflated(cx, str);
1156 if (!deflated) {
1157 return false;
1159 return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
1160 deflated.ptr(), type);
1163 template<typename CharT>
1164 inline int
1165 FindEnumStringIndexImpl(const CharT* chars, size_t length, const EnumEntry* values)
1167 int i = 0;
1168 for (const EnumEntry* value = values; value->value; ++value, ++i) {
1169 if (length != value->length) {
1170 continue;
1173 bool equal = true;
1174 const char* val = value->value;
1175 for (size_t j = 0; j != length; ++j) {
1176 if (unsigned(val[j]) != unsigned(chars[j])) {
1177 equal = false;
1178 break;
1182 if (equal) {
1183 return i;
1187 return -1;
1190 template<bool InvalidValueFatal>
1191 inline int
1192 FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* values,
1193 const char* type, const char* sourceDescription, bool* ok)
1195 // JS_StringEqualsAscii is slow as molasses, so don't use it here.
1196 JSString* str = JS::ToString(cx, v);
1197 if (!str) {
1198 *ok = false;
1199 return 0;
1203 int index;
1204 size_t length;
1205 JS::AutoCheckCannotGC nogc;
1206 if (js::StringHasLatin1Chars(str)) {
1207 const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str,
1208 &length);
1209 if (!chars) {
1210 *ok = false;
1211 return 0;
1213 index = FindEnumStringIndexImpl(chars, length, values);
1214 } else {
1215 const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, str,
1216 &length);
1217 if (!chars) {
1218 *ok = false;
1219 return 0;
1221 index = FindEnumStringIndexImpl(chars, length, values);
1223 if (index >= 0) {
1224 *ok = true;
1225 return index;
1229 *ok = EnumValueNotFound<InvalidValueFatal>(cx, str, type, sourceDescription);
1230 return -1;
1233 inline nsWrapperCache*
1234 GetWrapperCache(const ParentObject& aParentObject)
1236 return aParentObject.mWrapperCache;
1239 template<class T>
1240 inline T*
1241 GetParentPointer(T* aObject)
1243 return aObject;
1246 inline nsISupports*
1247 GetParentPointer(const ParentObject& aObject)
1249 return aObject.mObject;
1252 template <typename T>
1253 inline bool
1254 GetUseXBLScope(T* aParentObject)
1256 return false;
1259 inline bool
1260 GetUseXBLScope(const ParentObject& aParentObject)
1262 return aParentObject.mUseXBLScope;
1265 template<class T>
1266 inline void
1267 ClearWrapper(T* p, nsWrapperCache* cache)
1269 cache->ClearWrapper();
1272 template<class T>
1273 inline void
1274 ClearWrapper(T* p, void*)
1276 nsWrapperCache* cache;
1277 CallQueryInterface(p, &cache);
1278 ClearWrapper(p, cache);
1281 template<class T>
1282 inline void
1283 UpdateWrapper(T* p, nsWrapperCache* cache, JSObject* obj, const JSObject* old)
1285 JS::AutoAssertGCCallback inCallback(obj);
1286 cache->UpdateWrapper(obj, old);
1289 template<class T>
1290 inline void
1291 UpdateWrapper(T* p, void*, JSObject* obj, const JSObject* old)
1293 JS::AutoAssertGCCallback inCallback(obj);
1294 nsWrapperCache* cache;
1295 CallQueryInterface(p, &cache);
1296 UpdateWrapper(p, cache, obj, old);
1299 // Attempt to preserve the wrapper, if any, for a Paris DOM bindings object.
1300 // Return true if we successfully preserved the wrapper, or there is no wrapper
1301 // to preserve. In the latter case we don't need to preserve the wrapper, because
1302 // the object can only be obtained by JS once, or they cannot be meaningfully
1303 // owned from the native side.
1305 // This operation will return false only for non-nsISupports cycle-collected
1306 // objects, because we cannot determine if they are wrappercached or not.
1307 bool
1308 TryPreserveWrapper(JSObject* obj);
1310 // Can only be called with a DOM JSClass.
1311 bool
1312 InstanceClassHasProtoAtDepth(const js::Class* clasp,
1313 uint32_t protoID, uint32_t depth);
1315 // Only set allowNativeWrapper to false if you really know you need it, if in
1316 // doubt use true. Setting it to false disables security wrappers.
1317 bool
1318 XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
1319 xpcObjectHelper& helper, const nsIID* iid,
1320 bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval);
1322 // Special-cased wrapping for variants
1323 bool
1324 VariantToJsval(JSContext* aCx, nsIVariant* aVariant,
1325 JS::MutableHandle<JS::Value> aRetval);
1327 // Wrap an object "p" which is not using WebIDL bindings yet. This _will_
1328 // actually work on WebIDL binding objects that are wrappercached, but will be
1329 // much slower than GetOrCreateDOMReflector. "cache" must either be null or be
1330 // the nsWrapperCache for "p".
1331 template<class T>
1332 inline bool
1333 WrapObject(JSContext* cx, T* p, nsWrapperCache* cache, const nsIID* iid,
1334 JS::MutableHandle<JS::Value> rval)
1336 if (xpc_FastGetCachedWrapper(cx, cache, rval))
1337 return true;
1338 qsObjectHelper helper(p, cache);
1339 JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
1340 return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval);
1343 // A specialization of the above for nsIVariant, because that needs to
1344 // do something different.
1345 template<>
1346 inline bool
1347 WrapObject<nsIVariant>(JSContext* cx, nsIVariant* p,
1348 nsWrapperCache* cache, const nsIID* iid,
1349 JS::MutableHandle<JS::Value> rval)
1351 MOZ_ASSERT(iid);
1352 MOZ_ASSERT(iid->Equals(NS_GET_IID(nsIVariant)));
1353 return VariantToJsval(cx, p, rval);
1356 // Wrap an object "p" which is not using WebIDL bindings yet. Just like the
1357 // variant that takes an nsWrapperCache above, but will try to auto-derive the
1358 // nsWrapperCache* from "p".
1359 template<class T>
1360 inline bool
1361 WrapObject(JSContext* cx, T* p, const nsIID* iid,
1362 JS::MutableHandle<JS::Value> rval)
1364 return WrapObject(cx, p, GetWrapperCache(p), iid, rval);
1367 // Just like the WrapObject above, but without requiring you to pick which
1368 // interface you're wrapping as. This should only be used for objects that have
1369 // classinfo, for which it doesn't matter what IID is used to wrap.
1370 template<class T>
1371 inline bool
1372 WrapObject(JSContext* cx, T* p, JS::MutableHandle<JS::Value> rval)
1374 return WrapObject(cx, p, nullptr, rval);
1377 // Helper to make it possible to wrap directly out of an nsCOMPtr
1378 template<class T>
1379 inline bool
1380 WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
1381 const nsIID* iid, JS::MutableHandle<JS::Value> rval)
1383 return WrapObject(cx, p.get(), iid, rval);
1386 // Helper to make it possible to wrap directly out of an nsCOMPtr
1387 template<class T>
1388 inline bool
1389 WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
1390 JS::MutableHandle<JS::Value> rval)
1392 return WrapObject(cx, p, nullptr, rval);
1395 // Helper to make it possible to wrap directly out of an nsRefPtr
1396 template<class T>
1397 inline bool
1398 WrapObject(JSContext* cx, const nsRefPtr<T>& p,
1399 const nsIID* iid, JS::MutableHandle<JS::Value> rval)
1401 return WrapObject(cx, p.get(), iid, rval);
1404 // Helper to make it possible to wrap directly out of an nsRefPtr
1405 template<class T>
1406 inline bool
1407 WrapObject(JSContext* cx, const nsRefPtr<T>& p,
1408 JS::MutableHandle<JS::Value> rval)
1410 return WrapObject(cx, p, nullptr, rval);
1413 // Specialization to make it easy to use WrapObject in codegen.
1414 template<>
1415 inline bool
1416 WrapObject<JSObject>(JSContext* cx, JSObject* p,
1417 JS::MutableHandle<JS::Value> rval)
1419 rval.set(JS::ObjectOrNullValue(p));
1420 return true;
1423 inline bool
1424 WrapObject(JSContext* cx, JSObject& p, JS::MutableHandle<JS::Value> rval)
1426 rval.set(JS::ObjectValue(p));
1427 return true;
1430 // Given an object "p" that inherits from nsISupports, wrap it and return the
1431 // result. Null is returned on wrapping failure. This is somewhat similar to
1432 // WrapObject() above, but does NOT allow Xrays around the result, since we
1433 // don't want those for our parent object.
1434 template<typename T>
1435 static inline JSObject*
1436 WrapNativeISupportsParent(JSContext* cx, T* p, nsWrapperCache* cache)
1438 qsObjectHelper helper(ToSupports(p), cache);
1439 JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
1440 JS::Rooted<JS::Value> v(cx);
1441 return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
1442 v.toObjectOrNull() :
1443 nullptr;
1447 // Fallback for when our parent is not a WebIDL binding object.
1448 template<typename T, bool isISupports=IsBaseOf<nsISupports, T>::value>
1449 struct WrapNativeParentFallback
1451 static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
1453 return nullptr;
1457 // Fallback for when our parent is not a WebIDL binding object but _is_ an
1458 // nsISupports object.
1459 template<typename T >
1460 struct WrapNativeParentFallback<T, true >
1462 static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
1464 return WrapNativeISupportsParent(cx, parent, cache);
1468 // Wrapping of our native parent, for cases when it's a WebIDL object (though
1469 // possibly preffed off).
1470 template<typename T, bool hasWrapObject=HasWrapObject<T>::Value >
1471 struct WrapNativeParentHelper
1473 static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
1475 MOZ_ASSERT(cache);
1477 JSObject* obj;
1478 if ((obj = cache->GetWrapper())) {
1479 return obj;
1482 // Inline this here while we have non-dom objects in wrapper caches.
1483 if (!CouldBeDOMBinding(parent)) {
1484 obj = WrapNativeParentFallback<T>::Wrap(cx, parent, cache);
1485 } else {
1486 obj = parent->WrapObject(cx);
1489 return obj;
1493 // Wrapping of our native parent, for cases when it's not a WebIDL object. In
1494 // this case it must be nsISupports.
1495 template<typename T>
1496 struct WrapNativeParentHelper<T, false >
1498 static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
1500 JSObject* obj;
1501 if (cache && (obj = cache->GetWrapper())) {
1502 #ifdef DEBUG
1503 NS_ASSERTION(WrapNativeISupportsParent(cx, parent, cache) == obj,
1504 "Unexpected object in nsWrapperCache");
1505 #endif
1506 return obj;
1509 return WrapNativeISupportsParent(cx, parent, cache);
1513 // Wrapping of our native parent.
1514 template<typename T>
1515 static inline JSObject*
1516 WrapNativeParent(JSContext* cx, T* p, nsWrapperCache* cache,
1517 bool useXBLScope = false)
1519 if (!p) {
1520 return JS::CurrentGlobalOrNull(cx);
1523 JSObject* parent = WrapNativeParentHelper<T>::Wrap(cx, p, cache);
1524 if (!useXBLScope) {
1525 return parent;
1528 // If useXBLScope is true, it means that the canonical reflector for this
1529 // native object should live in the content XBL scope. Note that we never put
1530 // anonymous content inside an add-on scope.
1531 if (xpc::IsInContentXBLScope(parent)) {
1532 return parent;
1534 JS::Rooted<JSObject*> rootedParent(cx, parent);
1535 JS::Rooted<JSObject*> xblScope(cx, xpc::GetXBLScope(cx, rootedParent));
1536 NS_ENSURE_TRUE(xblScope, nullptr);
1537 JSAutoCompartment ac(cx, xblScope);
1538 if (NS_WARN_IF(!JS_WrapObject(cx, &rootedParent))) {
1539 return nullptr;
1542 return rootedParent;
1545 // Wrapping of our native parent, when we don't want to explicitly pass in
1546 // things like the nsWrapperCache for it.
1547 template<typename T>
1548 static inline JSObject*
1549 WrapNativeParent(JSContext* cx, const T& p)
1551 return WrapNativeParent(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
1554 HAS_MEMBER(GetParentObject)
1556 template<typename T, bool WrapperCached=HasGetParentObjectMember<T>::Value>
1557 struct GetParentObject
1559 static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
1561 MOZ_ASSERT(js::IsObjectInContextCompartment(obj, cx));
1562 T* native = UnwrapDOMObject<T>(obj);
1563 JSObject* wrappedParent = WrapNativeParent(cx, native->GetParentObject());
1564 return wrappedParent ? js::GetGlobalForObjectCrossCompartment(wrappedParent) : nullptr;
1568 template<typename T>
1569 struct GetParentObject<T, false>
1571 static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
1573 MOZ_CRASH();
1574 return nullptr;
1578 MOZ_ALWAYS_INLINE
1579 JSObject* GetJSObjectFromCallback(CallbackObject* callback)
1581 return callback->Callback();
1584 MOZ_ALWAYS_INLINE
1585 JSObject* GetJSObjectFromCallback(void* noncallback)
1587 return nullptr;
1590 template<typename T>
1591 static inline JSObject*
1592 WrapCallThisObject(JSContext* cx, const T& p)
1594 // Callbacks are nsISupports, so WrapNativeParent will just happily wrap them
1595 // up as an nsISupports XPCWrappedNative... which is not at all what we want.
1596 // So we need to special-case them.
1597 JS::Rooted<JSObject*> obj(cx, GetJSObjectFromCallback(p));
1598 if (!obj) {
1599 // WrapNativeParent is a bit of a Swiss army knife that will
1600 // wrap anything for us.
1601 obj = WrapNativeParent(cx, p);
1602 if (!obj) {
1603 return nullptr;
1607 // But all that won't necessarily put things in the compartment of cx.
1608 if (!JS_WrapObject(cx, &obj)) {
1609 return nullptr;
1612 return obj;
1616 * This specialized function simply wraps a JS::Rooted<> since
1617 * WrapNativeParent() is not applicable for JS objects.
1619 template<>
1620 inline JSObject*
1621 WrapCallThisObject<JS::Rooted<JSObject*>>(JSContext* cx,
1622 const JS::Rooted<JSObject*>& p)
1624 JS::Rooted<JSObject*> obj(cx, p);
1626 if (!JS_WrapObject(cx, &obj)) {
1627 return nullptr;
1630 return obj;
1633 // Helper for calling GetOrCreateDOMReflector with smart pointers
1634 // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
1635 template <class T, bool isSmartPtr=HasgetMember<T>::Value>
1636 struct GetOrCreateDOMReflectorHelper
1638 static inline bool GetOrCreate(JSContext* cx, const T& value,
1639 JS::MutableHandle<JS::Value> rval)
1641 return GetOrCreateDOMReflector(cx, value.get(), rval);
1645 template <class T>
1646 struct GetOrCreateDOMReflectorHelper<T, false>
1648 static inline bool GetOrCreate(JSContext* cx, T& value,
1649 JS::MutableHandle<JS::Value> rval)
1651 return GetOrCreateDOMReflector(cx, &value, rval);
1655 template<class T>
1656 inline bool
1657 GetOrCreateDOMReflector(JSContext* cx, T& value,
1658 JS::MutableHandle<JS::Value> rval)
1660 return GetOrCreateDOMReflectorHelper<T>::GetOrCreate(cx, value, rval);
1663 // We need this version of GetOrCreateDOMReflector for codegen, so it'll have
1664 // the same signature as WrapNewBindingNonWrapperCachedObject and
1665 // WrapNewBindingNonWrapperCachedOwnedObject, which still need the scope.
1666 template<class T>
1667 inline bool
1668 GetOrCreateDOMReflector(JSContext* cx, JS::Handle<JSObject*> scope, T& value,
1669 JS::MutableHandle<JS::Value> rval)
1671 return GetOrCreateDOMReflector(cx, value, rval);
1674 // Helper for calling GetOrCreateDOMReflectorNoWrap with smart pointers
1675 // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
1676 template <class T, bool isSmartPtr=HasgetMember<T>::Value>
1677 struct GetOrCreateDOMReflectorNoWrapHelper
1679 static inline bool GetOrCreate(JSContext* cx, const T& value,
1680 JS::MutableHandle<JS::Value> rval)
1682 return GetOrCreateDOMReflectorNoWrap(cx, value.get(), rval);
1686 template <class T>
1687 struct GetOrCreateDOMReflectorNoWrapHelper<T, false>
1689 static inline bool GetOrCreate(JSContext* cx, T& value,
1690 JS::MutableHandle<JS::Value> rval)
1692 return GetOrCreateDOMReflectorNoWrap(cx, &value, rval);
1696 template<class T>
1697 inline bool
1698 GetOrCreateDOMReflectorNoWrap(JSContext* cx, T& value,
1699 JS::MutableHandle<JS::Value> rval)
1701 return
1702 GetOrCreateDOMReflectorNoWrapHelper<T>::GetOrCreate(cx, value, rval);
1705 template <class T>
1706 inline JSObject*
1707 GetCallbackFromCallbackObject(T* aObj)
1709 return aObj->Callback();
1712 // Helper for getting the callback JSObject* of a smart ptr around a
1713 // CallbackObject or a reference to a CallbackObject or something like
1714 // that.
1715 template <class T, bool isSmartPtr=HasgetMember<T>::Value>
1716 struct GetCallbackFromCallbackObjectHelper
1718 static inline JSObject* Get(const T& aObj)
1720 return GetCallbackFromCallbackObject(aObj.get());
1724 template <class T>
1725 struct GetCallbackFromCallbackObjectHelper<T, false>
1727 static inline JSObject* Get(T& aObj)
1729 return GetCallbackFromCallbackObject(&aObj);
1733 template<class T>
1734 inline JSObject*
1735 GetCallbackFromCallbackObject(T& aObj)
1737 return GetCallbackFromCallbackObjectHelper<T>::Get(aObj);
1740 static inline bool
1741 InternJSString(JSContext* cx, jsid& id, const char* chars)
1743 if (JSString *str = ::JS_InternString(cx, chars)) {
1744 id = INTERNED_STRING_TO_JSID(cx, str);
1745 return true;
1747 return false;
1750 // Spec needs a name property
1751 template <typename Spec>
1752 static bool
1753 InitIds(JSContext* cx, const Prefable<Spec>* prefableSpecs, jsid* ids)
1755 MOZ_ASSERT(prefableSpecs);
1756 MOZ_ASSERT(prefableSpecs->specs);
1757 do {
1758 // We ignore whether the set of ids is enabled and just intern all the IDs,
1759 // because this is only done once per application runtime.
1760 Spec* spec = prefableSpecs->specs;
1761 do {
1762 if (!JS::PropertySpecNameToPermanentId(cx, spec->name, ids)) {
1763 return false;
1765 } while (++ids, (++spec)->name);
1767 // We ran out of ids for that pref. Put a JSID_VOID in on the id
1768 // corresponding to the list terminator for the pref.
1769 *ids = JSID_VOID;
1770 ++ids;
1771 } while ((++prefableSpecs)->specs);
1773 return true;
1776 bool
1777 QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
1779 template <class T>
1780 struct
1781 WantsQueryInterface
1783 static_assert(IsBaseOf<nsISupports, T>::value,
1784 "QueryInterface can't work without an nsISupports.");
1785 static bool Enabled(JSContext* aCx, JSObject* aGlobal)
1787 return NS_IsMainThread() && IsChromeOrXBL(aCx, aGlobal);
1791 void
1792 GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
1793 nsWrapperCache* aCache, nsIJSID* aIID,
1794 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError);
1796 template<class T>
1797 void
1798 GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID,
1799 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
1801 GetInterfaceImpl(aCx, aThis, aThis, aIID, aRetval, aError);
1804 bool
1805 UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp);
1807 bool
1808 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
1810 bool
1811 ThrowConstructorWithoutNew(JSContext* cx, const char* name);
1813 bool
1814 GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
1815 JS::Handle<jsid> id, bool* found,
1816 JS::MutableHandle<JS::Value> vp);
1819 bool
1820 HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
1821 JS::Handle<jsid> id, bool* has);
1824 // Append the property names in "names" to "props". If
1825 // shadowPrototypeProperties is false then skip properties that are also
1826 // present on the proto chain of proxy. If shadowPrototypeProperties is true,
1827 // then the "proxy" argument is ignored.
1828 bool
1829 AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
1830 nsTArray<nsString>& names,
1831 bool shadowPrototypeProperties, JS::AutoIdVector& props);
1833 namespace binding_detail {
1835 // A struct that has the same layout as an nsString but much faster
1836 // constructor and destructor behavior. FakeString uses inline storage
1837 // for small strings and a nsStringBuffer for longer strings.
1838 struct FakeString {
1839 FakeString() :
1840 mFlags(nsString::F_TERMINATED)
1844 ~FakeString() {
1845 if (mFlags & nsString::F_SHARED) {
1846 nsStringBuffer::FromData(mData)->Release();
1850 void Rebind(const nsString::char_type* aData, nsString::size_type aLength) {
1851 MOZ_ASSERT(mFlags == nsString::F_TERMINATED);
1852 mData = const_cast<nsString::char_type*>(aData);
1853 mLength = aLength;
1856 void Truncate() {
1857 MOZ_ASSERT(mFlags == nsString::F_TERMINATED);
1858 mData = nsString::char_traits::sEmptyBuffer;
1859 mLength = 0;
1862 void SetIsVoid(bool aValue) {
1863 MOZ_ASSERT(aValue,
1864 "We don't support SetIsVoid(false) on FakeString!");
1865 Truncate();
1866 mFlags |= nsString::F_VOIDED;
1869 const nsString::char_type* Data() const
1871 return mData;
1874 nsString::char_type* BeginWriting()
1876 return mData;
1879 nsString::size_type Length() const
1881 return mLength;
1884 // Reserve space to write aLength chars, not including null-terminator.
1885 bool SetLength(nsString::size_type aLength, mozilla::fallible_t const&) {
1886 // Use mInlineStorage for small strings.
1887 if (aLength < sInlineCapacity) {
1888 SetData(mInlineStorage);
1889 } else {
1890 nsStringBuffer *buf = nsStringBuffer::Alloc((aLength + 1) * sizeof(nsString::char_type)).take();
1891 if (MOZ_UNLIKELY(!buf)) {
1892 return false;
1895 SetData(static_cast<nsString::char_type*>(buf->Data()));
1896 mFlags = nsString::F_SHARED | nsString::F_TERMINATED;
1898 mLength = aLength;
1899 mData[mLength] = char16_t(0);
1900 return true;
1903 // If this ever changes, change the corresponding code in the
1904 // Optional<nsAString> specialization as well.
1905 const nsAString* ToAStringPtr() const {
1906 return reinterpret_cast<const nsString*>(this);
1909 nsAString* ToAStringPtr() {
1910 return reinterpret_cast<nsString*>(this);
1913 operator const nsAString& () const {
1914 return *reinterpret_cast<const nsString*>(this);
1917 private:
1918 nsString::char_type* mData;
1919 nsString::size_type mLength;
1920 uint32_t mFlags;
1922 static const size_t sInlineCapacity = 64;
1923 nsString::char_type mInlineStorage[sInlineCapacity];
1925 FakeString(const FakeString& other) = delete;
1926 void operator=(const FakeString& other) = delete;
1928 void SetData(nsString::char_type* aData) {
1929 MOZ_ASSERT(mFlags == nsString::F_TERMINATED);
1930 mData = const_cast<nsString::char_type*>(aData);
1933 // A class to use for our static asserts to ensure our object layout
1934 // matches that of nsString.
1935 class StringAsserter;
1936 friend class StringAsserter;
1938 class StringAsserter : public nsString {
1939 public:
1940 static void StaticAsserts() {
1941 static_assert(offsetof(FakeString, mInlineStorage) ==
1942 sizeof(nsString),
1943 "FakeString should include all nsString members");
1944 static_assert(offsetof(FakeString, mData) ==
1945 offsetof(StringAsserter, mData),
1946 "Offset of mData should match");
1947 static_assert(offsetof(FakeString, mLength) ==
1948 offsetof(StringAsserter, mLength),
1949 "Offset of mLength should match");
1950 static_assert(offsetof(FakeString, mFlags) ==
1951 offsetof(StringAsserter, mFlags),
1952 "Offset of mFlags should match");
1957 } // namespace binding_detail
1959 enum StringificationBehavior {
1960 eStringify,
1961 eEmpty,
1962 eNull
1965 template<typename T>
1966 static inline bool
1967 ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
1968 StringificationBehavior nullBehavior,
1969 StringificationBehavior undefinedBehavior,
1970 T& result)
1972 JSString *s;
1973 if (v.isString()) {
1974 s = v.toString();
1975 } else {
1976 StringificationBehavior behavior;
1977 if (v.isNull()) {
1978 behavior = nullBehavior;
1979 } else if (v.isUndefined()) {
1980 behavior = undefinedBehavior;
1981 } else {
1982 behavior = eStringify;
1985 if (behavior != eStringify) {
1986 if (behavior == eEmpty) {
1987 result.Truncate();
1988 } else {
1989 result.SetIsVoid(true);
1991 return true;
1994 s = JS::ToString(cx, v);
1995 if (!s) {
1996 return false;
2000 return AssignJSString(cx, result, s);
2003 void
2004 NormalizeUSVString(JSContext* aCx, nsAString& aString);
2006 void
2007 NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString);
2009 template<typename T>
2010 inline bool
2011 ConvertIdToString(JSContext* cx, JS::HandleId id, T& result, bool& isSymbol)
2013 if (MOZ_LIKELY(JSID_IS_STRING(id))) {
2014 if (!AssignJSString(cx, result, JSID_TO_STRING(id))) {
2015 return false;
2017 } else if (JSID_IS_SYMBOL(id)) {
2018 isSymbol = true;
2019 return true;
2020 } else {
2021 JS::RootedValue nameVal(cx, js::IdToValue(id));
2022 if (!ConvertJSValueToString(cx, nameVal, eStringify, eStringify, result)) {
2023 return false;
2026 isSymbol = false;
2027 return true;
2030 bool
2031 ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
2032 bool nullable, nsACString& result);
2034 template<typename T>
2035 void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
2036 template<typename T>
2037 void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
2039 // Class for simple sequence arguments, only used internally by codegen.
2040 namespace binding_detail {
2042 template<typename T>
2043 class AutoSequence : public AutoFallibleTArray<T, 16>
2045 public:
2046 AutoSequence() : AutoFallibleTArray<T, 16>()
2049 // Allow converting to const sequences as needed
2050 operator const Sequence<T>&() const {
2051 return *reinterpret_cast<const Sequence<T>*>(this);
2055 } // namespace binding_detail
2057 // Class used to trace sequences, with specializations for various
2058 // sequence types.
2059 template<typename T,
2060 bool isDictionary=IsBaseOf<DictionaryBase, T>::value,
2061 bool isTypedArray=IsBaseOf<AllTypedArraysBase, T>::value,
2062 bool isOwningUnion=IsBaseOf<AllOwningUnionBase, T>::value>
2063 class SequenceTracer
2065 explicit SequenceTracer() = delete; // Should never be instantiated
2068 // sequence<object> or sequence<object?>
2069 template<>
2070 class SequenceTracer<JSObject*, false, false, false>
2072 explicit SequenceTracer() = delete; // Should never be instantiated
2074 public:
2075 static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
2076 for (; objp != end; ++objp) {
2077 JS_CallUnbarrieredObjectTracer(trc, objp, "sequence<object>");
2082 // sequence<any>
2083 template<>
2084 class SequenceTracer<JS::Value, false, false, false>
2086 explicit SequenceTracer() = delete; // Should never be instantiated
2088 public:
2089 static void TraceSequence(JSTracer* trc, JS::Value* valp, JS::Value* end) {
2090 for (; valp != end; ++valp) {
2091 JS_CallUnbarrieredValueTracer(trc, valp, "sequence<any>");
2096 // sequence<sequence<T>>
2097 template<typename T>
2098 class SequenceTracer<Sequence<T>, false, false, false>
2100 explicit SequenceTracer() = delete; // Should never be instantiated
2102 public:
2103 static void TraceSequence(JSTracer* trc, Sequence<T>* seqp, Sequence<T>* end) {
2104 for (; seqp != end; ++seqp) {
2105 DoTraceSequence(trc, *seqp);
2110 // sequence<sequence<T>> as return value
2111 template<typename T>
2112 class SequenceTracer<nsTArray<T>, false, false, false>
2114 explicit SequenceTracer() = delete; // Should never be instantiated
2116 public:
2117 static void TraceSequence(JSTracer* trc, nsTArray<T>* seqp, nsTArray<T>* end) {
2118 for (; seqp != end; ++seqp) {
2119 DoTraceSequence(trc, *seqp);
2124 // sequence<someDictionary>
2125 template<typename T>
2126 class SequenceTracer<T, true, false, false>
2128 explicit SequenceTracer() = delete; // Should never be instantiated
2130 public:
2131 static void TraceSequence(JSTracer* trc, T* dictp, T* end) {
2132 for (; dictp != end; ++dictp) {
2133 dictp->TraceDictionary(trc);
2138 // sequence<SomeTypedArray>
2139 template<typename T>
2140 class SequenceTracer<T, false, true, false>
2142 explicit SequenceTracer() = delete; // Should never be instantiated
2144 public:
2145 static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
2146 for (; arrayp != end; ++arrayp) {
2147 arrayp->TraceSelf(trc);
2152 // sequence<SomeOwningUnion>
2153 template<typename T>
2154 class SequenceTracer<T, false, false, true>
2156 explicit SequenceTracer() = delete; // Should never be instantiated
2158 public:
2159 static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
2160 for (; arrayp != end; ++arrayp) {
2161 arrayp->TraceUnion(trc);
2166 // sequence<T?> with T? being a Nullable<T>
2167 template<typename T>
2168 class SequenceTracer<Nullable<T>, false, false, false>
2170 explicit SequenceTracer() = delete; // Should never be instantiated
2172 public:
2173 static void TraceSequence(JSTracer* trc, Nullable<T>* seqp,
2174 Nullable<T>* end) {
2175 for (; seqp != end; ++seqp) {
2176 if (!seqp->IsNull()) {
2177 // Pretend like we actually have a length-one sequence here so
2178 // we can do template instantiation correctly for T.
2179 T& val = seqp->Value();
2180 T* ptr = &val;
2181 SequenceTracer<T>::TraceSequence(trc, ptr, ptr+1);
2187 // XXXbz It's not clear whether it's better to add a pldhash dependency here
2188 // (for PLDHashOperator) or add a BindingUtils.h dependency (for
2189 // SequenceTracer) to MozMap.h...
2190 template<typename T>
2191 static PLDHashOperator
2192 TraceMozMapValue(T* aValue, void* aClosure)
2194 JSTracer* trc = static_cast<JSTracer*>(aClosure);
2195 // Act like it's a one-element sequence to leverage all that infrastructure.
2196 SequenceTracer<T>::TraceSequence(trc, aValue, aValue + 1);
2197 return PL_DHASH_NEXT;
2200 template<typename T>
2201 void TraceMozMap(JSTracer* trc, MozMap<T>& map)
2203 map.EnumerateValues(TraceMozMapValue<T>, trc);
2206 // sequence<MozMap>
2207 template<typename T>
2208 class SequenceTracer<MozMap<T>, false, false, false>
2210 explicit SequenceTracer() = delete; // Should never be instantiated
2212 public:
2213 static void TraceSequence(JSTracer* trc, MozMap<T>* seqp, MozMap<T>* end) {
2214 for (; seqp != end; ++seqp) {
2215 seqp->EnumerateValues(TraceMozMapValue<T>, trc);
2220 template<typename T>
2221 void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq)
2223 SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
2224 seq.Elements() + seq.Length());
2227 template<typename T>
2228 void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq)
2230 SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
2231 seq.Elements() + seq.Length());
2234 // Rooter class for sequences; this is what we mostly use in the codegen
2235 template<typename T>
2236 class MOZ_STACK_CLASS SequenceRooter : private JS::CustomAutoRooter
2238 public:
2239 SequenceRooter(JSContext *aCx, FallibleTArray<T>* aSequence
2240 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2241 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2242 mFallibleArray(aSequence),
2243 mSequenceType(eFallibleArray)
2247 SequenceRooter(JSContext *aCx, InfallibleTArray<T>* aSequence
2248 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2249 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2250 mInfallibleArray(aSequence),
2251 mSequenceType(eInfallibleArray)
2255 SequenceRooter(JSContext *aCx, Nullable<nsTArray<T> >* aSequence
2256 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2257 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2258 mNullableArray(aSequence),
2259 mSequenceType(eNullableArray)
2263 private:
2264 enum SequenceType {
2265 eInfallibleArray,
2266 eFallibleArray,
2267 eNullableArray
2270 virtual void trace(JSTracer *trc) MOZ_OVERRIDE
2272 if (mSequenceType == eFallibleArray) {
2273 DoTraceSequence(trc, *mFallibleArray);
2274 } else if (mSequenceType == eInfallibleArray) {
2275 DoTraceSequence(trc, *mInfallibleArray);
2276 } else {
2277 MOZ_ASSERT(mSequenceType == eNullableArray);
2278 if (!mNullableArray->IsNull()) {
2279 DoTraceSequence(trc, mNullableArray->Value());
2284 union {
2285 InfallibleTArray<T>* mInfallibleArray;
2286 FallibleTArray<T>* mFallibleArray;
2287 Nullable<nsTArray<T> >* mNullableArray;
2290 SequenceType mSequenceType;
2293 // Rooter class for MozMap; this is what we mostly use in the codegen.
2294 template<typename T>
2295 class MOZ_STACK_CLASS MozMapRooter : private JS::CustomAutoRooter
2297 public:
2298 MozMapRooter(JSContext *aCx, MozMap<T>* aMozMap
2299 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2300 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2301 mMozMap(aMozMap),
2302 mMozMapType(eMozMap)
2306 MozMapRooter(JSContext *aCx, Nullable<MozMap<T>>* aMozMap
2307 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2308 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2309 mNullableMozMap(aMozMap),
2310 mMozMapType(eNullableMozMap)
2314 private:
2315 enum MozMapType {
2316 eMozMap,
2317 eNullableMozMap
2320 virtual void trace(JSTracer *trc) MOZ_OVERRIDE
2322 if (mMozMapType == eMozMap) {
2323 TraceMozMap(trc, *mMozMap);
2324 } else {
2325 MOZ_ASSERT(mMozMapType == eNullableMozMap);
2326 if (!mNullableMozMap->IsNull()) {
2327 TraceMozMap(trc, mNullableMozMap->Value());
2332 union {
2333 MozMap<T>* mMozMap;
2334 Nullable<MozMap<T>>* mNullableMozMap;
2337 MozMapType mMozMapType;
2340 template<typename T>
2341 class MOZ_STACK_CLASS RootedUnion : public T,
2342 private JS::CustomAutoRooter
2344 public:
2345 explicit RootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
2346 T(),
2347 JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
2351 virtual void trace(JSTracer *trc) MOZ_OVERRIDE
2353 this->TraceUnion(trc);
2357 template<typename T>
2358 class MOZ_STACK_CLASS NullableRootedUnion : public Nullable<T>,
2359 private JS::CustomAutoRooter
2361 public:
2362 explicit NullableRootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
2363 Nullable<T>(),
2364 JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
2368 virtual void trace(JSTracer *trc) MOZ_OVERRIDE
2370 if (!this->IsNull()) {
2371 this->Value().TraceUnion(trc);
2376 inline bool
2377 IdEquals(jsid id, const char* string)
2379 return JSID_IS_STRING(id) &&
2380 JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
2383 inline bool
2384 AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector, const char* name)
2386 return vector.growBy(1) &&
2387 InternJSString(cx, *(vector[vector.length() - 1]).address(), name);
2390 // Implementation of the bits that XrayWrapper needs
2393 * This resolves operations, attributes and constants of the interfaces for obj.
2395 * wrapper is the Xray JS object.
2396 * obj is the target object of the Xray, a binding's instance object or a
2397 * interface or interface prototype object.
2399 bool
2400 XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
2401 JS::Handle<JSObject*> obj,
2402 JS::Handle<jsid> id,
2403 JS::MutableHandle<JSPropertyDescriptor> desc,
2404 bool& cacheOnHolder);
2407 * Define a property on obj through an Xray wrapper.
2409 * wrapper is the Xray JS object.
2410 * obj is the target object of the Xray, a binding's instance object or a
2411 * interface or interface prototype object.
2412 * defined will be set to true if a property was set as a result of this call.
2414 bool
2415 XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
2416 JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
2417 JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined);
2420 * Add to props the property keys of all indexed or named properties of obj and
2421 * operations, attributes and constants of the interfaces for obj.
2423 * wrapper is the Xray JS object.
2424 * obj is the target object of the Xray, a binding's instance object or a
2425 * interface or interface prototype object.
2426 * flags are JSITER_* flags.
2428 bool
2429 XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
2430 JS::Handle<JSObject*> obj,
2431 unsigned flags, JS::AutoIdVector& props);
2434 * Returns the prototype to use for an Xray for a DOM object, wrapped in cx's
2435 * compartment. This always returns the prototype that would be used for a DOM
2436 * object if we ignore any changes that might have been done to the prototype
2437 * chain by JS, the XBL code or plugins.
2439 * cx should be in the Xray's compartment.
2440 * obj is the target object of the Xray, a binding's instance object or an
2441 * interface or interface prototype object.
2443 inline bool
2444 XrayGetNativeProto(JSContext* cx, JS::Handle<JSObject*> obj,
2445 JS::MutableHandle<JSObject*> protop)
2447 JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
2449 JSAutoCompartment ac(cx, global);
2450 const DOMJSClass* domClass = GetDOMClass(obj);
2451 if (domClass) {
2452 ProtoHandleGetter protoGetter = domClass->mGetProto;
2453 if (protoGetter) {
2454 protop.set(protoGetter(cx, global));
2455 } else {
2456 protop.set(JS_GetObjectPrototype(cx, global));
2458 } else {
2459 const js::Class* clasp = js::GetObjectClass(obj);
2460 MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
2461 ProtoGetter protoGetter =
2462 DOMIfaceAndProtoJSClass::FromJSClass(clasp)->mGetParentProto;
2463 protop.set(protoGetter(cx, global));
2467 return JS_WrapObject(cx, protop);
2470 extern NativePropertyHooks sWorkerNativePropertyHooks;
2472 // We use one constructor JSNative to represent all DOM interface objects (so
2473 // we can easily detect when we need to wrap them in an Xray wrapper). We store
2474 // the real JSNative in the mNative member of a JSNativeHolder in the
2475 // CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction object for a
2476 // specific interface object. We also store the NativeProperties in the
2477 // JSNativeHolder.
2478 // Note that some interface objects are not yet a JSFunction but a normal
2479 // JSObject with a DOMJSClass, those do not use these slots.
2481 enum {
2482 CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT = 0
2485 bool
2486 Constructor(JSContext* cx, unsigned argc, JS::Value* vp);
2488 inline bool
2489 UseDOMXray(JSObject* obj)
2491 const js::Class* clasp = js::GetObjectClass(obj);
2492 return IsDOMClass(clasp) ||
2493 JS_IsNativeFunction(obj, Constructor) ||
2494 IsDOMIfaceAndProtoClass(clasp);
2497 #ifdef DEBUG
2498 inline bool
2499 HasConstructor(JSObject* obj)
2501 return JS_IsNativeFunction(obj, Constructor) ||
2502 js::GetObjectClass(obj)->construct;
2504 #endif
2506 // Transfer reference in ptr to smartPtr.
2507 template<class T>
2508 inline void
2509 Take(nsRefPtr<T>& smartPtr, T* ptr)
2511 smartPtr = dont_AddRef(ptr);
2514 // Transfer ownership of ptr to smartPtr.
2515 template<class T>
2516 inline void
2517 Take(nsAutoPtr<T>& smartPtr, T* ptr)
2519 smartPtr = ptr;
2522 inline void
2523 MustInheritFromNonRefcountedDOMObject(NonRefcountedDOMObject*)
2527 HAS_MEMBER(JSBindingFinalized)
2529 template<class T, bool hasCallback=HasJSBindingFinalizedMember<T>::Value>
2530 struct JSBindingFinalized
2532 static void Finalized(T* self)
2537 template<class T>
2538 struct JSBindingFinalized<T, true>
2540 static void Finalized(T* self)
2542 self->JSBindingFinalized();
2546 // Helpers for creating a const version of a type.
2547 template<typename T>
2548 const T& Constify(T& arg)
2550 return arg;
2553 // Helper for turning (Owning)NonNull<T> into T&
2554 template<typename T>
2555 T& NonNullHelper(T& aArg)
2557 return aArg;
2560 template<typename T>
2561 T& NonNullHelper(NonNull<T>& aArg)
2563 return aArg;
2566 template<typename T>
2567 const T& NonNullHelper(const NonNull<T>& aArg)
2569 return aArg;
2572 template<typename T>
2573 T& NonNullHelper(OwningNonNull<T>& aArg)
2575 return aArg;
2578 template<typename T>
2579 const T& NonNullHelper(const OwningNonNull<T>& aArg)
2581 return aArg;
2584 inline
2585 void NonNullHelper(NonNull<binding_detail::FakeString>& aArg)
2587 // This overload is here to make sure that we never end up applying
2588 // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
2589 // try to, it should fail to compile, since presumably the caller will try to
2590 // use our nonexistent return value.
2593 inline
2594 void NonNullHelper(const NonNull<binding_detail::FakeString>& aArg)
2596 // This overload is here to make sure that we never end up applying
2597 // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
2598 // try to, it should fail to compile, since presumably the caller will try to
2599 // use our nonexistent return value.
2602 inline
2603 void NonNullHelper(binding_detail::FakeString& aArg)
2605 // This overload is here to make sure that we never end up applying
2606 // NonNullHelper to a FakeString before we've constified it. If we
2607 // try to, it should fail to compile, since presumably the caller will try to
2608 // use our nonexistent return value.
2611 MOZ_ALWAYS_INLINE
2612 const nsAString& NonNullHelper(const binding_detail::FakeString& aArg)
2614 return aArg;
2617 // Reparent the wrapper of aObj to whatever its native now thinks its
2618 // parent should be.
2619 nsresult
2620 ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObj);
2623 * Used to implement the hasInstance hook of an interface object.
2625 * instance should not be a security wrapper.
2627 bool
2628 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
2629 JS::Handle<JSObject*> instance,
2630 bool* bp);
2631 bool
2632 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp,
2633 bool* bp);
2634 bool
2635 InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
2636 JS::Handle<JSObject*> instance,
2637 bool* bp);
2639 // Helper for lenient getters/setters to report to console. If this
2640 // returns false, we couldn't even get a global.
2641 bool
2642 ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj);
2644 inline JSObject*
2645 GetUnforgeableHolder(JSObject* aGlobal, prototypes::ID aId)
2647 ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(aGlobal);
2648 JSObject* interfaceProto = protoAndIfaceCache.EntrySlotMustExist(aId);
2649 return &js::GetReservedSlot(interfaceProto,
2650 DOM_INTERFACE_PROTO_SLOTS_BASE).toObject();
2653 // Given a JSObject* that represents the chrome side of a JS-implemented WebIDL
2654 // interface, get the nsIGlobalObject corresponding to the content side, if any.
2655 // A false return means an exception was thrown.
2656 bool
2657 GetContentGlobalForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
2658 nsIGlobalObject** global);
2660 void
2661 ConstructJSImplementation(JSContext* aCx, const char* aContractId,
2662 nsIGlobalObject* aGlobal,
2663 JS::MutableHandle<JSObject*> aObject,
2664 ErrorResult& aRv);
2666 already_AddRefed<nsIGlobalObject>
2667 ConstructJSImplementation(JSContext* aCx, const char* aContractId,
2668 const GlobalObject& aGlobal,
2669 JS::MutableHandle<JSObject*> aObject,
2670 ErrorResult& aRv);
2673 * Convert an nsCString to jsval, returning true on success.
2674 * These functions are intended for ByteString implementations.
2675 * As such, the string is not UTF-8 encoded. Any UTF8 strings passed to these
2676 * methods will be mangled.
2678 bool NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
2679 JS::MutableHandle<JS::Value> rval);
2680 inline bool ByteStringToJsval(JSContext *cx, const nsACString &str,
2681 JS::MutableHandle<JS::Value> rval)
2683 if (str.IsVoid()) {
2684 rval.setNull();
2685 return true;
2687 return NonVoidByteStringToJsval(cx, str, rval);
2690 template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
2691 struct PreserveWrapperHelper
2693 static void PreserveWrapper(T* aObject)
2695 aObject->PreserveWrapper(aObject, NS_CYCLE_COLLECTION_PARTICIPANT(T));
2699 template<class T>
2700 struct PreserveWrapperHelper<T, true>
2702 static void PreserveWrapper(T* aObject)
2704 aObject->PreserveWrapper(reinterpret_cast<nsISupports*>(aObject));
2708 template<class T>
2709 void PreserveWrapper(T* aObject)
2711 PreserveWrapperHelper<T>::PreserveWrapper(aObject);
2714 template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
2715 struct CastingAssertions
2717 static bool ToSupportsIsCorrect(T*)
2719 return true;
2721 static bool ToSupportsIsOnPrimaryInheritanceChain(T*, nsWrapperCache*)
2723 return true;
2727 template<class T>
2728 struct CastingAssertions<T, true>
2730 static bool ToSupportsIsCorrect(T* aObject)
2732 return ToSupports(aObject) == reinterpret_cast<nsISupports*>(aObject);
2734 static bool ToSupportsIsOnPrimaryInheritanceChain(T* aObject,
2735 nsWrapperCache* aCache)
2737 return reinterpret_cast<void*>(aObject) != aCache;
2741 template<class T>
2742 bool
2743 ToSupportsIsCorrect(T* aObject)
2745 return CastingAssertions<T>::ToSupportsIsCorrect(aObject);
2748 template<class T>
2749 bool
2750 ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache)
2752 return CastingAssertions<T>::ToSupportsIsOnPrimaryInheritanceChain(aObject,
2753 aCache);
2756 template<class T, template <typename> class SmartPtr,
2757 bool isISupports=IsBaseOf<nsISupports, T>::value>
2758 class DeferredFinalizer
2760 typedef nsTArray<SmartPtr<T> > SmartPtrArray;
2762 static void*
2763 AppendDeferredFinalizePointer(void* aData, void* aObject)
2765 SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
2766 if (!pointers) {
2767 pointers = new SmartPtrArray();
2770 T* self = static_cast<T*>(aObject);
2772 SmartPtr<T>* defer = pointers->AppendElement();
2773 Take(*defer, self);
2774 return pointers;
2776 static bool
2777 DeferredFinalize(uint32_t aSlice, void* aData)
2779 MOZ_ASSERT(aSlice > 0, "nonsensical/useless call with aSlice == 0");
2780 SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
2781 uint32_t oldLen = pointers->Length();
2782 if (oldLen < aSlice) {
2783 aSlice = oldLen;
2785 uint32_t newLen = oldLen - aSlice;
2786 pointers->RemoveElementsAt(newLen, aSlice);
2787 if (newLen == 0) {
2788 delete pointers;
2789 return true;
2791 return false;
2794 public:
2795 static void
2796 AddForDeferredFinalization(T* aObject)
2798 cyclecollector::DeferredFinalize(AppendDeferredFinalizePointer,
2799 DeferredFinalize, aObject);
2803 template<class T, template <typename> class SmartPtr>
2804 class DeferredFinalizer<T, SmartPtr, true>
2806 public:
2807 static void
2808 AddForDeferredFinalization(T* aObject)
2810 cyclecollector::DeferredFinalize(reinterpret_cast<nsISupports*>(aObject));
2814 template<class T, template <typename> class SmartPtr>
2815 static void
2816 AddForDeferredFinalization(T* aObject)
2818 DeferredFinalizer<T, SmartPtr>::AddForDeferredFinalization(aObject);
2821 // This returns T's CC participant if it participates in CC or null if it
2822 // doesn't. This also returns null for classes that don't inherit from
2823 // nsISupports (QI should be used to get the participant for those).
2824 template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
2825 class GetCCParticipant
2827 // Helper for GetCCParticipant for classes that participate in CC.
2828 template<class U>
2829 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2830 GetHelper(int, typename U::NS_CYCLE_COLLECTION_INNERCLASS* dummy=nullptr)
2832 return T::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant();
2834 // Helper for GetCCParticipant for classes that don't participate in CC.
2835 template<class U>
2836 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2837 GetHelper(double)
2839 return nullptr;
2842 public:
2843 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2844 Get()
2846 // Passing int() here will try to call the GetHelper that takes an int as
2847 // its firt argument. If T doesn't participate in CC then substitution for
2848 // the second argument (with a default value) will fail and because of
2849 // SFINAE the next best match (the variant taking a double) will be called.
2850 return GetHelper<T>(int());
2854 template<class T>
2855 class GetCCParticipant<T, true>
2857 public:
2858 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2859 Get()
2861 return nullptr;
2866 * Helper function for testing whether the given object comes from a
2867 * privileged app.
2869 bool
2870 IsInPrivilegedApp(JSContext* aCx, JSObject* aObj);
2873 * Helper function for testing whether the given object comes from a
2874 * certified app.
2876 bool
2877 IsInCertifiedApp(JSContext* aCx, JSObject* aObj);
2879 void
2880 FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
2882 bool
2883 ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
2884 JS::Handle<jsid> aId, bool* aResolvedp);
2886 bool
2887 EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj);
2889 template <class T>
2890 struct CreateGlobalOptions
2892 static MOZ_CONSTEXPR_VAR ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
2893 ProtoAndIfaceCache::NonWindowLike;
2894 // Intl API is broken and makes JS_InitStandardClasses fail intermittently,
2895 // see bug 934889.
2896 static MOZ_CONSTEXPR_VAR bool ForceInitStandardClassesToFalse = true;
2897 static void TraceGlobal(JSTracer* aTrc, JSObject* aObj)
2899 mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
2901 static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
2903 MOZ_ALWAYS_TRUE(TryPreserveWrapper(aGlobal));
2905 return true;
2909 template <>
2910 struct CreateGlobalOptions<nsGlobalWindow>
2912 static MOZ_CONSTEXPR_VAR ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
2913 ProtoAndIfaceCache::WindowLike;
2914 static MOZ_CONSTEXPR_VAR bool ForceInitStandardClassesToFalse = false;
2915 static void TraceGlobal(JSTracer* aTrc, JSObject* aObj);
2916 static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
2919 nsresult
2920 RegisterDOMNames();
2922 template <class T, ProtoHandleGetter GetProto>
2923 bool
2924 CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
2925 const JSClass* aClass, JS::CompartmentOptions& aOptions,
2926 JSPrincipals* aPrincipal, bool aInitStandardClasses,
2927 JS::MutableHandle<JSObject*> aGlobal)
2929 aOptions.setTrace(CreateGlobalOptions<T>::TraceGlobal);
2931 aGlobal.set(JS_NewGlobalObject(aCx, aClass, aPrincipal,
2932 JS::DontFireOnNewGlobalHook, aOptions));
2933 if (!aGlobal) {
2934 NS_WARNING("Failed to create global");
2935 return false;
2938 JSAutoCompartment ac(aCx, aGlobal);
2941 js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aNative));
2942 NS_ADDREF(aNative);
2944 aCache->SetWrapper(aGlobal);
2946 dom::AllocateProtoAndIfaceCache(aGlobal,
2947 CreateGlobalOptions<T>::ProtoAndIfaceCacheKind);
2949 if (!CreateGlobalOptions<T>::PostCreateGlobal(aCx, aGlobal)) {
2950 return false;
2954 if (aInitStandardClasses &&
2955 !CreateGlobalOptions<T>::ForceInitStandardClassesToFalse &&
2956 !JS_InitStandardClasses(aCx, aGlobal)) {
2957 NS_WARNING("Failed to init standard classes");
2958 return false;
2961 JS::Handle<JSObject*> proto = GetProto(aCx, aGlobal);
2962 if (!proto || !JS_SplicePrototype(aCx, aGlobal, proto)) {
2963 NS_WARNING("Failed to set proto");
2964 return false;
2967 return true;
2971 * Holds a jsid that is initialized to an interned string, with conversion to
2972 * Handle<jsid>.
2974 class InternedStringId
2976 jsid id;
2978 public:
2979 InternedStringId() : id(JSID_VOID) {}
2981 bool init(JSContext *cx, const char *string) {
2982 JSString* str = JS_InternString(cx, string);
2983 if (!str)
2984 return false;
2985 id = INTERNED_STRING_TO_JSID(cx, str);
2986 return true;
2989 operator const jsid& () {
2990 return id;
2993 operator JS::Handle<jsid> () {
2994 /* This is safe because we have interned the string. */
2995 return JS::Handle<jsid>::fromMarkedLocation(&id);
2999 bool
3000 GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp);
3002 bool
3003 GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp);
3005 bool
3006 GenericBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp);
3008 bool
3009 GenericPromiseReturningBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp);
3011 bool
3012 StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp);
3014 // ConvertExceptionToPromise should only be called when we have an error
3015 // condition (e.g. returned false from a JSAPI method). Note that there may be
3016 // no exception on cx, in which case this is an uncatchable failure that will
3017 // simply be propagated. Otherwise this method will attempt to convert the
3018 // exception to a Promise rejected with the exception that it will store in
3019 // rval.
3021 // promiseScope should be the scope in which the Promise should be created.
3022 bool
3023 ConvertExceptionToPromise(JSContext* cx,
3024 JSObject* promiseScope,
3025 JS::MutableHandle<JS::Value> rval);
3027 // While we wait for the outcome of spec discussions on whether properties for
3028 // DOM global objects live on the object or the prototype, we supply this one
3029 // place to switch the behaviour, so we can easily turn this off on branches.
3030 inline bool
3031 GlobalPropertiesAreOwn()
3033 return true;
3036 #ifdef DEBUG
3037 void
3038 AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
3039 JS::Handle<JS::Value> aValue);
3040 #endif
3042 // Returns true if aObj's global has any of the permissions named in aPermissions
3043 // set to nsIPermissionManager::ALLOW_ACTION. aPermissions must be null-terminated.
3044 bool
3045 CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
3047 //Returns true if page is being prerendered.
3048 bool
3049 CheckSafetyInPrerendering(JSContext* aCx, JSObject* aObj);
3051 bool
3052 CallerSubsumes(JSObject* aObject);
3054 MOZ_ALWAYS_INLINE bool
3055 CallerSubsumes(JS::Handle<JS::Value> aValue)
3057 if (!aValue.isObject()) {
3058 return true;
3060 return CallerSubsumes(&aValue.toObject());
3063 template<class T>
3064 inline bool
3065 WrappedJSToDictionary(JSContext* aCx, nsISupports* aObject, T& aDictionary)
3067 nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
3068 if (!wrappedObj) {
3069 return false;
3072 JS::Rooted<JSObject*> obj(aCx, wrappedObj->GetJSObject());
3073 if (!obj) {
3074 return false;
3077 JSAutoCompartment ac(aCx, obj);
3078 JS::Rooted<JS::Value> v(aCx, JS::ObjectValue(*obj));
3079 return aDictionary.Init(aCx, v);
3082 template<class T>
3083 inline bool
3084 WrappedJSToDictionary(nsISupports* aObject, T& aDictionary)
3086 nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
3087 NS_ENSURE_TRUE(wrappedObj, false);
3088 JS::Rooted<JSObject*> obj(CycleCollectedJSRuntime::Get()->Runtime(),
3089 wrappedObj->GetJSObject());
3090 NS_ENSURE_TRUE(obj, false);
3092 nsIGlobalObject* global = xpc::NativeGlobal(obj);
3093 NS_ENSURE_TRUE(global, false);
3095 // we need this AutoEntryScript here because the spec requires us to execute
3096 // getters when parsing a dictionary
3097 AutoEntryScript aes(global);
3098 aes.TakeOwnershipOfErrorReporting();
3100 JS::Rooted<JS::Value> v(aes.cx(), JS::ObjectValue(*obj));
3101 return aDictionary.Init(aes.cx(), v);
3105 template<class T, class S>
3106 inline nsRefPtr<T>
3107 StrongOrRawPtr(already_AddRefed<S>&& aPtr)
3109 return aPtr.template downcast<T>();
3112 template<class T>
3113 inline T*
3114 StrongOrRawPtr(T* aPtr)
3116 return aPtr;
3119 template<class T, template<typename> class SmartPtr, class S>
3120 inline void
3121 StrongOrRawPtr(SmartPtr<S>&& aPtr) = delete;
3123 inline
3124 JSObject*
3125 GetErrorPrototype(JSContext* aCx, JS::Handle<JSObject*> aForObj)
3127 return JS_GetErrorPrototype(aCx);
3130 } // namespace dom
3131 } // namespace mozilla
3133 #endif /* mozilla_dom_BindingUtils_h__ */