Merge m-c to fx-team.
[gecko.git] / dom / bindings / BindingUtils.h
blobc37b5efba87916f06e1ae2728b7e12720ca33b3e
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/Alignment.h"
13 #include "mozilla/Array.h"
14 #include "mozilla/dom/BindingDeclarations.h"
15 #include "mozilla/dom/CallbackObject.h"
16 #include "mozilla/dom/DOMJSClass.h"
17 #include "mozilla/dom/DOMJSProxyHandler.h"
18 #include "mozilla/dom/Exceptions.h"
19 #include "mozilla/dom/NonRefcountedDOMObject.h"
20 #include "mozilla/dom/Nullable.h"
21 #include "mozilla/dom/RootedDictionary.h"
22 #include "mozilla/dom/workers/Workers.h"
23 #include "mozilla/ErrorResult.h"
24 #include "mozilla/HoldDropJSObjects.h"
25 #include "mozilla/Likely.h"
26 #include "mozilla/Util.h"
27 #include "nsCycleCollector.h"
28 #include "nsIXPConnect.h"
29 #include "MainThreadUtils.h"
30 #include "nsTraceRefcnt.h"
31 #include "qsObjectHelper.h"
32 #include "xpcpublic.h"
33 #include "nsIVariant.h"
35 #include "nsWrapperCacheInlines.h"
37 class nsPIDOMWindow;
39 extern nsresult
40 xpc_qsUnwrapArgImpl(JSContext* cx, JS::Handle<JS::Value> v, const nsIID& iid, void** ppArg,
41 nsISupports** ppArgRef, JS::MutableHandle<JS::Value> vp);
43 namespace mozilla {
44 namespace dom {
46 struct SelfRef
48 SelfRef() : ptr(nullptr) {}
49 explicit SelfRef(nsISupports *p) : ptr(p) {}
50 ~SelfRef() { NS_IF_RELEASE(ptr); }
52 nsISupports* ptr;
55 /** Convert a jsval to an XPCOM pointer. */
56 template <class Interface, class StrongRefType>
57 inline nsresult
58 UnwrapArg(JSContext* cx, JS::Handle<JS::Value> v, Interface** ppArg,
59 StrongRefType** ppArgRef, JS::MutableHandle<JS::Value> vp)
61 nsISupports* argRef = *ppArgRef;
62 nsresult rv = xpc_qsUnwrapArgImpl(cx, v, NS_GET_TEMPLATE_IID(Interface),
63 reinterpret_cast<void**>(ppArg), &argRef,
64 vp);
65 *ppArgRef = static_cast<StrongRefType*>(argRef);
66 return rv;
69 inline const ErrNum
70 GetInvalidThisErrorForMethod(bool aSecurityError)
72 return aSecurityError ? MSG_METHOD_THIS_UNWRAPPING_DENIED :
73 MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
76 inline const ErrNum
77 GetInvalidThisErrorForGetter(bool aSecurityError)
79 return aSecurityError ? MSG_GETTER_THIS_UNWRAPPING_DENIED :
80 MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
83 inline const ErrNum
84 GetInvalidThisErrorForSetter(bool aSecurityError)
86 return aSecurityError ? MSG_SETTER_THIS_UNWRAPPING_DENIED :
87 MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
90 bool
91 ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
92 const ErrNum aErrorNumber,
93 const char* aInterfaceName);
95 inline bool
96 ThrowMethodFailedWithDetails(JSContext* cx, ErrorResult& rv,
97 const char* ifaceName,
98 const char* memberName,
99 bool reportJSContentExceptions = false)
101 if (rv.IsTypeError()) {
102 rv.ReportTypeError(cx);
103 return false;
105 if (rv.IsJSException()) {
106 if (reportJSContentExceptions) {
107 rv.ReportJSExceptionFromJSImplementation(cx);
108 } else {
109 rv.ReportJSException(cx);
111 return false;
113 if (rv.IsNotEnoughArgsError()) {
114 rv.ReportNotEnoughArgsError(cx, ifaceName, memberName);
116 return Throw(cx, rv.ErrorCode());
119 // Returns true if the JSClass is used for DOM objects.
120 inline bool
121 IsDOMClass(const JSClass* clasp)
123 return clasp->flags & JSCLASS_IS_DOMJSCLASS;
126 inline bool
127 IsDOMClass(const js::Class* clasp)
129 return IsDOMClass(Jsvalify(clasp));
132 // Returns true if the JSClass is used for DOM interface and interface
133 // prototype objects.
134 inline bool
135 IsDOMIfaceAndProtoClass(const JSClass* clasp)
137 return clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS;
140 inline bool
141 IsDOMIfaceAndProtoClass(const js::Class* clasp)
143 return IsDOMIfaceAndProtoClass(Jsvalify(clasp));
146 static_assert(DOM_OBJECT_SLOT == js::PROXY_PRIVATE_SLOT,
147 "js::PROXY_PRIVATE_SLOT doesn't match DOM_OBJECT_SLOT. "
148 "Expect bad things");
149 template <class T>
150 inline T*
151 UnwrapDOMObject(JSObject* obj)
153 MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)) || IsDOMProxy(obj),
154 "Don't pass non-DOM objects to this function");
156 JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
157 return static_cast<T*>(val.toPrivate());
160 inline const DOMClass*
161 GetDOMClass(JSObject* obj)
163 const js::Class* clasp = js::GetObjectClass(obj);
164 if (IsDOMClass(clasp)) {
165 return &DOMJSClass::FromJSClass(clasp)->mClass;
168 if (js::IsProxyClass(clasp)) {
169 js::BaseProxyHandler* handler = js::GetProxyHandler(obj);
170 if (handler->family() == ProxyFamily()) {
171 return &static_cast<DOMProxyHandler*>(handler)->mClass;
175 return nullptr;
178 inline nsISupports*
179 UnwrapDOMObjectToISupports(JSObject* aObject)
181 const DOMClass* clasp = GetDOMClass(aObject);
182 if (!clasp || !clasp->mDOMObjectIsISupports) {
183 return nullptr;
186 return UnwrapDOMObject<nsISupports>(aObject);
189 inline bool
190 IsDOMObject(JSObject* obj)
192 const js::Class* clasp = js::GetObjectClass(obj);
193 return IsDOMClass(clasp) || IsDOMProxy(obj, clasp);
196 #define UNWRAP_OBJECT(Interface, cx, obj, value) \
197 mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface, \
198 mozilla::dom::Interface##Binding::NativeType>(cx, obj, value)
200 // Some callers don't want to set an exception when unwrapping fails
201 // (for example, overload resolution uses unwrapping to tell what sort
202 // of thing it's looking at).
203 // U must be something that a T* can be assigned to (e.g. T* or an nsRefPtr<T>).
204 template <prototypes::ID PrototypeID, class T, typename U>
205 MOZ_ALWAYS_INLINE nsresult
206 UnwrapObject(JSContext* cx, JSObject* obj, U& value)
208 /* First check to see whether we have a DOM object */
209 const DOMClass* domClass = GetDOMClass(obj);
210 if (!domClass) {
211 /* Maybe we have a security wrapper or outer window? */
212 if (!js::IsWrapper(obj)) {
213 /* Not a DOM object, not a wrapper, just bail */
214 return NS_ERROR_XPC_BAD_CONVERT_JS;
217 obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
218 if (!obj) {
219 return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
221 MOZ_ASSERT(!js::IsWrapper(obj));
222 domClass = GetDOMClass(obj);
223 if (!domClass) {
224 /* We don't have a DOM object */
225 return NS_ERROR_XPC_BAD_CONVERT_JS;
229 /* This object is a DOM object. Double-check that it is safely
230 castable to T by checking whether it claims to inherit from the
231 class identified by protoID. */
232 if (domClass->mInterfaceChain[PrototypeTraits<PrototypeID>::Depth] ==
233 PrototypeID) {
234 value = UnwrapDOMObject<T>(obj);
235 return NS_OK;
238 /* It's the wrong sort of DOM object */
239 return NS_ERROR_XPC_BAD_CONVERT_JS;
242 inline bool
243 IsNotDateOrRegExp(JSContext* cx, JS::Handle<JSObject*> obj)
245 MOZ_ASSERT(obj);
246 return !JS_ObjectIsDate(cx, obj) && !JS_ObjectIsRegExp(cx, obj);
249 MOZ_ALWAYS_INLINE bool
250 IsArrayLike(JSContext* cx, JS::Handle<JSObject*> obj)
252 return IsNotDateOrRegExp(cx, obj);
255 MOZ_ALWAYS_INLINE bool
256 IsObjectValueConvertibleToDictionary(JSContext* cx,
257 JS::Handle<JS::Value> objVal)
259 JS::Rooted<JSObject*> obj(cx, &objVal.toObject());
260 return IsNotDateOrRegExp(cx, obj);
263 MOZ_ALWAYS_INLINE bool
264 IsConvertibleToDictionary(JSContext* cx, JS::Handle<JS::Value> val)
266 return val.isNullOrUndefined() ||
267 (val.isObject() && IsObjectValueConvertibleToDictionary(cx, val));
270 MOZ_ALWAYS_INLINE bool
271 IsConvertibleToCallbackInterface(JSContext* cx, JS::Handle<JSObject*> obj)
273 return IsNotDateOrRegExp(cx, obj);
276 // The items in the protoAndIfaceArray are indexed by the prototypes::id::ID and
277 // constructors::id::ID enums, in that order. The end of the prototype objects
278 // should be the start of the interface objects.
279 static_assert((size_t)constructors::id::_ID_Start ==
280 (size_t)prototypes::id::_ID_Count,
281 "Overlapping or discontiguous indexes.");
282 const size_t kProtoAndIfaceCacheCount = constructors::id::_ID_Count;
284 class ProtoAndIfaceArray : public Array<JS::Heap<JSObject*>, kProtoAndIfaceCacheCount>
286 public:
287 ProtoAndIfaceArray() {
288 MOZ_COUNT_CTOR(ProtoAndIfaceArray);
291 ~ProtoAndIfaceArray() {
292 MOZ_COUNT_DTOR(ProtoAndIfaceArray);
296 inline void
297 AllocateProtoAndIfaceCache(JSObject* obj)
299 MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
300 MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
302 ProtoAndIfaceArray* protoAndIfaceArray = new ProtoAndIfaceArray();
304 js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
305 JS::PrivateValue(protoAndIfaceArray));
308 inline void
309 TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
311 MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
313 if (!HasProtoAndIfaceArray(obj))
314 return;
315 ProtoAndIfaceArray& protoAndIfaceArray = *GetProtoAndIfaceArray(obj);
316 for (size_t i = 0; i < ArrayLength(protoAndIfaceArray); ++i) {
317 if (protoAndIfaceArray[i]) {
318 JS_CallHeapObjectTracer(trc, &protoAndIfaceArray[i], "protoAndIfaceArray[i]");
323 inline void
324 DestroyProtoAndIfaceCache(JSObject* obj)
326 MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
328 ProtoAndIfaceArray* protoAndIfaceArray = GetProtoAndIfaceArray(obj);
330 delete protoAndIfaceArray;
334 * Add constants to an object.
336 bool
337 DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
338 const ConstantSpec* cs);
340 struct JSNativeHolder
342 JSNative mNative;
343 const NativePropertyHooks* mPropertyHooks;
346 struct NamedConstructor
348 const char* mName;
349 const JSNativeHolder mHolder;
350 unsigned mNargs;
354 * Create a DOM interface object (if constructorClass is non-null) and/or a
355 * DOM interface prototype object (if protoClass is non-null).
357 * global is used as the parent of the interface object and the interface
358 * prototype object
359 * protoProto is the prototype to use for the interface prototype object.
360 * interfaceProto is the prototype to use for the interface object.
361 * protoClass is the JSClass to use for the interface prototype object.
362 * This is null if we should not create an interface prototype
363 * object.
364 * protoCache a pointer to a JSObject pointer where we should cache the
365 * interface prototype object. This must be null if protoClass is and
366 * vice versa.
367 * constructorClass is the JSClass to use for the interface object.
368 * This is null if we should not create an interface object or
369 * if it should be a function object.
370 * constructor holds the JSNative to back the interface object which should be a
371 * Function, unless constructorClass is non-null in which case it is
372 * ignored. If this is null and constructorClass is also null then
373 * we should not create an interface object at all.
374 * ctorNargs is the length of the constructor function; 0 if no constructor
375 * constructorCache a pointer to a JSObject pointer where we should cache the
376 * interface object. This must be null if both constructorClass
377 * and constructor are null, and non-null otherwise.
378 * domClass is the DOMClass of instance objects for this class. This can be
379 * null if this is not a concrete proto.
380 * properties contains the methods, attributes and constants to be defined on
381 * objects in any compartment.
382 * chromeProperties contains the methods, attributes and constants to be defined
383 * on objects in chrome compartments. This must be null if the
384 * interface doesn't have any ChromeOnly properties or if the
385 * object is being created in non-chrome compartment.
386 * defineOnGlobal controls whether properties should be defined on the given
387 * global for the interface object (if any) and named
388 * constructors (if any) for this interface. This can be
389 * false in situations where we want the properties to only
390 * appear on privileged Xrays but not on the unprivileged
391 * underlying global.
393 * At least one of protoClass, constructorClass or constructor should be
394 * non-null. If constructorClass or constructor are non-null, the resulting
395 * interface object will be defined on the given global with property name
396 * |name|, which must also be non-null.
398 void
399 CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
400 JS::Handle<JSObject*> protoProto,
401 const JSClass* protoClass, JS::Heap<JSObject*>* protoCache,
402 JS::Handle<JSObject*> interfaceProto,
403 const JSClass* constructorClass, const JSNativeHolder* constructor,
404 unsigned ctorNargs, const NamedConstructor* namedConstructors,
405 JS::Heap<JSObject*>* constructorCache, const DOMClass* domClass,
406 const NativeProperties* regularProperties,
407 const NativeProperties* chromeOnlyProperties,
408 const char* name, bool defineOnGlobal);
411 * Define the unforgeable attributes on an object.
413 bool
414 DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
415 const Prefable<const JSPropertySpec>* props);
417 bool
418 DefineWebIDLBindingPropertiesOnXPCObject(JSContext* cx,
419 JS::Handle<JSObject*> obj,
420 const NativeProperties* properties,
421 bool defineUnforgeableAttributes);
423 #ifdef _MSC_VER
424 #define HAS_MEMBER_CHECK(_name) \
425 template<typename V> static yes& Check(char (*)[(&V::_name == 0) + 1])
426 #else
427 #define HAS_MEMBER_CHECK(_name) \
428 template<typename V> static yes& Check(char (*)[sizeof(&V::_name) + 1])
429 #endif
431 #define HAS_MEMBER(_name) \
432 template<typename T> \
433 class Has##_name##Member { \
434 typedef char yes[1]; \
435 typedef char no[2]; \
436 HAS_MEMBER_CHECK(_name); \
437 template<typename V> static no& Check(...); \
439 public: \
440 static bool const Value = sizeof(Check<T>(nullptr)) == sizeof(yes); \
443 HAS_MEMBER(WrapObject)
445 // HasWrapObject<T>::Value will be true if T has a WrapObject member but it's
446 // not nsWrapperCache::WrapObject.
447 template<typename T>
448 struct HasWrapObject
450 private:
451 typedef char yes[1];
452 typedef char no[2];
453 typedef JSObject* (nsWrapperCache::*WrapObject)(JSContext*,
454 JS::Handle<JSObject*>);
455 template<typename U, U> struct SFINAE;
456 template <typename V> static no& Check(SFINAE<WrapObject, &V::WrapObject>*);
457 template <typename V> static yes& Check(...);
459 public:
460 static bool const Value = HasWrapObjectMember<T>::Value &&
461 sizeof(Check<T>(nullptr)) == sizeof(yes);
464 #ifdef DEBUG
465 template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
466 struct
467 CheckWrapperCacheCast
469 static bool Check()
471 return reinterpret_cast<uintptr_t>(
472 static_cast<nsWrapperCache*>(
473 reinterpret_cast<T*>(1))) == 1;
476 template <class T>
477 struct
478 CheckWrapperCacheCast<T, true>
480 static bool Check()
482 return true;
485 #endif
487 MOZ_ALWAYS_INLINE bool
488 CouldBeDOMBinding(void*)
490 return true;
493 MOZ_ALWAYS_INLINE bool
494 CouldBeDOMBinding(nsWrapperCache* aCache)
496 return aCache->IsDOMBinding();
499 // The DOM_OBJECT_SLOT_SOW slot contains a JS::ObjectValue which points to the
500 // cached system object wrapper (SOW) or JS::UndefinedValue if this class
501 // doesn't need SOWs.
503 inline const JS::Value&
504 GetSystemOnlyWrapperSlot(JSObject* obj)
506 MOZ_ASSERT(IsDOMClass(js::GetObjectJSClass(obj)) &&
507 !(js::GetObjectJSClass(obj)->flags & JSCLASS_DOM_GLOBAL));
508 return js::GetReservedSlot(obj, DOM_OBJECT_SLOT_SOW);
510 inline void
511 SetSystemOnlyWrapperSlot(JSObject* obj, const JS::Value& v)
513 MOZ_ASSERT(IsDOMClass(js::GetObjectJSClass(obj)) &&
514 !(js::GetObjectJSClass(obj)->flags & JSCLASS_DOM_GLOBAL));
515 js::SetReservedSlot(obj, DOM_OBJECT_SLOT_SOW, v);
518 inline bool
519 GetSameCompartmentWrapperForDOMBinding(JSObject*& obj)
521 const js::Class* clasp = js::GetObjectClass(obj);
522 if (dom::IsDOMClass(clasp)) {
523 if (!(clasp->flags & JSCLASS_DOM_GLOBAL)) {
524 JS::Value v = GetSystemOnlyWrapperSlot(obj);
525 if (v.isObject()) {
526 obj = &v.toObject();
529 return true;
531 return IsDOMProxy(obj, clasp);
534 inline void
535 SetSystemOnlyWrapper(JSObject* obj, nsWrapperCache* cache, JSObject& wrapper)
537 SetSystemOnlyWrapperSlot(obj, JS::ObjectValue(wrapper));
538 cache->SetHasSystemOnlyWrapper();
541 // Make sure to wrap the given string value into the right compartment, as
542 // needed.
543 MOZ_ALWAYS_INLINE
544 bool
545 MaybeWrapStringValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
547 MOZ_ASSERT(rval.isString());
548 JSString* str = rval.toString();
549 if (JS::GetGCThingZone(str) != js::GetContextZone(cx)) {
550 return JS_WrapValue(cx, rval);
552 return true;
555 // Make sure to wrap the given object value into the right compartment as
556 // needed. This will work correctly, but possibly slowly, on all objects.
557 MOZ_ALWAYS_INLINE
558 bool
559 MaybeWrapObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
561 MOZ_ASSERT(rval.isObject());
563 JSObject* obj = &rval.toObject();
564 if (js::GetObjectCompartment(obj) != js::GetContextCompartment(cx)) {
565 return JS_WrapValue(cx, rval);
568 // We're same-compartment, but even then we might need to wrap
569 // objects specially. Check for that.
570 if (GetSameCompartmentWrapperForDOMBinding(obj)) {
571 // We're a new-binding object, and "obj" now points to the right thing
572 rval.set(JS::ObjectValue(*obj));
573 return true;
576 // It's not a WebIDL object. But it might be an XPConnect one, in which case
577 // we may need to outerize here, so make sure to call JS_WrapValue.
578 return JS_WrapValue(cx, rval);
581 // Like MaybeWrapObjectValue, but also allows null
582 MOZ_ALWAYS_INLINE
583 bool
584 MaybeWrapObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
586 MOZ_ASSERT(rval.isObjectOrNull());
587 if (rval.isNull()) {
588 return true;
590 return MaybeWrapObjectValue(cx, rval);
593 // Wrapping for objects that are known to not be DOM or XPConnect objects
594 MOZ_ALWAYS_INLINE
595 bool
596 MaybeWrapNonDOMObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
598 MOZ_ASSERT(rval.isObject());
599 MOZ_ASSERT(!GetDOMClass(&rval.toObject()));
600 MOZ_ASSERT(!(js::GetObjectClass(&rval.toObject())->flags &
601 JSCLASS_PRIVATE_IS_NSISUPPORTS));
603 JSObject* obj = &rval.toObject();
604 if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) {
605 return true;
607 return JS_WrapValue(cx, rval);
610 // Like MaybeWrapNonDOMObjectValue but allows null
611 MOZ_ALWAYS_INLINE
612 bool
613 MaybeWrapNonDOMObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
615 MOZ_ASSERT(rval.isObjectOrNull());
616 if (rval.isNull()) {
617 return true;
619 return MaybeWrapNonDOMObjectValue(cx, rval);
622 // If rval is a gcthing and is not in the compartment of cx, wrap rval
623 // into the compartment of cx (typically by replacing it with an Xray or
624 // cross-compartment wrapper around the original object).
625 MOZ_ALWAYS_INLINE bool
626 MaybeWrapValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
628 if (rval.isString()) {
629 return MaybeWrapStringValue(cx, rval);
632 if (!rval.isObject()) {
633 return true;
636 return MaybeWrapObjectValue(cx, rval);
639 static inline void
640 WrapNewBindingForSameCompartment(JSContext* cx, JSObject* obj, void* value,
641 JS::MutableHandle<JS::Value> rval)
643 rval.set(JS::ObjectValue(*obj));
646 static inline void
647 WrapNewBindingForSameCompartment(JSContext* cx, JSObject* obj,
648 nsWrapperCache* value,
649 JS::MutableHandle<JS::Value> rval)
651 if (value->HasSystemOnlyWrapper()) {
652 rval.set(GetSystemOnlyWrapperSlot(obj));
653 MOZ_ASSERT(rval.isObject());
654 } else {
655 rval.set(JS::ObjectValue(*obj));
659 // Create a JSObject wrapping "value", if there isn't one already, and store it
660 // in rval. "value" must be a concrete class that implements a
661 // GetWrapperPreserveColor() which can return its existing wrapper, if any, and
662 // a WrapObject() which will try to create a wrapper. Typically, this is done by
663 // having "value" inherit from nsWrapperCache.
664 template <class T>
665 MOZ_ALWAYS_INLINE bool
666 WrapNewBindingObject(JSContext* cx, JS::Handle<JSObject*> scope, T* value,
667 JS::MutableHandle<JS::Value> rval)
669 MOZ_ASSERT(value);
670 JSObject* obj = value->GetWrapperPreserveColor();
671 bool couldBeDOMBinding = CouldBeDOMBinding(value);
672 if (obj) {
673 JS::ExposeObjectToActiveJS(obj);
674 } else {
675 // Inline this here while we have non-dom objects in wrapper caches.
676 if (!couldBeDOMBinding) {
677 return false;
680 obj = value->WrapObject(cx, scope);
681 if (!obj) {
682 // At this point, obj is null, so just return false.
683 // Callers seem to be testing JS_IsExceptionPending(cx) to
684 // figure out whether WrapObject() threw.
685 return false;
689 #ifdef DEBUG
690 const DOMClass* clasp = GetDOMClass(obj);
691 // clasp can be null if the cache contained a non-DOM object from a
692 // different compartment than scope.
693 if (clasp) {
694 // Some sanity asserts about our object. Specifically:
695 // 1) If our class claims we're nsISupports, we better be nsISupports
696 // XXXbz ideally, we could assert that reinterpret_cast to nsISupports
697 // does the right thing, but I don't see a way to do it. :(
698 // 2) If our class doesn't claim we're nsISupports we better be
699 // reinterpret_castable to nsWrapperCache.
700 MOZ_ASSERT(clasp, "What happened here?");
701 MOZ_ASSERT_IF(clasp->mDOMObjectIsISupports, (IsBaseOf<nsISupports, T>::value));
702 MOZ_ASSERT(CheckWrapperCacheCast<T>::Check());
705 // When called via XrayWrapper, we end up here while running in the
706 // chrome compartment. But the obj we have would be created in
707 // whatever the content compartment is. So at this point we need to
708 // make sure it's correctly wrapped for the compartment of |scope|.
709 // cx should already be in the compartment of |scope| here.
710 MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
711 #endif
713 bool sameCompartment =
714 js::GetObjectCompartment(obj) == js::GetContextCompartment(cx);
715 if (sameCompartment && couldBeDOMBinding) {
716 WrapNewBindingForSameCompartment(cx, obj, value, rval);
717 return true;
720 rval.set(JS::ObjectValue(*obj));
721 return JS_WrapValue(cx, rval);
724 // Create a JSObject wrapping "value", for cases when "value" is a
725 // non-wrapper-cached object using WebIDL bindings. "value" must implement a
726 // WrapObject() method taking a JSContext and a scope.
727 template <class T>
728 inline bool
729 WrapNewBindingNonWrapperCachedObject(JSContext* cx,
730 JS::Handle<JSObject*> scopeArg,
731 T* value,
732 JS::MutableHandle<JS::Value> rval)
734 MOZ_ASSERT(value);
735 // We try to wrap in the compartment of the underlying object of "scope"
736 JS::Rooted<JSObject*> obj(cx);
738 // scope for the JSAutoCompartment so that we restore the compartment
739 // before we call JS_WrapValue.
740 Maybe<JSAutoCompartment> ac;
741 // Maybe<Handle> doesn't so much work, and in any case, adding
742 // more Maybe (one for a Rooted and one for a Handle) adds more
743 // code (and branches!) than just adding a single rooted.
744 JS::Rooted<JSObject*> scope(cx, scopeArg);
745 if (js::IsWrapper(scope)) {
746 scope = js::CheckedUnwrap(scope, /* stopAtOuter = */ false);
747 if (!scope)
748 return false;
749 ac.construct(cx, scope);
752 obj = value->WrapObject(cx, scope);
755 if (!obj) {
756 return false;
759 // We can end up here in all sorts of compartments, per above. Make
760 // sure to JS_WrapValue!
761 rval.set(JS::ObjectValue(*obj));
762 return JS_WrapValue(cx, rval);
765 // Create a JSObject wrapping "value", for cases when "value" is a
766 // non-wrapper-cached owned object using WebIDL bindings. "value" must implement a
767 // WrapObject() method taking a JSContext, a scope, and a boolean outparam that
768 // is true if the JSObject took ownership
769 template <class T>
770 inline bool
771 WrapNewBindingNonWrapperCachedOwnedObject(JSContext* cx,
772 JS::Handle<JSObject*> scopeArg,
773 nsAutoPtr<T>& value,
774 JS::MutableHandle<JS::Value> rval)
776 // We do a runtime check on value, because otherwise we might in
777 // fact end up wrapping a null and invoking methods on it later.
778 if (!value) {
779 NS_RUNTIMEABORT("Don't try to wrap null objects");
781 // We try to wrap in the compartment of the underlying object of "scope"
782 JS::Rooted<JSObject*> obj(cx);
784 // scope for the JSAutoCompartment so that we restore the compartment
785 // before we call JS_WrapValue.
786 Maybe<JSAutoCompartment> ac;
787 // Maybe<Handle> doesn't so much work, and in any case, adding
788 // more Maybe (one for a Rooted and one for a Handle) adds more
789 // code (and branches!) than just adding a single rooted.
790 JS::Rooted<JSObject*> scope(cx, scopeArg);
791 if (js::IsWrapper(scope)) {
792 scope = js::CheckedUnwrap(scope, /* stopAtOuter = */ false);
793 if (!scope)
794 return false;
795 ac.construct(cx, scope);
798 bool tookOwnership = false;
799 obj = value->WrapObject(cx, scope, &tookOwnership);
800 MOZ_ASSERT_IF(obj, tookOwnership);
801 if (tookOwnership) {
802 value.forget();
806 if (!obj) {
807 return false;
810 // We can end up here in all sorts of compartments, per above. Make
811 // sure to JS_WrapValue!
812 rval.set(JS::ObjectValue(*obj));
813 return JS_WrapValue(cx, rval);
816 // Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr).
817 template <template <typename> class SmartPtr, typename T>
818 inline bool
819 WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
820 const SmartPtr<T>& value,
821 JS::MutableHandle<JS::Value> rval)
823 return WrapNewBindingNonWrapperCachedObject(cx, scope, value.get(), rval);
826 // Only set allowNativeWrapper to false if you really know you need it, if in
827 // doubt use true. Setting it to false disables security wrappers.
828 bool
829 NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
830 JS::Handle<JSObject*> aScope,
831 JS::MutableHandle<JS::Value> aRetval,
832 xpcObjectHelper& aHelper,
833 const nsIID* aIID,
834 bool aAllowNativeWrapper);
837 * A method to handle new-binding wrap failure, by possibly falling back to
838 * wrapping as a non-new-binding object.
840 template <class T>
841 MOZ_ALWAYS_INLINE bool
842 HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
843 T* value, JS::MutableHandle<JS::Value> rval)
845 if (JS_IsExceptionPending(cx)) {
846 return false;
849 qsObjectHelper helper(value, GetWrapperCache(value));
850 return NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval,
851 helper, nullptr, true);
854 // Helper for calling HandleNewBindingWrappingFailure with smart pointers
855 // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
856 HAS_MEMBER(get)
858 template <class T, bool isSmartPtr=HasgetMember<T>::Value>
859 struct HandleNewBindingWrappingFailureHelper
861 static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
862 const T& value, JS::MutableHandle<JS::Value> rval)
864 return HandleNewBindingWrappingFailure(cx, scope, value.get(), rval);
868 template <class T>
869 struct HandleNewBindingWrappingFailureHelper<T, false>
871 static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope, T& value,
872 JS::MutableHandle<JS::Value> rval)
874 return HandleNewBindingWrappingFailure(cx, scope, &value, rval);
878 template<class T>
879 inline bool
880 HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
881 T& value, JS::MutableHandle<JS::Value> rval)
883 return HandleNewBindingWrappingFailureHelper<T>::Wrap(cx, scope, value, rval);
886 template<bool Fatal>
887 inline bool
888 EnumValueNotFound(JSContext* cx, const jschar* chars, size_t length,
889 const char* type, const char* sourceDescription)
891 return false;
894 template<>
895 inline bool
896 EnumValueNotFound<false>(JSContext* cx, const jschar* chars, size_t length,
897 const char* type, const char* sourceDescription)
899 // TODO: Log a warning to the console.
900 return true;
903 template<>
904 inline bool
905 EnumValueNotFound<true>(JSContext* cx, const jschar* chars, size_t length,
906 const char* type, const char* sourceDescription)
908 NS_LossyConvertUTF16toASCII deflated(static_cast<const PRUnichar*>(chars),
909 length);
910 return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
911 deflated.get(), type);
915 template<bool InvalidValueFatal>
916 inline int
917 FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* values,
918 const char* type, const char* sourceDescription, bool* ok)
920 // JS_StringEqualsAscii is slow as molasses, so don't use it here.
921 JSString* str = JS::ToString(cx, v);
922 if (!str) {
923 *ok = false;
924 return 0;
926 JS::Anchor<JSString*> anchor(str);
927 size_t length;
928 const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
929 if (!chars) {
930 *ok = false;
931 return 0;
933 int i = 0;
934 for (const EnumEntry* value = values; value->value; ++value, ++i) {
935 if (length != value->length) {
936 continue;
939 bool equal = true;
940 const char* val = value->value;
941 for (size_t j = 0; j != length; ++j) {
942 if (unsigned(val[j]) != unsigned(chars[j])) {
943 equal = false;
944 break;
948 if (equal) {
949 *ok = true;
950 return i;
954 *ok = EnumValueNotFound<InvalidValueFatal>(cx, chars, length, type,
955 sourceDescription);
956 return -1;
959 inline nsWrapperCache*
960 GetWrapperCache(const ParentObject& aParentObject)
962 return aParentObject.mWrapperCache;
965 template<class T>
966 inline T*
967 GetParentPointer(T* aObject)
969 return aObject;
972 inline nsISupports*
973 GetParentPointer(const ParentObject& aObject)
975 return aObject.mObject;
978 template<class T>
979 inline void
980 ClearWrapper(T* p, nsWrapperCache* cache)
982 cache->ClearWrapper();
985 template<class T>
986 inline void
987 ClearWrapper(T* p, void*)
989 nsWrapperCache* cache;
990 CallQueryInterface(p, &cache);
991 ClearWrapper(p, cache);
994 // Attempt to preserve the wrapper, if any, for a Paris DOM bindings object.
995 // Return true if we successfully preserved the wrapper, or there is no wrapper
996 // to preserve. In the latter case we don't need to preserve the wrapper, because
997 // the object can only be obtained by JS once, or they cannot be meaningfully
998 // owned from the native side.
1000 // This operation will return false only for non-nsISupports cycle-collected
1001 // objects, because we cannot determine if they are wrappercached or not.
1002 bool
1003 TryPreserveWrapper(JSObject* obj);
1005 // Can only be called with the immediate prototype of the instance object. Can
1006 // only be called on the prototype of an object known to be a DOM instance.
1007 bool
1008 InstanceClassHasProtoAtDepth(JSObject* protoObject, uint32_t protoID,
1009 uint32_t depth);
1011 // Only set allowNativeWrapper to false if you really know you need it, if in
1012 // doubt use true. Setting it to false disables security wrappers.
1013 bool
1014 XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
1015 xpcObjectHelper& helper, const nsIID* iid,
1016 bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval);
1018 // Special-cased wrapping for variants
1019 bool
1020 VariantToJsval(JSContext* aCx, JS::Handle<JSObject*> aScope,
1021 nsIVariant* aVariant, JS::MutableHandle<JS::Value> aRetval);
1023 // Wrap an object "p" which is not using WebIDL bindings yet. This _will_
1024 // actually work on WebIDL binding objects that are wrappercached, but will be
1025 // much slower than WrapNewBindingObject. "cache" must either be null or be the
1026 // nsWrapperCache for "p".
1027 template<class T>
1028 inline bool
1029 WrapObject(JSContext* cx, JS::Handle<JSObject*> scope, T* p,
1030 nsWrapperCache* cache, const nsIID* iid,
1031 JS::MutableHandle<JS::Value> rval)
1033 if (xpc_FastGetCachedWrapper(cache, scope, rval))
1034 return true;
1035 qsObjectHelper helper(p, cache);
1036 return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval);
1039 // A specialization of the above for nsIVariant, because that needs to
1040 // do something different.
1041 template<>
1042 inline bool
1043 WrapObject<nsIVariant>(JSContext* cx, JS::Handle<JSObject*> scope, nsIVariant* p,
1044 nsWrapperCache* cache, const nsIID* iid,
1045 JS::MutableHandle<JS::Value> rval)
1047 MOZ_ASSERT(iid);
1048 MOZ_ASSERT(iid->Equals(NS_GET_IID(nsIVariant)));
1049 return VariantToJsval(cx, scope, p, rval);
1052 // Wrap an object "p" which is not using WebIDL bindings yet. Just like the
1053 // variant that takes an nsWrapperCache above, but will try to auto-derive the
1054 // nsWrapperCache* from "p".
1055 template<class T>
1056 inline bool
1057 WrapObject(JSContext* cx, JS::Handle<JSObject*> scope, T* p, const nsIID* iid,
1058 JS::MutableHandle<JS::Value> rval)
1060 return WrapObject(cx, scope, p, GetWrapperCache(p), iid, rval);
1063 // Just like the WrapObject above, but without requiring you to pick which
1064 // interface you're wrapping as. This should only be used for objects that have
1065 // classinfo, for which it doesn't matter what IID is used to wrap.
1066 template<class T>
1067 inline bool
1068 WrapObject(JSContext* cx, JS::Handle<JSObject*> scope, T* p,
1069 JS::MutableHandle<JS::Value> rval)
1071 return WrapObject(cx, scope, p, nullptr, rval);
1074 // Helper to make it possible to wrap directly out of an nsCOMPtr
1075 template<class T>
1076 inline bool
1077 WrapObject(JSContext* cx, JS::Handle<JSObject*> scope, const nsCOMPtr<T>& p,
1078 const nsIID* iid, JS::MutableHandle<JS::Value> rval)
1080 return WrapObject(cx, scope, p.get(), iid, rval);
1083 // Helper to make it possible to wrap directly out of an nsCOMPtr
1084 template<class T>
1085 inline bool
1086 WrapObject(JSContext* cx, JS::Handle<JSObject*> scope, const nsCOMPtr<T>& p,
1087 JS::MutableHandle<JS::Value> rval)
1089 return WrapObject(cx, scope, p, nullptr, rval);
1092 // Helper to make it possible to wrap directly out of an nsRefPtr
1093 template<class T>
1094 inline bool
1095 WrapObject(JSContext* cx, JS::Handle<JSObject*> scope, const nsRefPtr<T>& p,
1096 const nsIID* iid, JS::MutableHandle<JS::Value> rval)
1098 return WrapObject(cx, scope, p.get(), iid, rval);
1101 // Helper to make it possible to wrap directly out of an nsRefPtr
1102 template<class T>
1103 inline bool
1104 WrapObject(JSContext* cx, JS::Handle<JSObject*> scope, const nsRefPtr<T>& p,
1105 JS::MutableHandle<JS::Value> rval)
1107 return WrapObject(cx, scope, p, nullptr, rval);
1110 // Specialization to make it easy to use WrapObject in codegen.
1111 template<>
1112 inline bool
1113 WrapObject<JSObject>(JSContext* cx, JS::Handle<JSObject*> scope, JSObject* p,
1114 JS::MutableHandle<JS::Value> rval)
1116 rval.set(JS::ObjectOrNullValue(p));
1117 return true;
1120 inline bool
1121 WrapObject(JSContext* cx, JS::Handle<JSObject*> scope, JSObject& p,
1122 JS::MutableHandle<JS::Value> rval)
1124 rval.set(JS::ObjectValue(p));
1125 return true;
1128 // Given an object "p" that inherits from nsISupports, wrap it and return the
1129 // result. Null is returned on wrapping failure. This is somewhat similar to
1130 // WrapObject() above, but does NOT allow Xrays around the result, since we
1131 // don't want those for our parent object.
1132 template<typename T>
1133 static inline JSObject*
1134 WrapNativeISupportsParent(JSContext* cx, JS::Handle<JSObject*> scope, T* p,
1135 nsWrapperCache* cache)
1137 qsObjectHelper helper(ToSupports(p), cache);
1138 JS::Rooted<JS::Value> v(cx);
1139 return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
1140 v.toObjectOrNull() :
1141 nullptr;
1145 // Fallback for when our parent is not a WebIDL binding object.
1146 template<typename T, bool isISupports=IsBaseOf<nsISupports, T>::value>
1147 struct WrapNativeParentFallback
1149 static inline JSObject* Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
1150 T* parent, nsWrapperCache* cache)
1152 return nullptr;
1156 // Fallback for when our parent is not a WebIDL binding object but _is_ an
1157 // nsISupports object.
1158 template<typename T >
1159 struct WrapNativeParentFallback<T, true >
1161 static inline JSObject* Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
1162 T* parent, nsWrapperCache* cache)
1164 return WrapNativeISupportsParent(cx, scope, parent, cache);
1168 // Wrapping of our native parent, for cases when it's a WebIDL object (though
1169 // possibly preffed off).
1170 template<typename T, bool hasWrapObject=HasWrapObject<T>::Value >
1171 struct WrapNativeParentHelper
1173 static inline JSObject* Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
1174 T* parent, nsWrapperCache* cache)
1176 MOZ_ASSERT(cache);
1178 JSObject* obj;
1179 if ((obj = cache->GetWrapper())) {
1180 return obj;
1183 // Inline this here while we have non-dom objects in wrapper caches.
1184 if (!CouldBeDOMBinding(parent)) {
1185 obj = WrapNativeParentFallback<T>::Wrap(cx, scope, parent, cache);
1186 } else {
1187 obj = parent->WrapObject(cx, scope);
1190 return obj;
1194 // Wrapping of our native parent, for cases when it's not a WebIDL object. In
1195 // this case it must be nsISupports.
1196 template<typename T>
1197 struct WrapNativeParentHelper<T, false >
1199 static inline JSObject* Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
1200 T* parent, nsWrapperCache* cache)
1202 JSObject* obj;
1203 if (cache && (obj = cache->GetWrapper())) {
1204 #ifdef DEBUG
1205 NS_ASSERTION(WrapNativeISupportsParent(cx, scope, parent, cache) == obj,
1206 "Unexpected object in nsWrapperCache");
1207 #endif
1208 return obj;
1211 return WrapNativeISupportsParent(cx, scope, parent, cache);
1215 // Wrapping of our native parent.
1216 template<typename T>
1217 static inline JSObject*
1218 WrapNativeParent(JSContext* cx, JS::Handle<JSObject*> scope, T* p,
1219 nsWrapperCache* cache)
1221 if (!p) {
1222 return scope;
1225 return WrapNativeParentHelper<T>::Wrap(cx, scope, p, cache);
1228 // Wrapping of our native parent, when we don't want to explicitly pass in
1229 // things like the nsWrapperCache for it.
1230 template<typename T>
1231 static inline JSObject*
1232 WrapNativeParent(JSContext* cx, JS::Handle<JSObject*> scope, const T& p)
1234 return WrapNativeParent(cx, scope, GetParentPointer(p), GetWrapperCache(p));
1237 // A way to differentiate between nodes, which use the parent object
1238 // returned by native->GetParentObject(), and all other objects, which
1239 // just use the parent's global.
1240 static inline JSObject*
1241 GetRealParentObject(void* aParent, JSObject* aParentObject)
1243 return aParentObject ?
1244 js::GetGlobalForObjectCrossCompartment(aParentObject) : nullptr;
1247 static inline JSObject*
1248 GetRealParentObject(Element* aParent, JSObject* aParentObject)
1250 return aParentObject;
1253 HAS_MEMBER(GetParentObject)
1255 template<typename T, bool WrapperCached=HasGetParentObjectMember<T>::Value>
1256 struct GetParentObject
1258 static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
1260 T* native = UnwrapDOMObject<T>(obj);
1261 return
1262 GetRealParentObject(native,
1263 WrapNativeParent(cx, obj, native->GetParentObject()));
1267 template<typename T>
1268 struct GetParentObject<T, false>
1270 static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
1272 MOZ_CRASH();
1273 return nullptr;
1277 MOZ_ALWAYS_INLINE
1278 JSObject* GetJSObjectFromCallback(CallbackObject* callback)
1280 return callback->Callback();
1283 MOZ_ALWAYS_INLINE
1284 JSObject* GetJSObjectFromCallback(void* noncallback)
1286 return nullptr;
1289 template<typename T>
1290 static inline JSObject*
1291 WrapCallThisObject(JSContext* cx, JS::Handle<JSObject*> scope, const T& p)
1293 // Callbacks are nsISupports, so WrapNativeParent will just happily wrap them
1294 // up as an nsISupports XPCWrappedNative... which is not at all what we want.
1295 // So we need to special-case them.
1296 JS::Rooted<JSObject*> obj(cx, GetJSObjectFromCallback(p));
1297 if (!obj) {
1298 // WrapNativeParent is a bit of a Swiss army knife that will
1299 // wrap anything for us.
1300 obj = WrapNativeParent(cx, scope, p);
1301 if (!obj) {
1302 return nullptr;
1306 // But all that won't necessarily put things in the compartment of cx.
1307 if (!JS_WrapObject(cx, &obj)) {
1308 return nullptr;
1311 return obj;
1314 // Helper for calling WrapNewBindingObject with smart pointers
1315 // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
1316 template <class T, bool isSmartPtr=HasgetMember<T>::Value>
1317 struct WrapNewBindingObjectHelper
1319 static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
1320 const T& value, JS::MutableHandle<JS::Value> rval)
1322 return WrapNewBindingObject(cx, scope, value.get(), rval);
1326 template <class T>
1327 struct WrapNewBindingObjectHelper<T, false>
1329 static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope, T& value,
1330 JS::MutableHandle<JS::Value> rval)
1332 return WrapNewBindingObject(cx, scope, &value, rval);
1336 template<class T>
1337 inline bool
1338 WrapNewBindingObject(JSContext* cx, JS::Handle<JSObject*> scope, T& value,
1339 JS::MutableHandle<JS::Value> rval)
1341 return WrapNewBindingObjectHelper<T>::Wrap(cx, scope, value, rval);
1344 template <class T>
1345 inline JSObject*
1346 GetCallbackFromCallbackObject(T* aObj)
1348 return aObj->Callback();
1351 // Helper for getting the callback JSObject* of a smart ptr around a
1352 // CallbackObject or a reference to a CallbackObject or something like
1353 // that.
1354 template <class T, bool isSmartPtr=HasgetMember<T>::Value>
1355 struct GetCallbackFromCallbackObjectHelper
1357 static inline JSObject* Get(const T& aObj)
1359 return GetCallbackFromCallbackObject(aObj.get());
1363 template <class T>
1364 struct GetCallbackFromCallbackObjectHelper<T, false>
1366 static inline JSObject* Get(T& aObj)
1368 return GetCallbackFromCallbackObject(&aObj);
1372 template<class T>
1373 inline JSObject*
1374 GetCallbackFromCallbackObject(T& aObj)
1376 return GetCallbackFromCallbackObjectHelper<T>::Get(aObj);
1379 static inline bool
1380 InternJSString(JSContext* cx, jsid& id, const char* chars)
1382 if (JSString *str = ::JS_InternString(cx, chars)) {
1383 id = INTERNED_STRING_TO_JSID(cx, str);
1384 return true;
1386 return false;
1389 // Spec needs a name property
1390 template <typename Spec>
1391 static bool
1392 InitIds(JSContext* cx, const Prefable<Spec>* prefableSpecs, jsid* ids)
1394 MOZ_ASSERT(prefableSpecs);
1395 MOZ_ASSERT(prefableSpecs->specs);
1396 do {
1397 // We ignore whether the set of ids is enabled and just intern all the IDs,
1398 // because this is only done once per application runtime.
1399 Spec* spec = prefableSpecs->specs;
1400 do {
1401 if (!InternJSString(cx, *ids, spec->name)) {
1402 return false;
1404 } while (++ids, (++spec)->name);
1406 // We ran out of ids for that pref. Put a JSID_VOID in on the id
1407 // corresponding to the list terminator for the pref.
1408 *ids = JSID_VOID;
1409 ++ids;
1410 } while ((++prefableSpecs)->specs);
1412 return true;
1415 bool
1416 QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
1418 template <class T>
1419 struct
1420 WantsQueryInterface
1422 static_assert(IsBaseOf<nsISupports, T>::value,
1423 "QueryInterface can't work without an nsISupports.");
1424 static bool Enabled(JSContext* aCx, JSObject* aGlobal)
1426 return NS_IsMainThread() && IsChromeOrXBL(aCx, aGlobal);
1430 bool
1431 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
1433 // vp is allowed to be null; in that case no get will be attempted,
1434 // and *found will simply indicate whether the property exists.
1435 bool
1436 GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
1437 JS::Handle<jsid> id, bool* found,
1438 JS::Value* vp);
1440 bool
1441 HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
1442 JS::Handle<jsid> id);
1445 // Append the property names in "names" to "props". If
1446 // shadowPrototypeProperties is false then skip properties that are also
1447 // present on the proto chain of proxy. If shadowPrototypeProperties is true,
1448 // then the "proxy" argument is ignored.
1449 bool
1450 AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
1451 nsTArray<nsString>& names,
1452 bool shadowPrototypeProperties, JS::AutoIdVector& props);
1454 // A struct that has the same layout as an nsDependentString but much
1455 // faster constructor and destructor behavior
1456 struct FakeDependentString {
1457 FakeDependentString() :
1458 mFlags(nsDependentString::F_TERMINATED)
1462 void SetData(const nsDependentString::char_type* aData,
1463 nsDependentString::size_type aLength) {
1464 MOZ_ASSERT(mFlags == nsDependentString::F_TERMINATED);
1465 mData = aData;
1466 mLength = aLength;
1469 void Truncate() {
1470 mData = nsDependentString::char_traits::sEmptyBuffer;
1471 mLength = 0;
1474 void SetNull() {
1475 Truncate();
1476 mFlags |= nsDependentString::F_VOIDED;
1479 const nsDependentString::char_type* Data() const
1481 return mData;
1484 nsDependentString::size_type Length() const
1486 return mLength;
1489 // If this ever changes, change the corresponding code in the
1490 // Optional<nsAString> specialization as well.
1491 const nsAString* ToAStringPtr() const {
1492 return reinterpret_cast<const nsDependentString*>(this);
1495 nsAString* ToAStringPtr() {
1496 return reinterpret_cast<nsDependentString*>(this);
1499 operator const nsAString& () const {
1500 return *reinterpret_cast<const nsDependentString*>(this);
1503 private:
1504 const nsDependentString::char_type* mData;
1505 nsDependentString::size_type mLength;
1506 uint32_t mFlags;
1508 // A class to use for our static asserts to ensure our object layout
1509 // matches that of nsDependentString.
1510 class DependentStringAsserter;
1511 friend class DependentStringAsserter;
1513 class DepedentStringAsserter : public nsDependentString {
1514 public:
1515 static void StaticAsserts() {
1516 static_assert(sizeof(FakeDependentString) == sizeof(nsDependentString),
1517 "Must have right object size");
1518 static_assert(offsetof(FakeDependentString, mData) ==
1519 offsetof(DepedentStringAsserter, mData),
1520 "Offset of mData should match");
1521 static_assert(offsetof(FakeDependentString, mLength) ==
1522 offsetof(DepedentStringAsserter, mLength),
1523 "Offset of mLength should match");
1524 static_assert(offsetof(FakeDependentString, mFlags) ==
1525 offsetof(DepedentStringAsserter, mFlags),
1526 "Offset of mFlags should match");
1531 enum StringificationBehavior {
1532 eStringify,
1533 eEmpty,
1534 eNull
1537 // pval must not be null and must point to a rooted JS::Value
1538 static inline bool
1539 ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
1540 JS::MutableHandle<JS::Value> pval,
1541 StringificationBehavior nullBehavior,
1542 StringificationBehavior undefinedBehavior,
1543 FakeDependentString& result)
1545 JSString *s;
1546 if (v.isString()) {
1547 s = v.toString();
1548 } else {
1549 StringificationBehavior behavior;
1550 if (v.isNull()) {
1551 behavior = nullBehavior;
1552 } else if (v.isUndefined()) {
1553 behavior = undefinedBehavior;
1554 } else {
1555 behavior = eStringify;
1558 if (behavior != eStringify) {
1559 if (behavior == eEmpty) {
1560 result.Truncate();
1561 } else {
1562 result.SetNull();
1564 return true;
1567 s = JS::ToString(cx, v);
1568 if (!s) {
1569 return false;
1571 pval.set(JS::StringValue(s)); // Root the new string.
1574 size_t len;
1575 const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
1576 if (!chars) {
1577 return false;
1580 result.SetData(chars, len);
1581 return true;
1584 bool
1585 ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
1586 JS::MutableHandle<JS::Value> pval, bool nullable,
1587 nsACString& result);
1589 template<typename T>
1590 void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
1591 template<typename T>
1592 void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
1594 // Class for simple sequence arguments, only used internally by codegen.
1595 template<typename T>
1596 class AutoSequence : public AutoFallibleTArray<T, 16>
1598 public:
1599 AutoSequence() : AutoFallibleTArray<T, 16>()
1602 // Allow converting to const sequences as needed
1603 operator const Sequence<T>&() const {
1604 return *reinterpret_cast<const Sequence<T>*>(this);
1608 // Class used to trace sequences, with specializations for various
1609 // sequence types.
1610 template<typename T,
1611 bool isDictionary=IsBaseOf<DictionaryBase, T>::value,
1612 bool isTypedArray=IsBaseOf<AllTypedArraysBase, T>::value>
1613 class SequenceTracer
1615 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1618 // sequence<object> or sequence<object?>
1619 template<>
1620 class SequenceTracer<JSObject*, false, false>
1622 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1624 public:
1625 static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
1626 for (; objp != end; ++objp) {
1627 JS_CallObjectTracer(trc, objp, "sequence<object>");
1632 // sequence<any>
1633 template<>
1634 class SequenceTracer<JS::Value, false, false>
1636 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1638 public:
1639 static void TraceSequence(JSTracer* trc, JS::Value* valp, JS::Value* end) {
1640 for (; valp != end; ++valp) {
1641 JS_CallValueTracer(trc, valp, "sequence<any>");
1646 // sequence<sequence<T>>
1647 template<typename T>
1648 class SequenceTracer<Sequence<T>, false, false>
1650 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1652 public:
1653 static void TraceSequence(JSTracer* trc, Sequence<T>* seqp, Sequence<T>* end) {
1654 for (; seqp != end; ++seqp) {
1655 DoTraceSequence(trc, *seqp);
1660 // sequence<sequence<T>> as return value
1661 template<typename T>
1662 class SequenceTracer<nsTArray<T>, false, false>
1664 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1666 public:
1667 static void TraceSequence(JSTracer* trc, nsTArray<T>* seqp, nsTArray<T>* end) {
1668 for (; seqp != end; ++seqp) {
1669 DoTraceSequence(trc, *seqp);
1674 // sequence<someDictionary>
1675 template<typename T>
1676 class SequenceTracer<T, true, false>
1678 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1680 public:
1681 static void TraceSequence(JSTracer* trc, T* dictp, T* end) {
1682 for (; dictp != end; ++dictp) {
1683 dictp->TraceDictionary(trc);
1688 // sequence<SomeTypedArray>
1689 template<typename T>
1690 class SequenceTracer<T, false, true>
1692 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1694 public:
1695 static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
1696 for (; arrayp != end; ++arrayp) {
1697 arrayp->TraceSelf(trc);
1702 // sequence<T?> with T? being a Nullable<T>
1703 template<typename T>
1704 class SequenceTracer<Nullable<T>, false, false>
1706 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1708 public:
1709 static void TraceSequence(JSTracer* trc, Nullable<T>* seqp,
1710 Nullable<T>* end) {
1711 for (; seqp != end; ++seqp) {
1712 if (!seqp->IsNull()) {
1713 // Pretend like we actually have a length-one sequence here so
1714 // we can do template instantiation correctly for T.
1715 T& val = seqp->Value();
1716 T* ptr = &val;
1717 SequenceTracer<T>::TraceSequence(trc, ptr, ptr+1);
1723 template<typename T>
1724 void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq)
1726 SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
1727 seq.Elements() + seq.Length());
1730 template<typename T>
1731 void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq)
1733 SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
1734 seq.Elements() + seq.Length());
1737 // Rooter class for sequences; this is what we mostly use in the codegen
1738 template<typename T>
1739 class MOZ_STACK_CLASS SequenceRooter : private JS::CustomAutoRooter
1741 public:
1742 SequenceRooter(JSContext *aCx, FallibleTArray<T>* aSequence
1743 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1744 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
1745 mFallibleArray(aSequence),
1746 mSequenceType(eFallibleArray)
1750 SequenceRooter(JSContext *aCx, InfallibleTArray<T>* aSequence
1751 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1752 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
1753 mInfallibleArray(aSequence),
1754 mSequenceType(eInfallibleArray)
1758 SequenceRooter(JSContext *aCx, Nullable<nsTArray<T> >* aSequence
1759 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1760 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
1761 mNullableArray(aSequence),
1762 mSequenceType(eNullableArray)
1766 private:
1767 enum SequenceType {
1768 eInfallibleArray,
1769 eFallibleArray,
1770 eNullableArray
1773 virtual void trace(JSTracer *trc) MOZ_OVERRIDE
1775 if (mSequenceType == eFallibleArray) {
1776 DoTraceSequence(trc, *mFallibleArray);
1777 } else if (mSequenceType == eInfallibleArray) {
1778 DoTraceSequence(trc, *mInfallibleArray);
1779 } else {
1780 MOZ_ASSERT(mSequenceType == eNullableArray);
1781 if (!mNullableArray->IsNull()) {
1782 DoTraceSequence(trc, mNullableArray->Value());
1787 union {
1788 InfallibleTArray<T>* mInfallibleArray;
1789 FallibleTArray<T>* mFallibleArray;
1790 Nullable<nsTArray<T> >* mNullableArray;
1793 SequenceType mSequenceType;
1796 template<typename T>
1797 class MOZ_STACK_CLASS RootedUnion : public T,
1798 private JS::CustomAutoRooter
1800 public:
1801 RootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
1802 T(),
1803 JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
1807 virtual void trace(JSTracer *trc) MOZ_OVERRIDE
1809 this->TraceUnion(trc);
1813 template<typename T>
1814 class MOZ_STACK_CLASS NullableRootedUnion : public Nullable<T>,
1815 private JS::CustomAutoRooter
1817 public:
1818 NullableRootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
1819 Nullable<T>(),
1820 JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
1824 virtual void trace(JSTracer *trc) MOZ_OVERRIDE
1826 if (!this->IsNull()) {
1827 this->Value().TraceUnion(trc);
1832 inline bool
1833 IdEquals(jsid id, const char* string)
1835 return JSID_IS_STRING(id) &&
1836 JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
1839 inline bool
1840 AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector, const char* name)
1842 return vector.growBy(1) &&
1843 InternJSString(cx, vector[vector.length() - 1], name);
1846 // Implementation of the bits that XrayWrapper needs
1849 * This resolves indexed or named properties of obj.
1851 * wrapper is the Xray JS object.
1852 * obj is the target object of the Xray, a binding's instance object or a
1853 * interface or interface prototype object.
1855 bool
1856 XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
1857 JS::Handle<JSObject*> obj,
1858 JS::Handle<jsid> id,
1859 JS::MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
1862 * This resolves operations, attributes and constants of the interfaces for obj.
1864 * wrapper is the Xray JS object.
1865 * obj is the target object of the Xray, a binding's instance object or a
1866 * interface or interface prototype object.
1868 bool
1869 XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
1870 JS::Handle<JSObject*> obj,
1871 JS::Handle<jsid> id, JS::MutableHandle<JSPropertyDescriptor> desc);
1874 * Define a property on obj through an Xray wrapper.
1876 * wrapper is the Xray JS object.
1877 * obj is the target object of the Xray, a binding's instance object or a
1878 * interface or interface prototype object.
1879 * defined will be set to true if a property was set as a result of this call.
1881 bool
1882 XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
1883 JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
1884 JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined);
1887 * This enumerates indexed or named properties of obj and operations, attributes
1888 * and constants of the interfaces for obj.
1890 * wrapper is the Xray JS object.
1891 * obj is the target object of the Xray, a binding's instance object or a
1892 * interface or interface prototype object.
1893 * flags are JSITER_* flags.
1895 bool
1896 XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
1897 JS::Handle<JSObject*> obj,
1898 unsigned flags, JS::AutoIdVector& props);
1900 extern NativePropertyHooks sWorkerNativePropertyHooks;
1902 // We use one constructor JSNative to represent all DOM interface objects (so
1903 // we can easily detect when we need to wrap them in an Xray wrapper). We store
1904 // the real JSNative in the mNative member of a JSNativeHolder in the
1905 // CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction object for a
1906 // specific interface object. We also store the NativeProperties in the
1907 // JSNativeHolder. The CONSTRUCTOR_XRAY_EXPANDO_SLOT is used to store the
1908 // expando chain of the Xray for the interface object.
1909 // Note that some interface objects are not yet a JSFunction but a normal
1910 // JSObject with a DOMJSClass, those do not use these slots.
1912 enum {
1913 CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT = 0,
1914 CONSTRUCTOR_XRAY_EXPANDO_SLOT
1917 bool
1918 Constructor(JSContext* cx, unsigned argc, JS::Value* vp);
1920 inline bool
1921 UseDOMXray(JSObject* obj)
1923 const js::Class* clasp = js::GetObjectClass(obj);
1924 return IsDOMClass(clasp) ||
1925 IsDOMProxy(obj, clasp) ||
1926 JS_IsNativeFunction(obj, Constructor) ||
1927 IsDOMIfaceAndProtoClass(clasp);
1930 #ifdef DEBUG
1931 inline bool
1932 HasConstructor(JSObject* obj)
1934 return JS_IsNativeFunction(obj, Constructor) ||
1935 js::GetObjectClass(obj)->construct;
1937 #endif
1939 // Transfer reference in ptr to smartPtr.
1940 template<class T>
1941 inline void
1942 Take(nsRefPtr<T>& smartPtr, T* ptr)
1944 smartPtr = dont_AddRef(ptr);
1947 // Transfer ownership of ptr to smartPtr.
1948 template<class T>
1949 inline void
1950 Take(nsAutoPtr<T>& smartPtr, T* ptr)
1952 smartPtr = ptr;
1955 inline void
1956 MustInheritFromNonRefcountedDOMObject(NonRefcountedDOMObject*)
1960 // Set the chain of expando objects for various consumers of the given object.
1961 // For Paris Bindings only. See the relevant infrastructure in XrayWrapper.cpp.
1962 JSObject* GetXrayExpandoChain(JSObject *obj);
1963 void SetXrayExpandoChain(JSObject *obj, JSObject *chain);
1966 * This creates a JSString containing the value that the toString function for
1967 * obj should create according to the WebIDL specification, ignoring any
1968 * modifications by script. The value is prefixed with pre and postfixed with
1969 * post, unless this is called for an object that has a stringifier. It is
1970 * specifically for use by Xray code.
1972 * wrapper is the Xray JS object.
1973 * obj is the target object of the Xray, a binding's instance object or a
1974 * interface or interface prototype object.
1975 * pre is a string that should be prefixed to the value.
1976 * post is a string that should be prefixed to the value.
1977 * v contains the JSString for the value if the function returns true.
1979 bool
1980 NativeToString(JSContext* cx, JS::Handle<JSObject*> wrapper,
1981 JS::Handle<JSObject*> obj, const char* pre,
1982 const char* post,
1983 JS::MutableHandle<JS::Value> v);
1985 HAS_MEMBER(JSBindingFinalized)
1987 template<class T, bool hasCallback=HasJSBindingFinalizedMember<T>::Value>
1988 struct JSBindingFinalized
1990 static void Finalized(T* self)
1995 template<class T>
1996 struct JSBindingFinalized<T, true>
1998 static void Finalized(T* self)
2000 self->JSBindingFinalized();
2004 // Helpers for creating a const version of a type.
2005 template<typename T>
2006 const T& Constify(T& arg)
2008 return arg;
2011 // Helper for turning (Owning)NonNull<T> into T&
2012 template<typename T>
2013 T& NonNullHelper(T& aArg)
2015 return aArg;
2018 template<typename T>
2019 T& NonNullHelper(NonNull<T>& aArg)
2021 return aArg;
2024 template<typename T>
2025 const T& NonNullHelper(const NonNull<T>& aArg)
2027 return aArg;
2030 template<typename T>
2031 T& NonNullHelper(OwningNonNull<T>& aArg)
2033 return aArg;
2036 template<typename T>
2037 const T& NonNullHelper(const OwningNonNull<T>& aArg)
2039 return aArg;
2042 // Reparent the wrapper of aObj to whatever its native now thinks its
2043 // parent should be.
2044 nsresult
2045 ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObj);
2048 * Used to implement the hasInstance hook of an interface object.
2050 * instance should not be a security wrapper.
2052 bool
2053 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
2054 JS::Handle<JSObject*> instance,
2055 bool* bp);
2056 bool
2057 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp,
2058 bool* bp);
2059 bool
2060 InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
2061 JS::Handle<JSObject*> instance,
2062 bool* bp);
2064 // Helper for lenient getters/setters to report to console. If this
2065 // returns false, we couldn't even get a global.
2066 bool
2067 ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj);
2069 inline JSObject*
2070 GetUnforgeableHolder(JSObject* aGlobal, prototypes::ID aId)
2072 ProtoAndIfaceArray& protoAndIfaceArray = *GetProtoAndIfaceArray(aGlobal);
2073 JSObject* interfaceProto = protoAndIfaceArray[aId];
2074 return &js::GetReservedSlot(interfaceProto,
2075 DOM_INTERFACE_PROTO_SLOTS_BASE).toObject();
2078 // Given a JSObject* that represents the chrome side of a JS-implemented WebIDL
2079 // interface, get the nsPIDOMWindow corresponding to the content side, if any.
2080 // A false return means an exception was thrown.
2081 bool
2082 GetWindowForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
2083 nsPIDOMWindow** window);
2085 already_AddRefed<nsPIDOMWindow>
2086 ConstructJSImplementation(JSContext* aCx, const char* aContractId,
2087 const GlobalObject& aGlobal,
2088 JS::MutableHandle<JSObject*> aObject,
2089 ErrorResult& aRv);
2092 * Convert an nsCString to jsval, returning true on success.
2093 * These functions are intended for ByteString implementations.
2094 * As such, the string is not UTF-8 encoded. Any UTF8 strings passed to these
2095 * methods will be mangled.
2097 bool NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
2098 JS::MutableHandle<JS::Value> rval);
2099 inline bool ByteStringToJsval(JSContext *cx, const nsACString &str,
2100 JS::MutableHandle<JS::Value> rval)
2102 if (str.IsVoid()) {
2103 rval.setNull();
2104 return true;
2106 return NonVoidByteStringToJsval(cx, str, rval);
2109 template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
2110 struct PreserveWrapperHelper
2112 static void PreserveWrapper(T* aObject)
2114 aObject->PreserveWrapper(aObject, NS_CYCLE_COLLECTION_PARTICIPANT(T));
2118 template<class T>
2119 struct PreserveWrapperHelper<T, true>
2121 static void PreserveWrapper(T* aObject)
2123 aObject->PreserveWrapper(reinterpret_cast<nsISupports*>(aObject));
2127 template<class T>
2128 void PreserveWrapper(T* aObject)
2130 PreserveWrapperHelper<T>::PreserveWrapper(aObject);
2133 template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
2134 struct CastingAssertions
2136 static bool ToSupportsIsCorrect(T*)
2138 return true;
2140 static bool ToSupportsIsOnPrimaryInheritanceChain(T*, nsWrapperCache*)
2142 return true;
2146 template<class T>
2147 struct CastingAssertions<T, true>
2149 static bool ToSupportsIsCorrect(T* aObject)
2151 return ToSupports(aObject) == reinterpret_cast<nsISupports*>(aObject);
2153 static bool ToSupportsIsOnPrimaryInheritanceChain(T* aObject,
2154 nsWrapperCache* aCache)
2156 return reinterpret_cast<void*>(aObject) != aCache;
2160 template<class T>
2161 bool
2162 ToSupportsIsCorrect(T* aObject)
2164 return CastingAssertions<T>::ToSupportsIsCorrect(aObject);
2167 template<class T>
2168 bool
2169 ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache)
2171 return CastingAssertions<T>::ToSupportsIsOnPrimaryInheritanceChain(aObject,
2172 aCache);
2175 template<class T, template <typename> class SmartPtr,
2176 bool isISupports=IsBaseOf<nsISupports, T>::value>
2177 class DeferredFinalizer
2179 typedef nsTArray<SmartPtr<T> > SmartPtrArray;
2181 static void*
2182 AppendDeferredFinalizePointer(void* aData, void* aObject)
2184 SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
2185 if (!pointers) {
2186 pointers = new SmartPtrArray();
2189 T* self = static_cast<T*>(aObject);
2191 SmartPtr<T>* defer = pointers->AppendElement();
2192 Take(*defer, self);
2193 return pointers;
2195 static bool
2196 DeferredFinalize(uint32_t aSlice, void* aData)
2198 MOZ_ASSERT(aSlice > 0, "nonsensical/useless call with aSlice == 0");
2199 SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
2200 uint32_t oldLen = pointers->Length();
2201 if (oldLen < aSlice) {
2202 aSlice = oldLen;
2204 uint32_t newLen = oldLen - aSlice;
2205 pointers->RemoveElementsAt(newLen, aSlice);
2206 if (newLen == 0) {
2207 delete pointers;
2208 return true;
2210 return false;
2213 public:
2214 static void
2215 AddForDeferredFinalization(T* aObject)
2217 cyclecollector::DeferredFinalize(AppendDeferredFinalizePointer,
2218 DeferredFinalize, aObject);
2222 template<class T, template <typename> class SmartPtr>
2223 class DeferredFinalizer<T, SmartPtr, true>
2225 public:
2226 static void
2227 AddForDeferredFinalization(T* aObject)
2229 cyclecollector::DeferredFinalize(reinterpret_cast<nsISupports*>(aObject));
2233 template<class T, template <typename> class SmartPtr>
2234 static void
2235 AddForDeferredFinalization(T* aObject)
2237 DeferredFinalizer<T, SmartPtr>::AddForDeferredFinalization(aObject);
2240 // This returns T's CC participant if it participates in CC or null if it
2241 // doesn't. This also returns null for classes that don't inherit from
2242 // nsISupports (QI should be used to get the participant for those).
2243 template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
2244 class GetCCParticipant
2246 // Helper for GetCCParticipant for classes that participate in CC.
2247 template<class U>
2248 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2249 GetHelper(int, typename U::NS_CYCLE_COLLECTION_INNERCLASS* dummy=nullptr)
2251 return T::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant();
2253 // Helper for GetCCParticipant for classes that don't participate in CC.
2254 template<class U>
2255 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2256 GetHelper(double)
2258 return nullptr;
2261 public:
2262 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2263 Get()
2265 // Passing int() here will try to call the GetHelper that takes an int as
2266 // its firt argument. If T doesn't participate in CC then substitution for
2267 // the second argument (with a default value) will fail and because of
2268 // SFINAE the next best match (the variant taking a double) will be called.
2269 return GetHelper<T>(int());
2273 template<class T>
2274 class GetCCParticipant<T, true>
2276 public:
2277 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2278 Get()
2280 return nullptr;
2284 bool
2285 ThreadsafeCheckIsChrome(JSContext* aCx, JSObject* aObj);
2287 void
2288 TraceGlobal(JSTracer* aTrc, JSObject* aObj);
2290 void
2291 FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
2293 bool
2294 ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
2295 JS::MutableHandle<jsid> aId, unsigned aFlags,
2296 JS::MutableHandle<JSObject*> aObjp);
2298 bool
2299 EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj);
2301 template <class T, JS::Handle<JSObject*> (*ProtoGetter)(JSContext*,
2302 JS::Handle<JSObject*>)>
2303 JSObject*
2304 CreateGlobal(JSContext* aCx, T* aObject, nsWrapperCache* aCache,
2305 const JSClass* aClass, JS::CompartmentOptions& aOptions,
2306 JSPrincipals* aPrincipal)
2308 MOZ_ASSERT(!NS_IsMainThread());
2310 JS::Rooted<JSObject*> global(aCx,
2311 JS_NewGlobalObject(aCx, aClass, aPrincipal, JS::DontFireOnNewGlobalHook,
2312 aOptions));
2313 if (!global) {
2314 NS_WARNING("Failed to create global");
2315 return nullptr;
2318 JSAutoCompartment ac(aCx, global);
2320 dom::AllocateProtoAndIfaceCache(global);
2322 js::SetReservedSlot(global, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
2323 NS_ADDREF(aObject);
2325 aCache->SetIsDOMBinding();
2326 aCache->SetWrapper(global);
2328 /* Intl API is broken and makes this fail intermittently, see bug 934889.
2329 if (!JS_InitStandardClasses(aCx, global)) {
2330 NS_WARNING("Failed to init standard classes");
2331 return nullptr;
2335 JS::Handle<JSObject*> proto = ProtoGetter(aCx, global);
2336 NS_ENSURE_TRUE(proto, nullptr);
2338 if (!JS_SetPrototype(aCx, global, proto)) {
2339 NS_WARNING("Failed to set proto");
2340 return nullptr;
2343 mozilla::HoldJSObjects(aObject);
2345 return global;
2348 } // namespace dom
2349 } // namespace mozilla
2351 #endif /* mozilla_dom_BindingUtils_h__ */