Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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/dom/BindingDeclarations.h"
16 #include "mozilla/dom/CallbackObject.h"
17 #include "mozilla/dom/DOMJSClass.h"
18 #include "mozilla/dom/DOMJSProxyHandler.h"
19 #include "mozilla/dom/Exceptions.h"
20 #include "mozilla/dom/NonRefcountedDOMObject.h"
21 #include "mozilla/dom/Nullable.h"
22 #include "mozilla/dom/RootedDictionary.h"
23 #include "mozilla/dom/workers/Workers.h"
24 #include "mozilla/ErrorResult.h"
25 #include "mozilla/Likely.h"
26 #include "mozilla/MemoryReporting.h"
27 #include "nsCycleCollector.h"
28 #include "nsIXPConnect.h"
29 #include "MainThreadUtils.h"
30 #include "nsISupportsImpl.h"
31 #include "qsObjectHelper.h"
32 #include "xpcpublic.h"
33 #include "nsIVariant.h"
34 #include "pldhash.h" // For PLDHashOperator
36 #include "nsWrapperCacheInlines.h"
38 class nsIJSID;
39 class nsPIDOMWindow;
41 extern nsresult
42 xpc_qsUnwrapArgImpl(JSContext* cx, JS::Handle<JS::Value> v, const nsIID& iid, void** ppArg,
43 nsISupports** ppArgRef, JS::MutableHandle<JS::Value> vp);
45 namespace mozilla {
46 namespace dom {
47 template<typename DataType> class MozMap;
49 struct SelfRef
50 {
51 SelfRef() : ptr(nullptr) {}
52 explicit SelfRef(nsISupports *p) : ptr(p) {}
53 ~SelfRef() { NS_IF_RELEASE(ptr); }
55 nsISupports* ptr;
56 };
58 /** Convert a jsval to an XPCOM pointer. */
59 template <class Interface, class StrongRefType>
60 inline nsresult
61 UnwrapArg(JSContext* cx, JS::Handle<JS::Value> v, Interface** ppArg,
62 StrongRefType** ppArgRef, JS::MutableHandle<JS::Value> vp)
63 {
64 nsISupports* argRef = *ppArgRef;
65 nsresult rv = xpc_qsUnwrapArgImpl(cx, v, NS_GET_TEMPLATE_IID(Interface),
66 reinterpret_cast<void**>(ppArg), &argRef,
67 vp);
68 *ppArgRef = static_cast<StrongRefType*>(argRef);
69 return rv;
70 }
72 inline const ErrNum
73 GetInvalidThisErrorForMethod(bool aSecurityError)
74 {
75 return aSecurityError ? MSG_METHOD_THIS_UNWRAPPING_DENIED :
76 MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
77 }
79 inline const ErrNum
80 GetInvalidThisErrorForGetter(bool aSecurityError)
81 {
82 return aSecurityError ? MSG_GETTER_THIS_UNWRAPPING_DENIED :
83 MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
84 }
86 inline const ErrNum
87 GetInvalidThisErrorForSetter(bool aSecurityError)
88 {
89 return aSecurityError ? MSG_SETTER_THIS_UNWRAPPING_DENIED :
90 MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
91 }
93 bool
94 ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
95 const ErrNum aErrorNumber,
96 const char* aInterfaceName);
98 bool
99 ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
100 const ErrNum aErrorNumber,
101 prototypes::ID aProtoId);
103 inline bool
104 ThrowMethodFailedWithDetails(JSContext* cx, ErrorResult& rv,
105 const char* ifaceName,
106 const char* memberName,
107 bool reportJSContentExceptions = false)
108 {
109 if (rv.IsTypeError()) {
110 rv.ReportTypeError(cx);
111 return false;
112 }
113 if (rv.IsJSException()) {
114 if (reportJSContentExceptions) {
115 rv.ReportJSExceptionFromJSImplementation(cx);
116 } else {
117 rv.ReportJSException(cx);
118 }
119 return false;
120 }
121 if (rv.IsNotEnoughArgsError()) {
122 rv.ReportNotEnoughArgsError(cx, ifaceName, memberName);
123 return false;
124 }
125 return Throw(cx, rv.ErrorCode());
126 }
128 // Returns true if the JSClass is used for DOM objects.
129 inline bool
130 IsDOMClass(const JSClass* clasp)
131 {
132 return clasp->flags & JSCLASS_IS_DOMJSCLASS;
133 }
135 inline bool
136 IsDOMClass(const js::Class* clasp)
137 {
138 return IsDOMClass(Jsvalify(clasp));
139 }
141 // Return true if the JSClass is used for non-proxy DOM objects.
142 inline bool
143 IsNonProxyDOMClass(const js::Class* clasp)
144 {
145 return IsDOMClass(clasp) && !clasp->isProxy();
146 }
148 inline bool
149 IsNonProxyDOMClass(const JSClass* clasp)
150 {
151 return IsNonProxyDOMClass(js::Valueify(clasp));
152 }
154 // Returns true if the JSClass is used for DOM interface and interface
155 // prototype objects.
156 inline bool
157 IsDOMIfaceAndProtoClass(const JSClass* clasp)
158 {
159 return clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS;
160 }
162 inline bool
163 IsDOMIfaceAndProtoClass(const js::Class* clasp)
164 {
165 return IsDOMIfaceAndProtoClass(Jsvalify(clasp));
166 }
168 static_assert(DOM_OBJECT_SLOT == js::PROXY_PRIVATE_SLOT,
169 "js::PROXY_PRIVATE_SLOT doesn't match DOM_OBJECT_SLOT. "
170 "Expect bad things");
171 template <class T>
172 inline T*
173 UnwrapDOMObject(JSObject* obj)
174 {
175 MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
176 "Don't pass non-DOM objects to this function");
178 JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
179 return static_cast<T*>(val.toPrivate());
180 }
182 inline const DOMClass*
183 GetDOMClass(JSObject* obj)
184 {
185 const js::Class* clasp = js::GetObjectClass(obj);
186 if (IsDOMClass(clasp)) {
187 return &DOMJSClass::FromJSClass(clasp)->mClass;
188 }
189 return nullptr;
190 }
192 inline nsISupports*
193 UnwrapDOMObjectToISupports(JSObject* aObject)
194 {
195 const DOMClass* clasp = GetDOMClass(aObject);
196 if (!clasp || !clasp->mDOMObjectIsISupports) {
197 return nullptr;
198 }
200 return UnwrapDOMObject<nsISupports>(aObject);
201 }
203 inline bool
204 IsDOMObject(JSObject* obj)
205 {
206 return IsDOMClass(js::GetObjectClass(obj));
207 }
209 #define UNWRAP_OBJECT(Interface, obj, value) \
210 mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface, \
211 mozilla::dom::Interface##Binding::NativeType>(obj, value)
213 // Some callers don't want to set an exception when unwrapping fails
214 // (for example, overload resolution uses unwrapping to tell what sort
215 // of thing it's looking at).
216 // U must be something that a T* can be assigned to (e.g. T* or an nsRefPtr<T>).
217 template <class T, typename U>
218 MOZ_ALWAYS_INLINE nsresult
219 UnwrapObject(JSObject* obj, U& value, prototypes::ID protoID,
220 uint32_t protoDepth)
221 {
222 /* First check to see whether we have a DOM object */
223 const DOMClass* domClass = GetDOMClass(obj);
224 if (!domClass) {
225 /* Maybe we have a security wrapper or outer window? */
226 if (!js::IsWrapper(obj)) {
227 /* Not a DOM object, not a wrapper, just bail */
228 return NS_ERROR_XPC_BAD_CONVERT_JS;
229 }
231 obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
232 if (!obj) {
233 return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
234 }
235 MOZ_ASSERT(!js::IsWrapper(obj));
236 domClass = GetDOMClass(obj);
237 if (!domClass) {
238 /* We don't have a DOM object */
239 return NS_ERROR_XPC_BAD_CONVERT_JS;
240 }
241 }
243 /* This object is a DOM object. Double-check that it is safely
244 castable to T by checking whether it claims to inherit from the
245 class identified by protoID. */
246 if (domClass->mInterfaceChain[protoDepth] == protoID) {
247 value = UnwrapDOMObject<T>(obj);
248 return NS_OK;
249 }
251 /* It's the wrong sort of DOM object */
252 return NS_ERROR_XPC_BAD_CONVERT_JS;
253 }
255 template <prototypes::ID PrototypeID, class T, typename U>
256 MOZ_ALWAYS_INLINE nsresult
257 UnwrapObject(JSObject* obj, U& value)
258 {
259 return UnwrapObject<T>(obj, value, PrototypeID,
260 PrototypeTraits<PrototypeID>::Depth);
261 }
263 inline bool
264 IsNotDateOrRegExp(JSContext* cx, JS::Handle<JSObject*> obj)
265 {
266 MOZ_ASSERT(obj);
267 return !JS_ObjectIsDate(cx, obj) && !JS_ObjectIsRegExp(cx, obj);
268 }
270 MOZ_ALWAYS_INLINE bool
271 IsObjectValueConvertibleToDictionary(JSContext* cx,
272 JS::Handle<JS::Value> objVal)
273 {
274 JS::Rooted<JSObject*> obj(cx, &objVal.toObject());
275 return IsNotDateOrRegExp(cx, obj);
276 }
278 MOZ_ALWAYS_INLINE bool
279 IsConvertibleToDictionary(JSContext* cx, JS::Handle<JS::Value> val)
280 {
281 return val.isNullOrUndefined() ||
282 (val.isObject() && IsObjectValueConvertibleToDictionary(cx, val));
283 }
285 MOZ_ALWAYS_INLINE bool
286 IsConvertibleToCallbackInterface(JSContext* cx, JS::Handle<JSObject*> obj)
287 {
288 return IsNotDateOrRegExp(cx, obj);
289 }
291 // The items in the protoAndIfaceCache are indexed by the prototypes::id::ID and
292 // constructors::id::ID enums, in that order. The end of the prototype objects
293 // should be the start of the interface objects.
294 static_assert((size_t)constructors::id::_ID_Start ==
295 (size_t)prototypes::id::_ID_Count,
296 "Overlapping or discontiguous indexes.");
297 const size_t kProtoAndIfaceCacheCount = constructors::id::_ID_Count;
299 class ProtoAndIfaceCache
300 {
301 // The caching strategy we use depends on what sort of global we're dealing
302 // with. For a window-like global, we want everything to be as fast as
303 // possible, so we use a flat array, indexed by prototype/constructor ID.
304 // For everything else (e.g. globals for JSMs), space is more important than
305 // speed, so we use a two-level lookup table.
307 class ArrayCache : public Array<JS::Heap<JSObject*>, kProtoAndIfaceCacheCount>
308 {
309 public:
310 JSObject* EntrySlotIfExists(size_t i) {
311 return (*this)[i];
312 }
314 JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
315 return (*this)[i];
316 }
318 JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
319 MOZ_ASSERT((*this)[i]);
320 return (*this)[i];
321 }
323 void Trace(JSTracer* aTracer) {
324 for (size_t i = 0; i < ArrayLength(*this); ++i) {
325 if ((*this)[i]) {
326 JS_CallHeapObjectTracer(aTracer, &(*this)[i], "protoAndIfaceCache[i]");
327 }
328 }
329 }
331 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
332 return aMallocSizeOf(this);
333 }
334 };
336 class PageTableCache
337 {
338 public:
339 PageTableCache() {
340 memset(&mPages, 0, sizeof(mPages));
341 }
343 ~PageTableCache() {
344 for (size_t i = 0; i < ArrayLength(mPages); ++i) {
345 delete mPages[i];
346 }
347 }
349 JSObject* EntrySlotIfExists(size_t i) {
350 MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
351 size_t pageIndex = i / kPageSize;
352 size_t leafIndex = i % kPageSize;
353 Page* p = mPages[pageIndex];
354 if (!p) {
355 return nullptr;
356 }
357 return (*p)[leafIndex];
358 }
360 JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
361 MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
362 size_t pageIndex = i / kPageSize;
363 size_t leafIndex = i % kPageSize;
364 Page* p = mPages[pageIndex];
365 if (!p) {
366 p = new Page;
367 mPages[pageIndex] = p;
368 }
369 return (*p)[leafIndex];
370 }
372 JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
373 MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
374 size_t pageIndex = i / kPageSize;
375 size_t leafIndex = i % kPageSize;
376 Page* p = mPages[pageIndex];
377 MOZ_ASSERT(p);
378 return (*p)[leafIndex];
379 }
381 void Trace(JSTracer* trc) {
382 for (size_t i = 0; i < ArrayLength(mPages); ++i) {
383 Page* p = mPages[i];
384 if (p) {
385 for (size_t j = 0; j < ArrayLength(*p); ++j) {
386 if ((*p)[j]) {
387 JS_CallHeapObjectTracer(trc, &(*p)[j], "protoAndIfaceCache[i]");
388 }
389 }
390 }
391 }
392 }
394 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
395 size_t n = aMallocSizeOf(this);
396 for (size_t i = 0; i < ArrayLength(mPages); ++i) {
397 n += aMallocSizeOf(mPages[i]);
398 }
399 return n;
400 }
402 private:
403 static const size_t kPageSize = 16;
404 typedef Array<JS::Heap<JSObject*>, kPageSize> Page;
405 static const size_t kNPages = kProtoAndIfaceCacheCount / kPageSize +
406 size_t(bool(kProtoAndIfaceCacheCount % kPageSize));
407 Array<Page*, kNPages> mPages;
408 };
410 public:
411 enum Kind {
412 WindowLike,
413 NonWindowLike
414 };
416 ProtoAndIfaceCache(Kind aKind) : mKind(aKind) {
417 MOZ_COUNT_CTOR(ProtoAndIfaceCache);
418 if (aKind == WindowLike) {
419 mArrayCache = new ArrayCache();
420 } else {
421 mPageTableCache = new PageTableCache();
422 }
423 }
425 ~ProtoAndIfaceCache() {
426 if (mKind == WindowLike) {
427 delete mArrayCache;
428 } else {
429 delete mPageTableCache;
430 }
431 MOZ_COUNT_DTOR(ProtoAndIfaceCache);
432 }
434 #define FORWARD_OPERATION(opName, args) \
435 do { \
436 if (mKind == WindowLike) { \
437 return mArrayCache->opName args; \
438 } else { \
439 return mPageTableCache->opName args; \
440 } \
441 } while(0)
443 JSObject* EntrySlotIfExists(size_t i) {
444 FORWARD_OPERATION(EntrySlotIfExists, (i));
445 }
447 JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
448 FORWARD_OPERATION(EntrySlotOrCreate, (i));
449 }
451 JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
452 FORWARD_OPERATION(EntrySlotMustExist, (i));
453 }
455 void Trace(JSTracer *aTracer) {
456 FORWARD_OPERATION(Trace, (aTracer));
457 }
459 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
460 size_t n = aMallocSizeOf(this);
461 n += (mKind == WindowLike
462 ? mArrayCache->SizeOfIncludingThis(aMallocSizeOf)
463 : mPageTableCache->SizeOfIncludingThis(aMallocSizeOf));
464 return n;
465 }
466 #undef FORWARD_OPERATION
468 private:
469 union {
470 ArrayCache *mArrayCache;
471 PageTableCache *mPageTableCache;
472 };
473 Kind mKind;
474 };
476 inline void
477 AllocateProtoAndIfaceCache(JSObject* obj, ProtoAndIfaceCache::Kind aKind)
478 {
479 MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
480 MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
482 ProtoAndIfaceCache* protoAndIfaceCache = new ProtoAndIfaceCache(aKind);
484 js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
485 JS::PrivateValue(protoAndIfaceCache));
486 }
488 inline void
489 TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
490 {
491 MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
493 if (!HasProtoAndIfaceCache(obj))
494 return;
495 ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
496 protoAndIfaceCache->Trace(trc);
497 }
499 inline void
500 DestroyProtoAndIfaceCache(JSObject* obj)
501 {
502 MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
504 ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
506 delete protoAndIfaceCache;
507 }
509 /**
510 * Add constants to an object.
511 */
512 bool
513 DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
514 const ConstantSpec* cs);
516 struct JSNativeHolder
517 {
518 JSNative mNative;
519 const NativePropertyHooks* mPropertyHooks;
520 };
522 struct NamedConstructor
523 {
524 const char* mName;
525 const JSNativeHolder mHolder;
526 unsigned mNargs;
527 };
529 /*
530 * Create a DOM interface object (if constructorClass is non-null) and/or a
531 * DOM interface prototype object (if protoClass is non-null).
532 *
533 * global is used as the parent of the interface object and the interface
534 * prototype object
535 * protoProto is the prototype to use for the interface prototype object.
536 * interfaceProto is the prototype to use for the interface object.
537 * protoClass is the JSClass to use for the interface prototype object.
538 * This is null if we should not create an interface prototype
539 * object.
540 * protoCache a pointer to a JSObject pointer where we should cache the
541 * interface prototype object. This must be null if protoClass is and
542 * vice versa.
543 * constructorClass is the JSClass to use for the interface object.
544 * This is null if we should not create an interface object or
545 * if it should be a function object.
546 * constructor holds the JSNative to back the interface object which should be a
547 * Function, unless constructorClass is non-null in which case it is
548 * ignored. If this is null and constructorClass is also null then
549 * we should not create an interface object at all.
550 * ctorNargs is the length of the constructor function; 0 if no constructor
551 * constructorCache a pointer to a JSObject pointer where we should cache the
552 * interface object. This must be null if both constructorClass
553 * and constructor are null, and non-null otherwise.
554 * domClass is the DOMClass of instance objects for this class. This can be
555 * null if this is not a concrete proto.
556 * properties contains the methods, attributes and constants to be defined on
557 * objects in any compartment.
558 * chromeProperties contains the methods, attributes and constants to be defined
559 * on objects in chrome compartments. This must be null if the
560 * interface doesn't have any ChromeOnly properties or if the
561 * object is being created in non-chrome compartment.
562 * defineOnGlobal controls whether properties should be defined on the given
563 * global for the interface object (if any) and named
564 * constructors (if any) for this interface. This can be
565 * false in situations where we want the properties to only
566 * appear on privileged Xrays but not on the unprivileged
567 * underlying global.
568 *
569 * At least one of protoClass, constructorClass or constructor should be
570 * non-null. If constructorClass or constructor are non-null, the resulting
571 * interface object will be defined on the given global with property name
572 * |name|, which must also be non-null.
573 */
574 void
575 CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
576 JS::Handle<JSObject*> protoProto,
577 const JSClass* protoClass, JS::Heap<JSObject*>* protoCache,
578 JS::Handle<JSObject*> interfaceProto,
579 const JSClass* constructorClass, const JSNativeHolder* constructor,
580 unsigned ctorNargs, const NamedConstructor* namedConstructors,
581 JS::Heap<JSObject*>* constructorCache, const DOMClass* domClass,
582 const NativeProperties* regularProperties,
583 const NativeProperties* chromeOnlyProperties,
584 const char* name, bool defineOnGlobal);
586 /*
587 * Define the unforgeable attributes on an object.
588 */
589 bool
590 DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
591 const Prefable<const JSPropertySpec>* props);
593 bool
594 DefineWebIDLBindingPropertiesOnXPCObject(JSContext* cx,
595 JS::Handle<JSObject*> obj,
596 const NativeProperties* properties,
597 bool defineUnforgeableAttributes);
599 #ifdef _MSC_VER
600 #define HAS_MEMBER_CHECK(_name) \
601 template<typename V> static yes& Check(char (*)[(&V::_name == 0) + 1])
602 #else
603 #define HAS_MEMBER_CHECK(_name) \
604 template<typename V> static yes& Check(char (*)[sizeof(&V::_name) + 1])
605 #endif
607 #define HAS_MEMBER(_name) \
608 template<typename T> \
609 class Has##_name##Member { \
610 typedef char yes[1]; \
611 typedef char no[2]; \
612 HAS_MEMBER_CHECK(_name); \
613 template<typename V> static no& Check(...); \
614 \
615 public: \
616 static bool const Value = sizeof(Check<T>(nullptr)) == sizeof(yes); \
617 };
619 HAS_MEMBER(WrapObject)
621 // HasWrapObject<T>::Value will be true if T has a WrapObject member but it's
622 // not nsWrapperCache::WrapObject.
623 template<typename T>
624 struct HasWrapObject
625 {
626 private:
627 typedef char yes[1];
628 typedef char no[2];
629 typedef JSObject* (nsWrapperCache::*WrapObject)(JSContext*,
630 JS::Handle<JSObject*>);
631 template<typename U, U> struct SFINAE;
632 template <typename V> static no& Check(SFINAE<WrapObject, &V::WrapObject>*);
633 template <typename V> static yes& Check(...);
635 public:
636 static bool const Value = HasWrapObjectMember<T>::Value &&
637 sizeof(Check<T>(nullptr)) == sizeof(yes);
638 };
640 #ifdef DEBUG
641 template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
642 struct
643 CheckWrapperCacheCast
644 {
645 static bool Check()
646 {
647 return reinterpret_cast<uintptr_t>(
648 static_cast<nsWrapperCache*>(
649 reinterpret_cast<T*>(1))) == 1;
650 }
651 };
652 template <class T>
653 struct
654 CheckWrapperCacheCast<T, true>
655 {
656 static bool Check()
657 {
658 return true;
659 }
660 };
661 #endif
663 MOZ_ALWAYS_INLINE bool
664 CouldBeDOMBinding(void*)
665 {
666 return true;
667 }
669 MOZ_ALWAYS_INLINE bool
670 CouldBeDOMBinding(nsWrapperCache* aCache)
671 {
672 return aCache->IsDOMBinding();
673 }
675 inline bool
676 TryToOuterize(JSContext* cx, JS::MutableHandle<JS::Value> rval)
677 {
678 if (js::IsInnerObject(&rval.toObject())) {
679 JS::Rooted<JSObject*> obj(cx, &rval.toObject());
680 obj = JS_ObjectToOuterObject(cx, obj);
681 if (!obj) {
682 return false;
683 }
685 rval.set(JS::ObjectValue(*obj));
686 }
688 return true;
689 }
691 // Make sure to wrap the given string value into the right compartment, as
692 // needed.
693 MOZ_ALWAYS_INLINE
694 bool
695 MaybeWrapStringValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
696 {
697 MOZ_ASSERT(rval.isString());
698 JSString* str = rval.toString();
699 if (JS::GetGCThingZone(str) != js::GetContextZone(cx)) {
700 return JS_WrapValue(cx, rval);
701 }
702 return true;
703 }
705 // Make sure to wrap the given object value into the right compartment as
706 // needed. This will work correctly, but possibly slowly, on all objects.
707 MOZ_ALWAYS_INLINE
708 bool
709 MaybeWrapObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
710 {
711 MOZ_ASSERT(rval.isObject());
713 // Cross-compartment always requires wrapping.
714 JSObject* obj = &rval.toObject();
715 if (js::GetObjectCompartment(obj) != js::GetContextCompartment(cx)) {
716 return JS_WrapValue(cx, rval);
717 }
719 // We're same-compartment, but even then we might need to wrap
720 // objects specially. Check for that.
721 if (IsDOMObject(obj)) {
722 return TryToOuterize(cx, rval);
723 }
725 // It's not a WebIDL object. But it might be an XPConnect one, in which case
726 // we may need to outerize here, so make sure to call JS_WrapValue.
727 return JS_WrapValue(cx, rval);
728 }
730 // Like MaybeWrapObjectValue, but also allows null
731 MOZ_ALWAYS_INLINE
732 bool
733 MaybeWrapObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
734 {
735 MOZ_ASSERT(rval.isObjectOrNull());
736 if (rval.isNull()) {
737 return true;
738 }
739 return MaybeWrapObjectValue(cx, rval);
740 }
742 // Wrapping for objects that are known to not be DOM or XPConnect objects
743 MOZ_ALWAYS_INLINE
744 bool
745 MaybeWrapNonDOMObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
746 {
747 MOZ_ASSERT(rval.isObject());
748 MOZ_ASSERT(!GetDOMClass(&rval.toObject()));
749 MOZ_ASSERT(!(js::GetObjectClass(&rval.toObject())->flags &
750 JSCLASS_PRIVATE_IS_NSISUPPORTS));
752 JSObject* obj = &rval.toObject();
753 if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) {
754 return true;
755 }
756 return JS_WrapValue(cx, rval);
757 }
759 // Like MaybeWrapNonDOMObjectValue but allows null
760 MOZ_ALWAYS_INLINE
761 bool
762 MaybeWrapNonDOMObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
763 {
764 MOZ_ASSERT(rval.isObjectOrNull());
765 if (rval.isNull()) {
766 return true;
767 }
768 return MaybeWrapNonDOMObjectValue(cx, rval);
769 }
771 // If rval is a gcthing and is not in the compartment of cx, wrap rval
772 // into the compartment of cx (typically by replacing it with an Xray or
773 // cross-compartment wrapper around the original object).
774 MOZ_ALWAYS_INLINE bool
775 MaybeWrapValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
776 {
777 if (rval.isString()) {
778 return MaybeWrapStringValue(cx, rval);
779 }
781 if (!rval.isObject()) {
782 return true;
783 }
785 return MaybeWrapObjectValue(cx, rval);
786 }
788 // Create a JSObject wrapping "value", if there isn't one already, and store it
789 // in rval. "value" must be a concrete class that implements a
790 // GetWrapperPreserveColor() which can return its existing wrapper, if any, and
791 // a WrapObject() which will try to create a wrapper. Typically, this is done by
792 // having "value" inherit from nsWrapperCache.
793 template <class T>
794 MOZ_ALWAYS_INLINE bool
795 WrapNewBindingObject(JSContext* cx, T* value, JS::MutableHandle<JS::Value> rval)
796 {
797 MOZ_ASSERT(value);
798 JSObject* obj = value->GetWrapperPreserveColor();
799 // We can get rid of this when we remove support for hasXPConnectImpls.
800 bool couldBeDOMBinding = CouldBeDOMBinding(value);
801 if (obj) {
802 JS::ExposeObjectToActiveJS(obj);
803 } else {
804 // Inline this here while we have non-dom objects in wrapper caches.
805 if (!couldBeDOMBinding) {
806 return false;
807 }
809 obj = value->WrapObject(cx);
810 if (!obj) {
811 // At this point, obj is null, so just return false.
812 // Callers seem to be testing JS_IsExceptionPending(cx) to
813 // figure out whether WrapObject() threw.
814 return false;
815 }
816 }
818 #ifdef DEBUG
819 const DOMClass* clasp = GetDOMClass(obj);
820 // clasp can be null if the cache contained a non-DOM object.
821 if (clasp) {
822 // Some sanity asserts about our object. Specifically:
823 // 1) If our class claims we're nsISupports, we better be nsISupports
824 // XXXbz ideally, we could assert that reinterpret_cast to nsISupports
825 // does the right thing, but I don't see a way to do it. :(
826 // 2) If our class doesn't claim we're nsISupports we better be
827 // reinterpret_castable to nsWrapperCache.
828 MOZ_ASSERT(clasp, "What happened here?");
829 MOZ_ASSERT_IF(clasp->mDOMObjectIsISupports, (IsBaseOf<nsISupports, T>::value));
830 MOZ_ASSERT(CheckWrapperCacheCast<T>::Check());
831 }
832 #endif
834 rval.set(JS::ObjectValue(*obj));
836 bool sameCompartment =
837 js::GetObjectCompartment(obj) == js::GetContextCompartment(cx);
838 if (sameCompartment && couldBeDOMBinding) {
839 // We only need to outerize Window objects, so anything inheriting from
840 // nsGlobalWindow (which inherits from EventTarget itself).
841 return IsBaseOf<nsGlobalWindow, T>::value || IsSame<EventTarget, T>::value ?
842 TryToOuterize(cx, rval) : true;
843 }
845 return JS_WrapValue(cx, rval);
846 }
848 // Create a JSObject wrapping "value", for cases when "value" is a
849 // non-wrapper-cached object using WebIDL bindings. "value" must implement a
850 // WrapObject() method taking a JSContext and a scope.
851 template <class T>
852 inline bool
853 WrapNewBindingNonWrapperCachedObject(JSContext* cx,
854 JS::Handle<JSObject*> scopeArg,
855 T* value,
856 JS::MutableHandle<JS::Value> rval)
857 {
858 MOZ_ASSERT(value);
859 // We try to wrap in the compartment of the underlying object of "scope"
860 JS::Rooted<JSObject*> obj(cx);
861 {
862 // scope for the JSAutoCompartment so that we restore the compartment
863 // before we call JS_WrapValue.
864 Maybe<JSAutoCompartment> ac;
865 // Maybe<Handle> doesn't so much work, and in any case, adding
866 // more Maybe (one for a Rooted and one for a Handle) adds more
867 // code (and branches!) than just adding a single rooted.
868 JS::Rooted<JSObject*> scope(cx, scopeArg);
869 if (js::IsWrapper(scope)) {
870 scope = js::CheckedUnwrap(scope, /* stopAtOuter = */ false);
871 if (!scope)
872 return false;
873 ac.construct(cx, scope);
874 }
876 MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
877 obj = value->WrapObject(cx);
878 }
880 if (!obj) {
881 return false;
882 }
884 // We can end up here in all sorts of compartments, per above. Make
885 // sure to JS_WrapValue!
886 rval.set(JS::ObjectValue(*obj));
887 return JS_WrapValue(cx, rval);
888 }
890 // Create a JSObject wrapping "value", for cases when "value" is a
891 // non-wrapper-cached owned object using WebIDL bindings. "value" must implement a
892 // WrapObject() method taking a JSContext, a scope, and a boolean outparam that
893 // is true if the JSObject took ownership
894 template <class T>
895 inline bool
896 WrapNewBindingNonWrapperCachedOwnedObject(JSContext* cx,
897 JS::Handle<JSObject*> scopeArg,
898 nsAutoPtr<T>& value,
899 JS::MutableHandle<JS::Value> rval)
900 {
901 // We do a runtime check on value, because otherwise we might in
902 // fact end up wrapping a null and invoking methods on it later.
903 if (!value) {
904 NS_RUNTIMEABORT("Don't try to wrap null objects");
905 }
906 // We try to wrap in the compartment of the underlying object of "scope"
907 JS::Rooted<JSObject*> obj(cx);
908 {
909 // scope for the JSAutoCompartment so that we restore the compartment
910 // before we call JS_WrapValue.
911 Maybe<JSAutoCompartment> ac;
912 // Maybe<Handle> doesn't so much work, and in any case, adding
913 // more Maybe (one for a Rooted and one for a Handle) adds more
914 // code (and branches!) than just adding a single rooted.
915 JS::Rooted<JSObject*> scope(cx, scopeArg);
916 if (js::IsWrapper(scope)) {
917 scope = js::CheckedUnwrap(scope, /* stopAtOuter = */ false);
918 if (!scope)
919 return false;
920 ac.construct(cx, scope);
921 }
923 bool tookOwnership = false;
924 MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
925 obj = value->WrapObject(cx, &tookOwnership);
926 MOZ_ASSERT_IF(obj, tookOwnership);
927 if (tookOwnership) {
928 value.forget();
929 }
930 }
932 if (!obj) {
933 return false;
934 }
936 // We can end up here in all sorts of compartments, per above. Make
937 // sure to JS_WrapValue!
938 rval.set(JS::ObjectValue(*obj));
939 return JS_WrapValue(cx, rval);
940 }
942 // Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr).
943 template <template <typename> class SmartPtr, typename T>
944 inline bool
945 WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
946 const SmartPtr<T>& value,
947 JS::MutableHandle<JS::Value> rval)
948 {
949 return WrapNewBindingNonWrapperCachedObject(cx, scope, value.get(), rval);
950 }
952 // Only set allowNativeWrapper to false if you really know you need it, if in
953 // doubt use true. Setting it to false disables security wrappers.
954 bool
955 NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
956 JS::Handle<JSObject*> aScope,
957 JS::MutableHandle<JS::Value> aRetval,
958 xpcObjectHelper& aHelper,
959 const nsIID* aIID,
960 bool aAllowNativeWrapper);
962 /**
963 * A method to handle new-binding wrap failure, by possibly falling back to
964 * wrapping as a non-new-binding object.
965 */
966 template <class T>
967 MOZ_ALWAYS_INLINE bool
968 HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
969 T* value, JS::MutableHandle<JS::Value> rval)
970 {
971 if (JS_IsExceptionPending(cx)) {
972 return false;
973 }
975 qsObjectHelper helper(value, GetWrapperCache(value));
976 return NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval,
977 helper, nullptr, true);
978 }
980 // Helper for calling HandleNewBindingWrappingFailure with smart pointers
981 // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
982 HAS_MEMBER(get)
984 template <class T, bool isSmartPtr=HasgetMember<T>::Value>
985 struct HandleNewBindingWrappingFailureHelper
986 {
987 static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
988 const T& value, JS::MutableHandle<JS::Value> rval)
989 {
990 return HandleNewBindingWrappingFailure(cx, scope, value.get(), rval);
991 }
992 };
994 template <class T>
995 struct HandleNewBindingWrappingFailureHelper<T, false>
996 {
997 static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope, T& value,
998 JS::MutableHandle<JS::Value> rval)
999 {
1000 return HandleNewBindingWrappingFailure(cx, scope, &value, rval);
1001 }
1002 };
1004 template<class T>
1005 inline bool
1006 HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
1007 T& value, JS::MutableHandle<JS::Value> rval)
1008 {
1009 return HandleNewBindingWrappingFailureHelper<T>::Wrap(cx, scope, value, rval);
1010 }
1012 template<bool Fatal>
1013 inline bool
1014 EnumValueNotFound(JSContext* cx, const jschar* chars, size_t length,
1015 const char* type, const char* sourceDescription)
1016 {
1017 return false;
1018 }
1020 template<>
1021 inline bool
1022 EnumValueNotFound<false>(JSContext* cx, const jschar* chars, size_t length,
1023 const char* type, const char* sourceDescription)
1024 {
1025 // TODO: Log a warning to the console.
1026 return true;
1027 }
1029 template<>
1030 inline bool
1031 EnumValueNotFound<true>(JSContext* cx, const jschar* chars, size_t length,
1032 const char* type, const char* sourceDescription)
1033 {
1034 NS_LossyConvertUTF16toASCII deflated(static_cast<const char16_t*>(chars),
1035 length);
1036 return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
1037 deflated.get(), type);
1038 }
1041 template<bool InvalidValueFatal>
1042 inline int
1043 FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* values,
1044 const char* type, const char* sourceDescription, bool* ok)
1045 {
1046 // JS_StringEqualsAscii is slow as molasses, so don't use it here.
1047 JSString* str = JS::ToString(cx, v);
1048 if (!str) {
1049 *ok = false;
1050 return 0;
1051 }
1052 JS::Anchor<JSString*> anchor(str);
1053 size_t length;
1054 const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
1055 if (!chars) {
1056 *ok = false;
1057 return 0;
1058 }
1059 int i = 0;
1060 for (const EnumEntry* value = values; value->value; ++value, ++i) {
1061 if (length != value->length) {
1062 continue;
1063 }
1065 bool equal = true;
1066 const char* val = value->value;
1067 for (size_t j = 0; j != length; ++j) {
1068 if (unsigned(val[j]) != unsigned(chars[j])) {
1069 equal = false;
1070 break;
1071 }
1072 }
1074 if (equal) {
1075 *ok = true;
1076 return i;
1077 }
1078 }
1080 *ok = EnumValueNotFound<InvalidValueFatal>(cx, chars, length, type,
1081 sourceDescription);
1082 return -1;
1083 }
1085 inline nsWrapperCache*
1086 GetWrapperCache(const ParentObject& aParentObject)
1087 {
1088 return aParentObject.mWrapperCache;
1089 }
1091 template<class T>
1092 inline T*
1093 GetParentPointer(T* aObject)
1094 {
1095 return aObject;
1096 }
1098 inline nsISupports*
1099 GetParentPointer(const ParentObject& aObject)
1100 {
1101 return aObject.mObject;
1102 }
1104 template <typename T>
1105 inline bool
1106 GetUseXBLScope(T* aParentObject)
1107 {
1108 return false;
1109 }
1111 inline bool
1112 GetUseXBLScope(const ParentObject& aParentObject)
1113 {
1114 return aParentObject.mUseXBLScope;
1115 }
1117 template<class T>
1118 inline void
1119 ClearWrapper(T* p, nsWrapperCache* cache)
1120 {
1121 cache->ClearWrapper();
1122 }
1124 template<class T>
1125 inline void
1126 ClearWrapper(T* p, void*)
1127 {
1128 nsWrapperCache* cache;
1129 CallQueryInterface(p, &cache);
1130 ClearWrapper(p, cache);
1131 }
1133 // Attempt to preserve the wrapper, if any, for a Paris DOM bindings object.
1134 // Return true if we successfully preserved the wrapper, or there is no wrapper
1135 // to preserve. In the latter case we don't need to preserve the wrapper, because
1136 // the object can only be obtained by JS once, or they cannot be meaningfully
1137 // owned from the native side.
1138 //
1139 // This operation will return false only for non-nsISupports cycle-collected
1140 // objects, because we cannot determine if they are wrappercached or not.
1141 bool
1142 TryPreserveWrapper(JSObject* obj);
1144 // Can only be called with the immediate prototype of the instance object. Can
1145 // only be called on the prototype of an object known to be a DOM instance.
1146 bool
1147 InstanceClassHasProtoAtDepth(JSObject* protoObject, uint32_t protoID,
1148 uint32_t depth);
1150 // Only set allowNativeWrapper to false if you really know you need it, if in
1151 // doubt use true. Setting it to false disables security wrappers.
1152 bool
1153 XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
1154 xpcObjectHelper& helper, const nsIID* iid,
1155 bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval);
1157 // Special-cased wrapping for variants
1158 bool
1159 VariantToJsval(JSContext* aCx, nsIVariant* aVariant,
1160 JS::MutableHandle<JS::Value> aRetval);
1162 // Wrap an object "p" which is not using WebIDL bindings yet. This _will_
1163 // actually work on WebIDL binding objects that are wrappercached, but will be
1164 // much slower than WrapNewBindingObject. "cache" must either be null or be the
1165 // nsWrapperCache for "p".
1166 template<class T>
1167 inline bool
1168 WrapObject(JSContext* cx, T* p, nsWrapperCache* cache, const nsIID* iid,
1169 JS::MutableHandle<JS::Value> rval)
1170 {
1171 if (xpc_FastGetCachedWrapper(cx, cache, rval))
1172 return true;
1173 qsObjectHelper helper(p, cache);
1174 JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
1175 return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval);
1176 }
1178 // A specialization of the above for nsIVariant, because that needs to
1179 // do something different.
1180 template<>
1181 inline bool
1182 WrapObject<nsIVariant>(JSContext* cx, nsIVariant* p,
1183 nsWrapperCache* cache, const nsIID* iid,
1184 JS::MutableHandle<JS::Value> rval)
1185 {
1186 MOZ_ASSERT(iid);
1187 MOZ_ASSERT(iid->Equals(NS_GET_IID(nsIVariant)));
1188 return VariantToJsval(cx, p, rval);
1189 }
1191 // Wrap an object "p" which is not using WebIDL bindings yet. Just like the
1192 // variant that takes an nsWrapperCache above, but will try to auto-derive the
1193 // nsWrapperCache* from "p".
1194 template<class T>
1195 inline bool
1196 WrapObject(JSContext* cx, T* p, const nsIID* iid,
1197 JS::MutableHandle<JS::Value> rval)
1198 {
1199 return WrapObject(cx, p, GetWrapperCache(p), iid, rval);
1200 }
1202 // Just like the WrapObject above, but without requiring you to pick which
1203 // interface you're wrapping as. This should only be used for objects that have
1204 // classinfo, for which it doesn't matter what IID is used to wrap.
1205 template<class T>
1206 inline bool
1207 WrapObject(JSContext* cx, T* p, JS::MutableHandle<JS::Value> rval)
1208 {
1209 return WrapObject(cx, p, nullptr, rval);
1210 }
1212 // Helper to make it possible to wrap directly out of an nsCOMPtr
1213 template<class T>
1214 inline bool
1215 WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
1216 const nsIID* iid, JS::MutableHandle<JS::Value> rval)
1217 {
1218 return WrapObject(cx, p.get(), iid, rval);
1219 }
1221 // Helper to make it possible to wrap directly out of an nsCOMPtr
1222 template<class T>
1223 inline bool
1224 WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
1225 JS::MutableHandle<JS::Value> rval)
1226 {
1227 return WrapObject(cx, p, nullptr, rval);
1228 }
1230 // Helper to make it possible to wrap directly out of an nsRefPtr
1231 template<class T>
1232 inline bool
1233 WrapObject(JSContext* cx, const nsRefPtr<T>& p,
1234 const nsIID* iid, JS::MutableHandle<JS::Value> rval)
1235 {
1236 return WrapObject(cx, p.get(), iid, rval);
1237 }
1239 // Helper to make it possible to wrap directly out of an nsRefPtr
1240 template<class T>
1241 inline bool
1242 WrapObject(JSContext* cx, const nsRefPtr<T>& p,
1243 JS::MutableHandle<JS::Value> rval)
1244 {
1245 return WrapObject(cx, p, nullptr, rval);
1246 }
1248 // Specialization to make it easy to use WrapObject in codegen.
1249 template<>
1250 inline bool
1251 WrapObject<JSObject>(JSContext* cx, JSObject* p,
1252 JS::MutableHandle<JS::Value> rval)
1253 {
1254 rval.set(JS::ObjectOrNullValue(p));
1255 return true;
1256 }
1258 inline bool
1259 WrapObject(JSContext* cx, JSObject& p, JS::MutableHandle<JS::Value> rval)
1260 {
1261 rval.set(JS::ObjectValue(p));
1262 return true;
1263 }
1265 // Given an object "p" that inherits from nsISupports, wrap it and return the
1266 // result. Null is returned on wrapping failure. This is somewhat similar to
1267 // WrapObject() above, but does NOT allow Xrays around the result, since we
1268 // don't want those for our parent object.
1269 template<typename T>
1270 static inline JSObject*
1271 WrapNativeISupportsParent(JSContext* cx, T* p, nsWrapperCache* cache)
1272 {
1273 qsObjectHelper helper(ToSupports(p), cache);
1274 JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
1275 JS::Rooted<JS::Value> v(cx);
1276 return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
1277 v.toObjectOrNull() :
1278 nullptr;
1279 }
1282 // Fallback for when our parent is not a WebIDL binding object.
1283 template<typename T, bool isISupports=IsBaseOf<nsISupports, T>::value>
1284 struct WrapNativeParentFallback
1285 {
1286 static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
1287 {
1288 return nullptr;
1289 }
1290 };
1292 // Fallback for when our parent is not a WebIDL binding object but _is_ an
1293 // nsISupports object.
1294 template<typename T >
1295 struct WrapNativeParentFallback<T, true >
1296 {
1297 static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
1298 {
1299 return WrapNativeISupportsParent(cx, parent, cache);
1300 }
1301 };
1303 // Wrapping of our native parent, for cases when it's a WebIDL object (though
1304 // possibly preffed off).
1305 template<typename T, bool hasWrapObject=HasWrapObject<T>::Value >
1306 struct WrapNativeParentHelper
1307 {
1308 static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
1309 {
1310 MOZ_ASSERT(cache);
1312 JSObject* obj;
1313 if ((obj = cache->GetWrapper())) {
1314 return obj;
1315 }
1317 // Inline this here while we have non-dom objects in wrapper caches.
1318 if (!CouldBeDOMBinding(parent)) {
1319 obj = WrapNativeParentFallback<T>::Wrap(cx, parent, cache);
1320 } else {
1321 obj = parent->WrapObject(cx);
1322 }
1324 return obj;
1325 }
1326 };
1328 // Wrapping of our native parent, for cases when it's not a WebIDL object. In
1329 // this case it must be nsISupports.
1330 template<typename T>
1331 struct WrapNativeParentHelper<T, false >
1332 {
1333 static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
1334 {
1335 JSObject* obj;
1336 if (cache && (obj = cache->GetWrapper())) {
1337 #ifdef DEBUG
1338 NS_ASSERTION(WrapNativeISupportsParent(cx, parent, cache) == obj,
1339 "Unexpected object in nsWrapperCache");
1340 #endif
1341 return obj;
1342 }
1344 return WrapNativeISupportsParent(cx, parent, cache);
1345 }
1346 };
1348 // Wrapping of our native parent.
1349 template<typename T>
1350 static inline JSObject*
1351 WrapNativeParent(JSContext* cx, T* p, nsWrapperCache* cache,
1352 bool useXBLScope = false)
1353 {
1354 if (!p) {
1355 return JS::CurrentGlobalOrNull(cx);
1356 }
1358 JSObject* parent = WrapNativeParentHelper<T>::Wrap(cx, p, cache);
1359 if (!useXBLScope) {
1360 return parent;
1361 }
1363 // If useXBLScope is true, it means that the canonical reflector for this
1364 // native object should live in the XBL scope.
1365 if (xpc::IsInXBLScope(parent)) {
1366 return parent;
1367 }
1368 JS::Rooted<JSObject*> rootedParent(cx, parent);
1369 JS::Rooted<JSObject*> xblScope(cx, xpc::GetXBLScope(cx, rootedParent));
1370 NS_ENSURE_TRUE(xblScope, nullptr);
1371 JSAutoCompartment ac(cx, xblScope);
1372 if (NS_WARN_IF(!JS_WrapObject(cx, &rootedParent))) {
1373 return nullptr;
1374 }
1376 return rootedParent;
1377 }
1379 // Wrapping of our native parent, when we don't want to explicitly pass in
1380 // things like the nsWrapperCache for it.
1381 template<typename T>
1382 static inline JSObject*
1383 WrapNativeParent(JSContext* cx, const T& p)
1384 {
1385 return WrapNativeParent(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
1386 }
1388 // A way to differentiate between nodes, which use the parent object
1389 // returned by native->GetParentObject(), and all other objects, which
1390 // just use the parent's global.
1391 static inline JSObject*
1392 GetRealParentObject(void* aParent, JSObject* aParentObject)
1393 {
1394 return aParentObject ?
1395 js::GetGlobalForObjectCrossCompartment(aParentObject) : nullptr;
1396 }
1398 static inline JSObject*
1399 GetRealParentObject(Element* aParent, JSObject* aParentObject)
1400 {
1401 return aParentObject;
1402 }
1404 HAS_MEMBER(GetParentObject)
1406 template<typename T, bool WrapperCached=HasGetParentObjectMember<T>::Value>
1407 struct GetParentObject
1408 {
1409 static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
1410 {
1411 MOZ_ASSERT(js::IsObjectInContextCompartment(obj, cx));
1412 T* native = UnwrapDOMObject<T>(obj);
1413 return
1414 GetRealParentObject(native,
1415 WrapNativeParent(cx, native->GetParentObject()));
1416 }
1417 };
1419 template<typename T>
1420 struct GetParentObject<T, false>
1421 {
1422 static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
1423 {
1424 MOZ_CRASH();
1425 return nullptr;
1426 }
1427 };
1429 MOZ_ALWAYS_INLINE
1430 JSObject* GetJSObjectFromCallback(CallbackObject* callback)
1431 {
1432 return callback->Callback();
1433 }
1435 MOZ_ALWAYS_INLINE
1436 JSObject* GetJSObjectFromCallback(void* noncallback)
1437 {
1438 return nullptr;
1439 }
1441 template<typename T>
1442 static inline JSObject*
1443 WrapCallThisObject(JSContext* cx, const T& p)
1444 {
1445 // Callbacks are nsISupports, so WrapNativeParent will just happily wrap them
1446 // up as an nsISupports XPCWrappedNative... which is not at all what we want.
1447 // So we need to special-case them.
1448 JS::Rooted<JSObject*> obj(cx, GetJSObjectFromCallback(p));
1449 if (!obj) {
1450 // WrapNativeParent is a bit of a Swiss army knife that will
1451 // wrap anything for us.
1452 obj = WrapNativeParent(cx, p);
1453 if (!obj) {
1454 return nullptr;
1455 }
1456 }
1458 // But all that won't necessarily put things in the compartment of cx.
1459 if (!JS_WrapObject(cx, &obj)) {
1460 return nullptr;
1461 }
1463 return obj;
1464 }
1466 /*
1467 * This specialized function simply wraps a JS::Rooted<> since
1468 * WrapNativeParent() is not applicable for JS objects.
1469 */
1470 template<>
1471 inline JSObject*
1472 WrapCallThisObject<JS::Rooted<JSObject*>>(JSContext* cx,
1473 const JS::Rooted<JSObject*>& p)
1474 {
1475 JS::Rooted<JSObject*> obj(cx, p);
1477 if (!JS_WrapObject(cx, &obj)) {
1478 return nullptr;
1479 }
1481 return obj;
1482 }
1484 // Helper for calling WrapNewBindingObject with smart pointers
1485 // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
1486 template <class T, bool isSmartPtr=HasgetMember<T>::Value>
1487 struct WrapNewBindingObjectHelper
1488 {
1489 static inline bool Wrap(JSContext* cx, const T& value,
1490 JS::MutableHandle<JS::Value> rval)
1491 {
1492 return WrapNewBindingObject(cx, value.get(), rval);
1493 }
1494 };
1496 template <class T>
1497 struct WrapNewBindingObjectHelper<T, false>
1498 {
1499 static inline bool Wrap(JSContext* cx, T& value,
1500 JS::MutableHandle<JS::Value> rval)
1501 {
1502 return WrapNewBindingObject(cx, &value, rval);
1503 }
1504 };
1506 template<class T>
1507 inline bool
1508 WrapNewBindingObject(JSContext* cx, T& value, JS::MutableHandle<JS::Value> rval)
1509 {
1510 return WrapNewBindingObjectHelper<T>::Wrap(cx, value, rval);
1511 }
1513 // We need this version of WrapNewBindingObject for codegen, so it'll have the
1514 // same signature as WrapNewBindingNonWrapperCachedObject and
1515 // WrapNewBindingNonWrapperCachedOwnedObject, which still need the scope.
1516 template<class T>
1517 inline bool
1518 WrapNewBindingObject(JSContext* cx, JS::Handle<JSObject*> scope, T& value,
1519 JS::MutableHandle<JS::Value> rval)
1520 {
1521 return WrapNewBindingObject(cx, value, rval);
1522 }
1524 template <class T>
1525 inline JSObject*
1526 GetCallbackFromCallbackObject(T* aObj)
1527 {
1528 return aObj->Callback();
1529 }
1531 // Helper for getting the callback JSObject* of a smart ptr around a
1532 // CallbackObject or a reference to a CallbackObject or something like
1533 // that.
1534 template <class T, bool isSmartPtr=HasgetMember<T>::Value>
1535 struct GetCallbackFromCallbackObjectHelper
1536 {
1537 static inline JSObject* Get(const T& aObj)
1538 {
1539 return GetCallbackFromCallbackObject(aObj.get());
1540 }
1541 };
1543 template <class T>
1544 struct GetCallbackFromCallbackObjectHelper<T, false>
1545 {
1546 static inline JSObject* Get(T& aObj)
1547 {
1548 return GetCallbackFromCallbackObject(&aObj);
1549 }
1550 };
1552 template<class T>
1553 inline JSObject*
1554 GetCallbackFromCallbackObject(T& aObj)
1555 {
1556 return GetCallbackFromCallbackObjectHelper<T>::Get(aObj);
1557 }
1559 static inline bool
1560 InternJSString(JSContext* cx, jsid& id, const char* chars)
1561 {
1562 if (JSString *str = ::JS_InternString(cx, chars)) {
1563 id = INTERNED_STRING_TO_JSID(cx, str);
1564 return true;
1565 }
1566 return false;
1567 }
1569 // Spec needs a name property
1570 template <typename Spec>
1571 static bool
1572 InitIds(JSContext* cx, const Prefable<Spec>* prefableSpecs, jsid* ids)
1573 {
1574 MOZ_ASSERT(prefableSpecs);
1575 MOZ_ASSERT(prefableSpecs->specs);
1576 do {
1577 // We ignore whether the set of ids is enabled and just intern all the IDs,
1578 // because this is only done once per application runtime.
1579 Spec* spec = prefableSpecs->specs;
1580 do {
1581 if (!InternJSString(cx, *ids, spec->name)) {
1582 return false;
1583 }
1584 } while (++ids, (++spec)->name);
1586 // We ran out of ids for that pref. Put a JSID_VOID in on the id
1587 // corresponding to the list terminator for the pref.
1588 *ids = JSID_VOID;
1589 ++ids;
1590 } while ((++prefableSpecs)->specs);
1592 return true;
1593 }
1595 bool
1596 QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
1598 template <class T>
1599 struct
1600 WantsQueryInterface
1601 {
1602 static_assert(IsBaseOf<nsISupports, T>::value,
1603 "QueryInterface can't work without an nsISupports.");
1604 static bool Enabled(JSContext* aCx, JSObject* aGlobal)
1605 {
1606 return NS_IsMainThread() && IsChromeOrXBL(aCx, aGlobal);
1607 }
1608 };
1610 void
1611 GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
1612 nsWrapperCache* aCache, nsIJSID* aIID,
1613 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError);
1615 template<class T>
1616 void
1617 GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID,
1618 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
1619 {
1620 GetInterfaceImpl(aCx, aThis, aThis, aIID, aRetval, aError);
1621 }
1623 bool
1624 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
1626 bool
1627 ThrowConstructorWithoutNew(JSContext* cx, const char* name);
1629 // vp is allowed to be null; in that case no get will be attempted,
1630 // and *found will simply indicate whether the property exists.
1631 bool
1632 GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
1633 JS::Handle<jsid> id, bool* found,
1634 JS::Value* vp);
1636 bool
1637 HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
1638 JS::Handle<jsid> id);
1641 // Append the property names in "names" to "props". If
1642 // shadowPrototypeProperties is false then skip properties that are also
1643 // present on the proto chain of proxy. If shadowPrototypeProperties is true,
1644 // then the "proxy" argument is ignored.
1645 bool
1646 AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
1647 nsTArray<nsString>& names,
1648 bool shadowPrototypeProperties, JS::AutoIdVector& props);
1650 namespace binding_detail {
1652 // A struct that has the same layout as an nsDependentString but much
1653 // faster constructor and destructor behavior
1654 struct FakeDependentString {
1655 FakeDependentString() :
1656 mFlags(nsDependentString::F_TERMINATED)
1657 {
1658 }
1660 void SetData(const nsDependentString::char_type* aData,
1661 nsDependentString::size_type aLength) {
1662 MOZ_ASSERT(mFlags == nsDependentString::F_TERMINATED);
1663 mData = aData;
1664 mLength = aLength;
1665 }
1667 void Truncate() {
1668 mData = nsDependentString::char_traits::sEmptyBuffer;
1669 mLength = 0;
1670 }
1672 void SetNull() {
1673 Truncate();
1674 mFlags |= nsDependentString::F_VOIDED;
1675 }
1677 const nsDependentString::char_type* Data() const
1678 {
1679 return mData;
1680 }
1682 nsDependentString::size_type Length() const
1683 {
1684 return mLength;
1685 }
1687 // If this ever changes, change the corresponding code in the
1688 // Optional<nsAString> specialization as well.
1689 const nsAString* ToAStringPtr() const {
1690 return reinterpret_cast<const nsDependentString*>(this);
1691 }
1693 nsAString* ToAStringPtr() {
1694 return reinterpret_cast<nsDependentString*>(this);
1695 }
1697 operator const nsAString& () const {
1698 return *reinterpret_cast<const nsDependentString*>(this);
1699 }
1701 private:
1702 const nsDependentString::char_type* mData;
1703 nsDependentString::size_type mLength;
1704 uint32_t mFlags;
1706 // A class to use for our static asserts to ensure our object layout
1707 // matches that of nsDependentString.
1708 class DependentStringAsserter;
1709 friend class DependentStringAsserter;
1711 class DepedentStringAsserter : public nsDependentString {
1712 public:
1713 static void StaticAsserts() {
1714 static_assert(sizeof(FakeDependentString) == sizeof(nsDependentString),
1715 "Must have right object size");
1716 static_assert(offsetof(FakeDependentString, mData) ==
1717 offsetof(DepedentStringAsserter, mData),
1718 "Offset of mData should match");
1719 static_assert(offsetof(FakeDependentString, mLength) ==
1720 offsetof(DepedentStringAsserter, mLength),
1721 "Offset of mLength should match");
1722 static_assert(offsetof(FakeDependentString, mFlags) ==
1723 offsetof(DepedentStringAsserter, mFlags),
1724 "Offset of mFlags should match");
1725 }
1726 };
1727 };
1729 } // namespace binding_detail
1731 enum StringificationBehavior {
1732 eStringify,
1733 eEmpty,
1734 eNull
1735 };
1737 // pval must not be null and must point to a rooted JS::Value
1738 static inline bool
1739 ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
1740 JS::MutableHandle<JS::Value> pval,
1741 StringificationBehavior nullBehavior,
1742 StringificationBehavior undefinedBehavior,
1743 binding_detail::FakeDependentString& result)
1744 {
1745 JSString *s;
1746 if (v.isString()) {
1747 s = v.toString();
1748 } else {
1749 StringificationBehavior behavior;
1750 if (v.isNull()) {
1751 behavior = nullBehavior;
1752 } else if (v.isUndefined()) {
1753 behavior = undefinedBehavior;
1754 } else {
1755 behavior = eStringify;
1756 }
1758 if (behavior != eStringify) {
1759 if (behavior == eEmpty) {
1760 result.Truncate();
1761 } else {
1762 result.SetNull();
1763 }
1764 return true;
1765 }
1767 s = JS::ToString(cx, v);
1768 if (!s) {
1769 return false;
1770 }
1771 pval.set(JS::StringValue(s)); // Root the new string.
1772 }
1774 size_t len;
1775 const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
1776 if (!chars) {
1777 return false;
1778 }
1780 result.SetData(chars, len);
1781 return true;
1782 }
1784 bool
1785 ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
1786 JS::MutableHandle<JS::Value> pval, bool nullable,
1787 nsACString& result);
1789 template<typename T>
1790 void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
1791 template<typename T>
1792 void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
1794 // Class for simple sequence arguments, only used internally by codegen.
1795 namespace binding_detail {
1797 template<typename T>
1798 class AutoSequence : public AutoFallibleTArray<T, 16>
1799 {
1800 public:
1801 AutoSequence() : AutoFallibleTArray<T, 16>()
1802 {}
1804 // Allow converting to const sequences as needed
1805 operator const Sequence<T>&() const {
1806 return *reinterpret_cast<const Sequence<T>*>(this);
1807 }
1808 };
1810 } // namespace binding_detail
1812 // Class used to trace sequences, with specializations for various
1813 // sequence types.
1814 template<typename T,
1815 bool isDictionary=IsBaseOf<DictionaryBase, T>::value,
1816 bool isTypedArray=IsBaseOf<AllTypedArraysBase, T>::value,
1817 bool isOwningUnion=IsBaseOf<AllOwningUnionBase, T>::value>
1818 class SequenceTracer
1819 {
1820 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1821 };
1823 // sequence<object> or sequence<object?>
1824 template<>
1825 class SequenceTracer<JSObject*, false, false, false>
1826 {
1827 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1829 public:
1830 static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
1831 for (; objp != end; ++objp) {
1832 JS_CallObjectTracer(trc, objp, "sequence<object>");
1833 }
1834 }
1835 };
1837 // sequence<any>
1838 template<>
1839 class SequenceTracer<JS::Value, false, false, false>
1840 {
1841 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1843 public:
1844 static void TraceSequence(JSTracer* trc, JS::Value* valp, JS::Value* end) {
1845 for (; valp != end; ++valp) {
1846 JS_CallValueTracer(trc, valp, "sequence<any>");
1847 }
1848 }
1849 };
1851 // sequence<sequence<T>>
1852 template<typename T>
1853 class SequenceTracer<Sequence<T>, false, false, false>
1854 {
1855 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1857 public:
1858 static void TraceSequence(JSTracer* trc, Sequence<T>* seqp, Sequence<T>* end) {
1859 for (; seqp != end; ++seqp) {
1860 DoTraceSequence(trc, *seqp);
1861 }
1862 }
1863 };
1865 // sequence<sequence<T>> as return value
1866 template<typename T>
1867 class SequenceTracer<nsTArray<T>, false, false, false>
1868 {
1869 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1871 public:
1872 static void TraceSequence(JSTracer* trc, nsTArray<T>* seqp, nsTArray<T>* end) {
1873 for (; seqp != end; ++seqp) {
1874 DoTraceSequence(trc, *seqp);
1875 }
1876 }
1877 };
1879 // sequence<someDictionary>
1880 template<typename T>
1881 class SequenceTracer<T, true, false, false>
1882 {
1883 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1885 public:
1886 static void TraceSequence(JSTracer* trc, T* dictp, T* end) {
1887 for (; dictp != end; ++dictp) {
1888 dictp->TraceDictionary(trc);
1889 }
1890 }
1891 };
1893 // sequence<SomeTypedArray>
1894 template<typename T>
1895 class SequenceTracer<T, false, true, false>
1896 {
1897 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1899 public:
1900 static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
1901 for (; arrayp != end; ++arrayp) {
1902 arrayp->TraceSelf(trc);
1903 }
1904 }
1905 };
1907 // sequence<SomeOwningUnion>
1908 template<typename T>
1909 class SequenceTracer<T, false, false, true>
1910 {
1911 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1913 public:
1914 static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
1915 for (; arrayp != end; ++arrayp) {
1916 arrayp->TraceUnion(trc);
1917 }
1918 }
1919 };
1921 // sequence<T?> with T? being a Nullable<T>
1922 template<typename T>
1923 class SequenceTracer<Nullable<T>, false, false, false>
1924 {
1925 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1927 public:
1928 static void TraceSequence(JSTracer* trc, Nullable<T>* seqp,
1929 Nullable<T>* end) {
1930 for (; seqp != end; ++seqp) {
1931 if (!seqp->IsNull()) {
1932 // Pretend like we actually have a length-one sequence here so
1933 // we can do template instantiation correctly for T.
1934 T& val = seqp->Value();
1935 T* ptr = &val;
1936 SequenceTracer<T>::TraceSequence(trc, ptr, ptr+1);
1937 }
1938 }
1939 }
1940 };
1942 // XXXbz It's not clear whether it's better to add a pldhash dependency here
1943 // (for PLDHashOperator) or add a BindingUtils.h dependency (for
1944 // SequenceTracer) to MozMap.h...
1945 template<typename T>
1946 static PLDHashOperator
1947 TraceMozMapValue(T* aValue, void* aClosure)
1948 {
1949 JSTracer* trc = static_cast<JSTracer*>(aClosure);
1950 // Act like it's a one-element sequence to leverage all that infrastructure.
1951 SequenceTracer<T>::TraceSequence(trc, aValue, aValue + 1);
1952 return PL_DHASH_NEXT;
1953 }
1955 // sequence<MozMap>
1956 template<typename T>
1957 class SequenceTracer<MozMap<T>, false, false, false>
1958 {
1959 explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
1961 public:
1962 static void TraceSequence(JSTracer* trc, MozMap<T>* seqp, MozMap<T>* end) {
1963 for (; seqp != end; ++seqp) {
1964 seqp->EnumerateValues(TraceMozMapValue<T>, trc);
1965 }
1966 }
1967 };
1969 template<typename T>
1970 void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq)
1971 {
1972 SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
1973 seq.Elements() + seq.Length());
1974 }
1976 template<typename T>
1977 void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq)
1978 {
1979 SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
1980 seq.Elements() + seq.Length());
1981 }
1983 // Rooter class for sequences; this is what we mostly use in the codegen
1984 template<typename T>
1985 class MOZ_STACK_CLASS SequenceRooter : private JS::CustomAutoRooter
1986 {
1987 public:
1988 SequenceRooter(JSContext *aCx, FallibleTArray<T>* aSequence
1989 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1990 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
1991 mFallibleArray(aSequence),
1992 mSequenceType(eFallibleArray)
1993 {
1994 }
1996 SequenceRooter(JSContext *aCx, InfallibleTArray<T>* aSequence
1997 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1998 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
1999 mInfallibleArray(aSequence),
2000 mSequenceType(eInfallibleArray)
2001 {
2002 }
2004 SequenceRooter(JSContext *aCx, Nullable<nsTArray<T> >* aSequence
2005 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2006 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2007 mNullableArray(aSequence),
2008 mSequenceType(eNullableArray)
2009 {
2010 }
2012 private:
2013 enum SequenceType {
2014 eInfallibleArray,
2015 eFallibleArray,
2016 eNullableArray
2017 };
2019 virtual void trace(JSTracer *trc) MOZ_OVERRIDE
2020 {
2021 if (mSequenceType == eFallibleArray) {
2022 DoTraceSequence(trc, *mFallibleArray);
2023 } else if (mSequenceType == eInfallibleArray) {
2024 DoTraceSequence(trc, *mInfallibleArray);
2025 } else {
2026 MOZ_ASSERT(mSequenceType == eNullableArray);
2027 if (!mNullableArray->IsNull()) {
2028 DoTraceSequence(trc, mNullableArray->Value());
2029 }
2030 }
2031 }
2033 union {
2034 InfallibleTArray<T>* mInfallibleArray;
2035 FallibleTArray<T>* mFallibleArray;
2036 Nullable<nsTArray<T> >* mNullableArray;
2037 };
2039 SequenceType mSequenceType;
2040 };
2042 // Rooter class for MozMap; this is what we mostly use in the codegen.
2043 template<typename T>
2044 class MOZ_STACK_CLASS MozMapRooter : private JS::CustomAutoRooter
2045 {
2046 public:
2047 MozMapRooter(JSContext *aCx, MozMap<T>* aMozMap
2048 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2049 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2050 mMozMap(aMozMap),
2051 mMozMapType(eMozMap)
2052 {
2053 }
2055 MozMapRooter(JSContext *aCx, Nullable<MozMap<T>>* aMozMap
2056 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2057 : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2058 mNullableMozMap(aMozMap),
2059 mMozMapType(eNullableMozMap)
2060 {
2061 }
2063 private:
2064 enum MozMapType {
2065 eMozMap,
2066 eNullableMozMap
2067 };
2069 virtual void trace(JSTracer *trc) MOZ_OVERRIDE
2070 {
2071 MozMap<T>* mozMap;
2072 if (mMozMapType == eMozMap) {
2073 mozMap = mMozMap;
2074 } else {
2075 MOZ_ASSERT(mMozMapType == eNullableMozMap);
2076 if (mNullableMozMap->IsNull()) {
2077 // Nothing to do
2078 return;
2079 }
2080 mozMap = &mNullableMozMap->Value();
2081 }
2083 mozMap->EnumerateValues(TraceMozMapValue<T>, trc);
2084 }
2086 union {
2087 MozMap<T>* mMozMap;
2088 Nullable<MozMap<T>>* mNullableMozMap;
2089 };
2091 MozMapType mMozMapType;
2092 };
2094 template<typename T>
2095 class MOZ_STACK_CLASS RootedUnion : public T,
2096 private JS::CustomAutoRooter
2097 {
2098 public:
2099 RootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
2100 T(),
2101 JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
2102 {
2103 }
2105 virtual void trace(JSTracer *trc) MOZ_OVERRIDE
2106 {
2107 this->TraceUnion(trc);
2108 }
2109 };
2111 template<typename T>
2112 class MOZ_STACK_CLASS NullableRootedUnion : public Nullable<T>,
2113 private JS::CustomAutoRooter
2114 {
2115 public:
2116 NullableRootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
2117 Nullable<T>(),
2118 JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
2119 {
2120 }
2122 virtual void trace(JSTracer *trc) MOZ_OVERRIDE
2123 {
2124 if (!this->IsNull()) {
2125 this->Value().TraceUnion(trc);
2126 }
2127 }
2128 };
2130 inline bool
2131 IdEquals(jsid id, const char* string)
2132 {
2133 return JSID_IS_STRING(id) &&
2134 JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
2135 }
2137 inline bool
2138 AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector, const char* name)
2139 {
2140 return vector.growBy(1) &&
2141 InternJSString(cx, vector[vector.length() - 1], name);
2142 }
2144 // Implementation of the bits that XrayWrapper needs
2146 /**
2147 * This resolves indexed or named properties of obj.
2148 *
2149 * wrapper is the Xray JS object.
2150 * obj is the target object of the Xray, a binding's instance object or a
2151 * interface or interface prototype object.
2152 */
2153 bool
2154 XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
2155 JS::Handle<JSObject*> obj,
2156 JS::Handle<jsid> id,
2157 JS::MutableHandle<JSPropertyDescriptor> desc);
2159 /**
2160 * This resolves operations, attributes and constants of the interfaces for obj.
2161 *
2162 * wrapper is the Xray JS object.
2163 * obj is the target object of the Xray, a binding's instance object or a
2164 * interface or interface prototype object.
2165 */
2166 bool
2167 XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
2168 JS::Handle<JSObject*> obj,
2169 JS::Handle<jsid> id, JS::MutableHandle<JSPropertyDescriptor> desc);
2171 /**
2172 * Define a property on obj through an Xray wrapper.
2173 *
2174 * wrapper is the Xray JS object.
2175 * obj is the target object of the Xray, a binding's instance object or a
2176 * interface or interface prototype object.
2177 * defined will be set to true if a property was set as a result of this call.
2178 */
2179 bool
2180 XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
2181 JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
2182 JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined);
2184 /**
2185 * This enumerates indexed or named properties of obj and operations, attributes
2186 * and constants of the interfaces for obj.
2187 *
2188 * wrapper is the Xray JS object.
2189 * obj is the target object of the Xray, a binding's instance object or a
2190 * interface or interface prototype object.
2191 * flags are JSITER_* flags.
2192 */
2193 bool
2194 XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
2195 JS::Handle<JSObject*> obj,
2196 unsigned flags, JS::AutoIdVector& props);
2198 extern NativePropertyHooks sWorkerNativePropertyHooks;
2200 // We use one constructor JSNative to represent all DOM interface objects (so
2201 // we can easily detect when we need to wrap them in an Xray wrapper). We store
2202 // the real JSNative in the mNative member of a JSNativeHolder in the
2203 // CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction object for a
2204 // specific interface object. We also store the NativeProperties in the
2205 // JSNativeHolder.
2206 // Note that some interface objects are not yet a JSFunction but a normal
2207 // JSObject with a DOMJSClass, those do not use these slots.
2209 enum {
2210 CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT = 0
2211 };
2213 bool
2214 Constructor(JSContext* cx, unsigned argc, JS::Value* vp);
2216 inline bool
2217 UseDOMXray(JSObject* obj)
2218 {
2219 const js::Class* clasp = js::GetObjectClass(obj);
2220 return IsDOMClass(clasp) ||
2221 JS_IsNativeFunction(obj, Constructor) ||
2222 IsDOMIfaceAndProtoClass(clasp);
2223 }
2225 #ifdef DEBUG
2226 inline bool
2227 HasConstructor(JSObject* obj)
2228 {
2229 return JS_IsNativeFunction(obj, Constructor) ||
2230 js::GetObjectClass(obj)->construct;
2231 }
2232 #endif
2234 // Transfer reference in ptr to smartPtr.
2235 template<class T>
2236 inline void
2237 Take(nsRefPtr<T>& smartPtr, T* ptr)
2238 {
2239 smartPtr = dont_AddRef(ptr);
2240 }
2242 // Transfer ownership of ptr to smartPtr.
2243 template<class T>
2244 inline void
2245 Take(nsAutoPtr<T>& smartPtr, T* ptr)
2246 {
2247 smartPtr = ptr;
2248 }
2250 inline void
2251 MustInheritFromNonRefcountedDOMObject(NonRefcountedDOMObject*)
2252 {
2253 }
2255 /**
2256 * This creates a JSString containing the value that the toString function for
2257 * obj should create according to the WebIDL specification, ignoring any
2258 * modifications by script. The value is prefixed with pre and postfixed with
2259 * post, unless this is called for an object that has a stringifier. It is
2260 * specifically for use by Xray code.
2261 *
2262 * wrapper is the Xray JS object.
2263 * obj is the target object of the Xray, a binding's instance object or a
2264 * interface or interface prototype object.
2265 * pre is a string that should be prefixed to the value.
2266 * post is a string that should be prefixed to the value.
2267 * v contains the JSString for the value if the function returns true.
2268 */
2269 bool
2270 NativeToString(JSContext* cx, JS::Handle<JSObject*> wrapper,
2271 JS::Handle<JSObject*> obj, const char* pre,
2272 const char* post,
2273 JS::MutableHandle<JS::Value> v);
2275 HAS_MEMBER(JSBindingFinalized)
2277 template<class T, bool hasCallback=HasJSBindingFinalizedMember<T>::Value>
2278 struct JSBindingFinalized
2279 {
2280 static void Finalized(T* self)
2281 {
2282 }
2283 };
2285 template<class T>
2286 struct JSBindingFinalized<T, true>
2287 {
2288 static void Finalized(T* self)
2289 {
2290 self->JSBindingFinalized();
2291 }
2292 };
2294 // Helpers for creating a const version of a type.
2295 template<typename T>
2296 const T& Constify(T& arg)
2297 {
2298 return arg;
2299 }
2301 // Helper for turning (Owning)NonNull<T> into T&
2302 template<typename T>
2303 T& NonNullHelper(T& aArg)
2304 {
2305 return aArg;
2306 }
2308 template<typename T>
2309 T& NonNullHelper(NonNull<T>& aArg)
2310 {
2311 return aArg;
2312 }
2314 template<typename T>
2315 const T& NonNullHelper(const NonNull<T>& aArg)
2316 {
2317 return aArg;
2318 }
2320 template<typename T>
2321 T& NonNullHelper(OwningNonNull<T>& aArg)
2322 {
2323 return aArg;
2324 }
2326 template<typename T>
2327 const T& NonNullHelper(const OwningNonNull<T>& aArg)
2328 {
2329 return aArg;
2330 }
2332 inline
2333 void NonNullHelper(NonNull<binding_detail::FakeDependentString>& aArg)
2334 {
2335 // This overload is here to make sure that we never end up applying
2336 // NonNullHelper to a NonNull<binding_detail::FakeDependentString>. If we
2337 // try to, it should fail to compile, since presumably the caller will try to
2338 // use our nonexistent return value.
2339 }
2341 inline
2342 void NonNullHelper(const NonNull<binding_detail::FakeDependentString>& aArg)
2343 {
2344 // This overload is here to make sure that we never end up applying
2345 // NonNullHelper to a NonNull<binding_detail::FakeDependentString>. If we
2346 // try to, it should fail to compile, since presumably the caller will try to
2347 // use our nonexistent return value.
2348 }
2350 inline
2351 void NonNullHelper(binding_detail::FakeDependentString& aArg)
2352 {
2353 // This overload is here to make sure that we never end up applying
2354 // NonNullHelper to a FakeDependentString before we've constified it. If we
2355 // try to, it should fail to compile, since presumably the caller will try to
2356 // use our nonexistent return value.
2357 }
2359 MOZ_ALWAYS_INLINE
2360 const nsAString& NonNullHelper(const binding_detail::FakeDependentString& aArg)
2361 {
2362 return aArg;
2363 }
2365 // Reparent the wrapper of aObj to whatever its native now thinks its
2366 // parent should be.
2367 nsresult
2368 ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObj);
2370 /**
2371 * Used to implement the hasInstance hook of an interface object.
2372 *
2373 * instance should not be a security wrapper.
2374 */
2375 bool
2376 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
2377 JS::Handle<JSObject*> instance,
2378 bool* bp);
2379 bool
2380 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp,
2381 bool* bp);
2382 bool
2383 InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
2384 JS::Handle<JSObject*> instance,
2385 bool* bp);
2387 // Helper for lenient getters/setters to report to console. If this
2388 // returns false, we couldn't even get a global.
2389 bool
2390 ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj);
2392 inline JSObject*
2393 GetUnforgeableHolder(JSObject* aGlobal, prototypes::ID aId)
2394 {
2395 ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(aGlobal);
2396 JSObject* interfaceProto = protoAndIfaceCache.EntrySlotMustExist(aId);
2397 return &js::GetReservedSlot(interfaceProto,
2398 DOM_INTERFACE_PROTO_SLOTS_BASE).toObject();
2399 }
2401 // Given a JSObject* that represents the chrome side of a JS-implemented WebIDL
2402 // interface, get the nsPIDOMWindow corresponding to the content side, if any.
2403 // A false return means an exception was thrown.
2404 bool
2405 GetWindowForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
2406 nsPIDOMWindow** window);
2408 void
2409 ConstructJSImplementation(JSContext* aCx, const char* aContractId,
2410 nsPIDOMWindow* aWindow,
2411 JS::MutableHandle<JSObject*> aObject,
2412 ErrorResult& aRv);
2414 already_AddRefed<nsPIDOMWindow>
2415 ConstructJSImplementation(JSContext* aCx, const char* aContractId,
2416 const GlobalObject& aGlobal,
2417 JS::MutableHandle<JSObject*> aObject,
2418 ErrorResult& aRv);
2420 /**
2421 * Convert an nsCString to jsval, returning true on success.
2422 * These functions are intended for ByteString implementations.
2423 * As such, the string is not UTF-8 encoded. Any UTF8 strings passed to these
2424 * methods will be mangled.
2425 */
2426 bool NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
2427 JS::MutableHandle<JS::Value> rval);
2428 inline bool ByteStringToJsval(JSContext *cx, const nsACString &str,
2429 JS::MutableHandle<JS::Value> rval)
2430 {
2431 if (str.IsVoid()) {
2432 rval.setNull();
2433 return true;
2434 }
2435 return NonVoidByteStringToJsval(cx, str, rval);
2436 }
2438 template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
2439 struct PreserveWrapperHelper
2440 {
2441 static void PreserveWrapper(T* aObject)
2442 {
2443 aObject->PreserveWrapper(aObject, NS_CYCLE_COLLECTION_PARTICIPANT(T));
2444 }
2445 };
2447 template<class T>
2448 struct PreserveWrapperHelper<T, true>
2449 {
2450 static void PreserveWrapper(T* aObject)
2451 {
2452 aObject->PreserveWrapper(reinterpret_cast<nsISupports*>(aObject));
2453 }
2454 };
2456 template<class T>
2457 void PreserveWrapper(T* aObject)
2458 {
2459 PreserveWrapperHelper<T>::PreserveWrapper(aObject);
2460 }
2462 template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
2463 struct CastingAssertions
2464 {
2465 static bool ToSupportsIsCorrect(T*)
2466 {
2467 return true;
2468 }
2469 static bool ToSupportsIsOnPrimaryInheritanceChain(T*, nsWrapperCache*)
2470 {
2471 return true;
2472 }
2473 };
2475 template<class T>
2476 struct CastingAssertions<T, true>
2477 {
2478 static bool ToSupportsIsCorrect(T* aObject)
2479 {
2480 return ToSupports(aObject) == reinterpret_cast<nsISupports*>(aObject);
2481 }
2482 static bool ToSupportsIsOnPrimaryInheritanceChain(T* aObject,
2483 nsWrapperCache* aCache)
2484 {
2485 return reinterpret_cast<void*>(aObject) != aCache;
2486 }
2487 };
2489 template<class T>
2490 bool
2491 ToSupportsIsCorrect(T* aObject)
2492 {
2493 return CastingAssertions<T>::ToSupportsIsCorrect(aObject);
2494 }
2496 template<class T>
2497 bool
2498 ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache)
2499 {
2500 return CastingAssertions<T>::ToSupportsIsOnPrimaryInheritanceChain(aObject,
2501 aCache);
2502 }
2504 template<class T, template <typename> class SmartPtr,
2505 bool isISupports=IsBaseOf<nsISupports, T>::value>
2506 class DeferredFinalizer
2507 {
2508 typedef nsTArray<SmartPtr<T> > SmartPtrArray;
2510 static void*
2511 AppendDeferredFinalizePointer(void* aData, void* aObject)
2512 {
2513 SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
2514 if (!pointers) {
2515 pointers = new SmartPtrArray();
2516 }
2518 T* self = static_cast<T*>(aObject);
2520 SmartPtr<T>* defer = pointers->AppendElement();
2521 Take(*defer, self);
2522 return pointers;
2523 }
2524 static bool
2525 DeferredFinalize(uint32_t aSlice, void* aData)
2526 {
2527 MOZ_ASSERT(aSlice > 0, "nonsensical/useless call with aSlice == 0");
2528 SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
2529 uint32_t oldLen = pointers->Length();
2530 if (oldLen < aSlice) {
2531 aSlice = oldLen;
2532 }
2533 uint32_t newLen = oldLen - aSlice;
2534 pointers->RemoveElementsAt(newLen, aSlice);
2535 if (newLen == 0) {
2536 delete pointers;
2537 return true;
2538 }
2539 return false;
2540 }
2542 public:
2543 static void
2544 AddForDeferredFinalization(T* aObject)
2545 {
2546 cyclecollector::DeferredFinalize(AppendDeferredFinalizePointer,
2547 DeferredFinalize, aObject);
2548 }
2549 };
2551 template<class T, template <typename> class SmartPtr>
2552 class DeferredFinalizer<T, SmartPtr, true>
2553 {
2554 public:
2555 static void
2556 AddForDeferredFinalization(T* aObject)
2557 {
2558 cyclecollector::DeferredFinalize(reinterpret_cast<nsISupports*>(aObject));
2559 }
2560 };
2562 template<class T, template <typename> class SmartPtr>
2563 static void
2564 AddForDeferredFinalization(T* aObject)
2565 {
2566 DeferredFinalizer<T, SmartPtr>::AddForDeferredFinalization(aObject);
2567 }
2569 // This returns T's CC participant if it participates in CC or null if it
2570 // doesn't. This also returns null for classes that don't inherit from
2571 // nsISupports (QI should be used to get the participant for those).
2572 template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
2573 class GetCCParticipant
2574 {
2575 // Helper for GetCCParticipant for classes that participate in CC.
2576 template<class U>
2577 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2578 GetHelper(int, typename U::NS_CYCLE_COLLECTION_INNERCLASS* dummy=nullptr)
2579 {
2580 return T::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant();
2581 }
2582 // Helper for GetCCParticipant for classes that don't participate in CC.
2583 template<class U>
2584 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2585 GetHelper(double)
2586 {
2587 return nullptr;
2588 }
2590 public:
2591 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2592 Get()
2593 {
2594 // Passing int() here will try to call the GetHelper that takes an int as
2595 // its firt argument. If T doesn't participate in CC then substitution for
2596 // the second argument (with a default value) will fail and because of
2597 // SFINAE the next best match (the variant taking a double) will be called.
2598 return GetHelper<T>(int());
2599 }
2600 };
2602 template<class T>
2603 class GetCCParticipant<T, true>
2604 {
2605 public:
2606 static MOZ_CONSTEXPR nsCycleCollectionParticipant*
2607 Get()
2608 {
2609 return nullptr;
2610 }
2611 };
2613 /*
2614 * Helper function for testing whether the given object comes from a
2615 * privileged app.
2616 */
2617 bool
2618 IsInPrivilegedApp(JSContext* aCx, JSObject* aObj);
2620 /*
2621 * Helper function for testing whether the given object comes from a
2622 * certified app.
2623 */
2624 bool
2625 IsInCertifiedApp(JSContext* aCx, JSObject* aObj);
2627 void
2628 TraceGlobal(JSTracer* aTrc, JSObject* aObj);
2630 void
2631 FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
2633 bool
2634 ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
2635 JS::Handle<jsid> aId, JS::MutableHandle<JSObject*> aObjp);
2637 bool
2638 EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj);
2640 template <class T, JS::Handle<JSObject*> (*ProtoGetter)(JSContext*,
2641 JS::Handle<JSObject*>)>
2642 JSObject*
2643 CreateGlobal(JSContext* aCx, T* aObject, nsWrapperCache* aCache,
2644 const JSClass* aClass, JS::CompartmentOptions& aOptions,
2645 JSPrincipals* aPrincipal)
2646 {
2647 MOZ_ASSERT(!NS_IsMainThread());
2649 aOptions.setTrace(TraceGlobal);
2651 JS::Rooted<JSObject*> global(aCx,
2652 JS_NewGlobalObject(aCx, aClass, aPrincipal, JS::DontFireOnNewGlobalHook,
2653 aOptions));
2654 if (!global) {
2655 NS_WARNING("Failed to create global");
2656 return nullptr;
2657 }
2659 JSAutoCompartment ac(aCx, global);
2661 dom::AllocateProtoAndIfaceCache(global, ProtoAndIfaceCache::WindowLike);
2663 js::SetReservedSlot(global, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
2664 NS_ADDREF(aObject);
2666 aCache->SetIsDOMBinding();
2667 aCache->SetWrapper(global);
2669 /* Intl API is broken and makes this fail intermittently, see bug 934889.
2670 if (!JS_InitStandardClasses(aCx, global)) {
2671 NS_WARNING("Failed to init standard classes");
2672 return nullptr;
2673 }
2674 */
2676 JS::Handle<JSObject*> proto = ProtoGetter(aCx, global);
2677 NS_ENSURE_TRUE(proto, nullptr);
2679 if (!JS_SetPrototype(aCx, global, proto)) {
2680 NS_WARNING("Failed to set proto");
2681 return nullptr;
2682 }
2684 MOZ_ALWAYS_TRUE(TryPreserveWrapper(global));
2686 MOZ_ASSERT(UnwrapDOMObjectToISupports(global));
2688 return global;
2689 }
2691 /*
2692 * Holds a jsid that is initialized to an interned string, with conversion to
2693 * Handle<jsid>.
2694 */
2695 class InternedStringId
2696 {
2697 jsid id;
2699 public:
2700 InternedStringId() : id(JSID_VOID) {}
2702 bool init(JSContext *cx, const char *string) {
2703 JSString* str = JS_InternString(cx, string);
2704 if (!str)
2705 return false;
2706 id = INTERNED_STRING_TO_JSID(cx, str);
2707 return true;
2708 }
2710 operator const jsid& () {
2711 return id;
2712 }
2714 operator JS::Handle<jsid> () {
2715 /* This is safe because we have interned the string. */
2716 return JS::Handle<jsid>::fromMarkedLocation(&id);
2717 }
2718 };
2720 bool
2721 GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp);
2723 bool
2724 GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp);
2726 bool
2727 GenericBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp);
2729 bool
2730 GenericPromiseReturningBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp);
2732 bool
2733 StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp);
2735 // ConvertExceptionToPromise should only be called when we have an error
2736 // condition (e.g. returned false from a JSAPI method). Note that there may be
2737 // no exception on cx, in which case this is an uncatchable failure that will
2738 // simply be propagated. Otherwise this method will attempt to convert the
2739 // exception to a Promise rejected with the exception that it will store in
2740 // rval.
2741 //
2742 // promiseScope should be the scope in which the Promise should be created.
2743 bool
2744 ConvertExceptionToPromise(JSContext* cx,
2745 JSObject* promiseScope,
2746 JS::MutableHandle<JS::Value> rval);
2748 } // namespace dom
2749 } // namespace mozilla
2751 #endif /* mozilla_dom_BindingUtils_h__ */