dom/bindings/BindingUtils.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

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);
  1002 };
  1004 template<class T>
  1005 inline bool
  1006 HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
  1007                                 T& value, JS::MutableHandle<JS::Value> rval)
  1009   return HandleNewBindingWrappingFailureHelper<T>::Wrap(cx, scope, value, rval);
  1012 template<bool Fatal>
  1013 inline bool
  1014 EnumValueNotFound(JSContext* cx, const jschar* chars, size_t length,
  1015                   const char* type, const char* sourceDescription)
  1017   return false;
  1020 template<>
  1021 inline bool
  1022 EnumValueNotFound<false>(JSContext* cx, const jschar* chars, size_t length,
  1023                          const char* type, const char* sourceDescription)
  1025   // TODO: Log a warning to the console.
  1026   return true;
  1029 template<>
  1030 inline bool
  1031 EnumValueNotFound<true>(JSContext* cx, const jschar* chars, size_t length,
  1032                         const char* type, const char* sourceDescription)
  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);
  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)
  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;
  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;
  1059   int i = 0;
  1060   for (const EnumEntry* value = values; value->value; ++value, ++i) {
  1061     if (length != value->length) {
  1062       continue;
  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;
  1074     if (equal) {
  1075       *ok = true;
  1076       return i;
  1080   *ok = EnumValueNotFound<InvalidValueFatal>(cx, chars, length, type,
  1081                                              sourceDescription);
  1082   return -1;
  1085 inline nsWrapperCache*
  1086 GetWrapperCache(const ParentObject& aParentObject)
  1088   return aParentObject.mWrapperCache;
  1091 template<class T>
  1092 inline T*
  1093 GetParentPointer(T* aObject)
  1095   return aObject;
  1098 inline nsISupports*
  1099 GetParentPointer(const ParentObject& aObject)
  1101   return aObject.mObject;
  1104 template <typename T>
  1105 inline bool
  1106 GetUseXBLScope(T* aParentObject)
  1108   return false;
  1111 inline bool
  1112 GetUseXBLScope(const ParentObject& aParentObject)
  1114   return aParentObject.mUseXBLScope;
  1117 template<class T>
  1118 inline void
  1119 ClearWrapper(T* p, nsWrapperCache* cache)
  1121   cache->ClearWrapper();
  1124 template<class T>
  1125 inline void
  1126 ClearWrapper(T* p, void*)
  1128   nsWrapperCache* cache;
  1129   CallQueryInterface(p, &cache);
  1130   ClearWrapper(p, cache);
  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)
  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);
  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)
  1186   MOZ_ASSERT(iid);
  1187   MOZ_ASSERT(iid->Equals(NS_GET_IID(nsIVariant)));
  1188   return VariantToJsval(cx, p, rval);
  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)
  1199   return WrapObject(cx, p, GetWrapperCache(p), iid, rval);
  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)
  1209   return WrapObject(cx, p, nullptr, rval);
  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)
  1218   return WrapObject(cx, p.get(), iid, rval);
  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)
  1227   return WrapObject(cx, p, nullptr, rval);
  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)
  1236   return WrapObject(cx, p.get(), iid, rval);
  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)
  1245   return WrapObject(cx, p, nullptr, rval);
  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)
  1254   rval.set(JS::ObjectOrNullValue(p));
  1255   return true;
  1258 inline bool
  1259 WrapObject(JSContext* cx, JSObject& p, JS::MutableHandle<JS::Value> rval)
  1261   rval.set(JS::ObjectValue(p));
  1262   return true;
  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)
  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;
  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
  1286   static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
  1288     return nullptr;
  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 >
  1297   static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
  1299     return WrapNativeISupportsParent(cx, parent, cache);
  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
  1308   static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
  1310     MOZ_ASSERT(cache);
  1312     JSObject* obj;
  1313     if ((obj = cache->GetWrapper())) {
  1314       return obj;
  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);
  1324     return obj;
  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 >
  1333   static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
  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;
  1344     return WrapNativeISupportsParent(cx, parent, cache);
  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)
  1354   if (!p) {
  1355     return JS::CurrentGlobalOrNull(cx);
  1358   JSObject* parent = WrapNativeParentHelper<T>::Wrap(cx, p, cache);
  1359   if (!useXBLScope) {
  1360     return parent;
  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;
  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;
  1376   return rootedParent;
  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)
  1385   return WrapNativeParent(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
  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)
  1394   return aParentObject ?
  1395     js::GetGlobalForObjectCrossCompartment(aParentObject) : nullptr;
  1398 static inline JSObject*
  1399 GetRealParentObject(Element* aParent, JSObject* aParentObject)
  1401   return aParentObject;
  1404 HAS_MEMBER(GetParentObject)
  1406 template<typename T, bool WrapperCached=HasGetParentObjectMember<T>::Value>
  1407 struct GetParentObject
  1409   static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
  1411     MOZ_ASSERT(js::IsObjectInContextCompartment(obj, cx));
  1412     T* native = UnwrapDOMObject<T>(obj);
  1413     return
  1414       GetRealParentObject(native,
  1415                           WrapNativeParent(cx, native->GetParentObject()));
  1417 };
  1419 template<typename T>
  1420 struct GetParentObject<T, false>
  1422   static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
  1424     MOZ_CRASH();
  1425     return nullptr;
  1427 };
  1429 MOZ_ALWAYS_INLINE
  1430 JSObject* GetJSObjectFromCallback(CallbackObject* callback)
  1432   return callback->Callback();
  1435 MOZ_ALWAYS_INLINE
  1436 JSObject* GetJSObjectFromCallback(void* noncallback)
  1438   return nullptr;
  1441 template<typename T>
  1442 static inline JSObject*
  1443 WrapCallThisObject(JSContext* cx, const T& p)
  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;
  1458   // But all that won't necessarily put things in the compartment of cx.
  1459   if (!JS_WrapObject(cx, &obj)) {
  1460     return nullptr;
  1463   return obj;
  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)
  1475   JS::Rooted<JSObject*> obj(cx, p);
  1477   if (!JS_WrapObject(cx, &obj)) {
  1478     return nullptr;
  1481   return obj;
  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
  1489   static inline bool Wrap(JSContext* cx, const T& value,
  1490                           JS::MutableHandle<JS::Value> rval)
  1492     return WrapNewBindingObject(cx, value.get(), rval);
  1494 };
  1496 template <class T>
  1497 struct WrapNewBindingObjectHelper<T, false>
  1499   static inline bool Wrap(JSContext* cx, T& value,
  1500                           JS::MutableHandle<JS::Value> rval)
  1502     return WrapNewBindingObject(cx, &value, rval);
  1504 };
  1506 template<class T>
  1507 inline bool
  1508 WrapNewBindingObject(JSContext* cx, T& value, JS::MutableHandle<JS::Value> rval)
  1510   return WrapNewBindingObjectHelper<T>::Wrap(cx, value, rval);
  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)
  1521   return WrapNewBindingObject(cx, value, rval);
  1524 template <class T>
  1525 inline JSObject*
  1526 GetCallbackFromCallbackObject(T* aObj)
  1528   return aObj->Callback();
  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
  1537   static inline JSObject* Get(const T& aObj)
  1539     return GetCallbackFromCallbackObject(aObj.get());
  1541 };
  1543 template <class T>
  1544 struct GetCallbackFromCallbackObjectHelper<T, false>
  1546   static inline JSObject* Get(T& aObj)
  1548     return GetCallbackFromCallbackObject(&aObj);
  1550 };
  1552 template<class T>
  1553 inline JSObject*
  1554 GetCallbackFromCallbackObject(T& aObj)
  1556   return GetCallbackFromCallbackObjectHelper<T>::Get(aObj);
  1559 static inline bool
  1560 InternJSString(JSContext* cx, jsid& id, const char* chars)
  1562   if (JSString *str = ::JS_InternString(cx, chars)) {
  1563     id = INTERNED_STRING_TO_JSID(cx, str);
  1564     return true;
  1566   return false;
  1569 // Spec needs a name property
  1570 template <typename Spec>
  1571 static bool
  1572 InitIds(JSContext* cx, const Prefable<Spec>* prefableSpecs, jsid* ids)
  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;
  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;
  1595 bool
  1596 QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
  1598 template <class T>
  1599 struct
  1600 WantsQueryInterface
  1602   static_assert(IsBaseOf<nsISupports, T>::value,
  1603                 "QueryInterface can't work without an nsISupports.");
  1604   static bool Enabled(JSContext* aCx, JSObject* aGlobal)
  1606     return NS_IsMainThread() && IsChromeOrXBL(aCx, aGlobal);
  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)
  1620   GetInterfaceImpl(aCx, aThis, aThis, aIID, aRetval, aError);
  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)
  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;
  1667   void Truncate() {
  1668     mData = nsDependentString::char_traits::sEmptyBuffer;
  1669     mLength = 0;
  1672   void SetNull() {
  1673     Truncate();
  1674     mFlags |= nsDependentString::F_VOIDED;
  1677   const nsDependentString::char_type* Data() const
  1679     return mData;
  1682   nsDependentString::size_type Length() const
  1684     return mLength;
  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);
  1693   nsAString* ToAStringPtr() {
  1694     return reinterpret_cast<nsDependentString*>(this);
  1697   operator const nsAString& () const {
  1698     return *reinterpret_cast<const nsDependentString*>(this);
  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");
  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)
  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;
  1758     if (behavior != eStringify) {
  1759       if (behavior == eEmpty) {
  1760         result.Truncate();
  1761       } else {
  1762         result.SetNull();
  1764       return true;
  1767     s = JS::ToString(cx, v);
  1768     if (!s) {
  1769       return false;
  1771     pval.set(JS::StringValue(s));  // Root the new string.
  1774   size_t len;
  1775   const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
  1776   if (!chars) {
  1777     return false;
  1780   result.SetData(chars, len);
  1781   return true;
  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>
  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);
  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
  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>
  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>");
  1835 };
  1837 // sequence<any>
  1838 template<>
  1839 class SequenceTracer<JS::Value, false, false, false>
  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>");
  1849 };
  1851 // sequence<sequence<T>>
  1852 template<typename T>
  1853 class SequenceTracer<Sequence<T>, false, false, false>
  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);
  1863 };
  1865 // sequence<sequence<T>> as return value
  1866 template<typename T>
  1867 class SequenceTracer<nsTArray<T>, false, false, false>
  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);
  1877 };
  1879 // sequence<someDictionary>
  1880 template<typename T>
  1881 class SequenceTracer<T, true, false, false>
  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);
  1891 };
  1893 // sequence<SomeTypedArray>
  1894 template<typename T>
  1895 class SequenceTracer<T, false, true, false>
  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);
  1905 };
  1907 // sequence<SomeOwningUnion>
  1908 template<typename T>
  1909 class SequenceTracer<T, false, false, true>
  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);
  1919 };
  1921 // sequence<T?> with T? being a Nullable<T>
  1922 template<typename T>
  1923 class SequenceTracer<Nullable<T>, false, false, false>
  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);
  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)
  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;
  1955 // sequence<MozMap>
  1956 template<typename T>
  1957 class SequenceTracer<MozMap<T>, false, false, false>
  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);
  1967 };
  1969 template<typename T>
  1970 void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq)
  1972   SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
  1973                                    seq.Elements() + seq.Length());
  1976 template<typename T>
  1977 void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq)
  1979   SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
  1980                                    seq.Elements() + seq.Length());
  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
  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)
  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)
  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)
  2012  private:
  2013   enum SequenceType {
  2014     eInfallibleArray,
  2015     eFallibleArray,
  2016     eNullableArray
  2017   };
  2019   virtual void trace(JSTracer *trc) MOZ_OVERRIDE
  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());
  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
  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)
  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)
  2063 private:
  2064   enum MozMapType {
  2065     eMozMap,
  2066     eNullableMozMap
  2067   };
  2069   virtual void trace(JSTracer *trc) MOZ_OVERRIDE
  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;
  2080       mozMap = &mNullableMozMap->Value();
  2083     mozMap->EnumerateValues(TraceMozMapValue<T>, trc);
  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
  2098 public:
  2099   RootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
  2100     T(),
  2101     JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
  2105   virtual void trace(JSTracer *trc) MOZ_OVERRIDE
  2107     this->TraceUnion(trc);
  2109 };
  2111 template<typename T>
  2112 class MOZ_STACK_CLASS NullableRootedUnion : public Nullable<T>,
  2113                                             private JS::CustomAutoRooter
  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)
  2122   virtual void trace(JSTracer *trc) MOZ_OVERRIDE
  2124     if (!this->IsNull()) {
  2125       this->Value().TraceUnion(trc);
  2128 };
  2130 inline bool
  2131 IdEquals(jsid id, const char* string)
  2133   return JSID_IS_STRING(id) &&
  2134          JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
  2137 inline bool
  2138 AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector, const char* name)
  2140   return vector.growBy(1) &&
  2141          InternJSString(cx, vector[vector.length() - 1], name);
  2144 // Implementation of the bits that XrayWrapper needs
  2146 /**
  2147  * This resolves indexed or named properties of obj.
  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.
  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.
  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.
  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)
  2219   const js::Class* clasp = js::GetObjectClass(obj);
  2220   return IsDOMClass(clasp) ||
  2221          JS_IsNativeFunction(obj, Constructor) ||
  2222          IsDOMIfaceAndProtoClass(clasp);
  2225 #ifdef DEBUG
  2226 inline bool
  2227 HasConstructor(JSObject* obj)
  2229   return JS_IsNativeFunction(obj, Constructor) ||
  2230          js::GetObjectClass(obj)->construct;
  2232  #endif
  2234 // Transfer reference in ptr to smartPtr.
  2235 template<class T>
  2236 inline void
  2237 Take(nsRefPtr<T>& smartPtr, T* ptr)
  2239   smartPtr = dont_AddRef(ptr);
  2242 // Transfer ownership of ptr to smartPtr.
  2243 template<class T>
  2244 inline void
  2245 Take(nsAutoPtr<T>& smartPtr, T* ptr)
  2247   smartPtr = ptr;
  2250 inline void
  2251 MustInheritFromNonRefcountedDOMObject(NonRefcountedDOMObject*)
  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.
  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
  2280   static void Finalized(T* self)
  2283 };
  2285 template<class T>
  2286 struct JSBindingFinalized<T, true>
  2288   static void Finalized(T* self)
  2290     self->JSBindingFinalized();
  2292 };
  2294 // Helpers for creating a const version of a type.
  2295 template<typename T>
  2296 const T& Constify(T& arg)
  2298   return arg;
  2301 // Helper for turning (Owning)NonNull<T> into T&
  2302 template<typename T>
  2303 T& NonNullHelper(T& aArg)
  2305   return aArg;
  2308 template<typename T>
  2309 T& NonNullHelper(NonNull<T>& aArg)
  2311   return aArg;
  2314 template<typename T>
  2315 const T& NonNullHelper(const NonNull<T>& aArg)
  2317   return aArg;
  2320 template<typename T>
  2321 T& NonNullHelper(OwningNonNull<T>& aArg)
  2323   return aArg;
  2326 template<typename T>
  2327 const T& NonNullHelper(const OwningNonNull<T>& aArg)
  2329   return aArg;
  2332 inline
  2333 void NonNullHelper(NonNull<binding_detail::FakeDependentString>& aArg)
  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.
  2341 inline
  2342 void NonNullHelper(const NonNull<binding_detail::FakeDependentString>& aArg)
  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.
  2350 inline
  2351 void NonNullHelper(binding_detail::FakeDependentString& aArg)
  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.
  2359 MOZ_ALWAYS_INLINE
  2360 const nsAString& NonNullHelper(const binding_detail::FakeDependentString& aArg)
  2362   return aArg;
  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.
  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)
  2395   ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(aGlobal);
  2396   JSObject* interfaceProto = protoAndIfaceCache.EntrySlotMustExist(aId);
  2397   return &js::GetReservedSlot(interfaceProto,
  2398                               DOM_INTERFACE_PROTO_SLOTS_BASE).toObject();
  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)
  2431     if (str.IsVoid()) {
  2432         rval.setNull();
  2433         return true;
  2435     return NonVoidByteStringToJsval(cx, str, rval);
  2438 template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
  2439 struct PreserveWrapperHelper
  2441   static void PreserveWrapper(T* aObject)
  2443     aObject->PreserveWrapper(aObject, NS_CYCLE_COLLECTION_PARTICIPANT(T));
  2445 };
  2447 template<class T>
  2448 struct PreserveWrapperHelper<T, true>
  2450   static void PreserveWrapper(T* aObject)
  2452     aObject->PreserveWrapper(reinterpret_cast<nsISupports*>(aObject));
  2454 };
  2456 template<class T>
  2457 void PreserveWrapper(T* aObject)
  2459   PreserveWrapperHelper<T>::PreserveWrapper(aObject);
  2462 template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
  2463 struct CastingAssertions
  2465   static bool ToSupportsIsCorrect(T*)
  2467     return true;
  2469   static bool ToSupportsIsOnPrimaryInheritanceChain(T*, nsWrapperCache*)
  2471     return true;
  2473 };
  2475 template<class T>
  2476 struct CastingAssertions<T, true>
  2478   static bool ToSupportsIsCorrect(T* aObject)
  2480     return ToSupports(aObject) ==  reinterpret_cast<nsISupports*>(aObject);
  2482   static bool ToSupportsIsOnPrimaryInheritanceChain(T* aObject,
  2483                                                     nsWrapperCache* aCache)
  2485     return reinterpret_cast<void*>(aObject) != aCache;
  2487 };
  2489 template<class T>
  2490 bool
  2491 ToSupportsIsCorrect(T* aObject)
  2493   return CastingAssertions<T>::ToSupportsIsCorrect(aObject);
  2496 template<class T>
  2497 bool
  2498 ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache)
  2500   return CastingAssertions<T>::ToSupportsIsOnPrimaryInheritanceChain(aObject,
  2501                                                                      aCache);
  2504 template<class T, template <typename> class SmartPtr,
  2505          bool isISupports=IsBaseOf<nsISupports, T>::value>
  2506 class DeferredFinalizer
  2508   typedef nsTArray<SmartPtr<T> > SmartPtrArray;
  2510   static void*
  2511   AppendDeferredFinalizePointer(void* aData, void* aObject)
  2513     SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
  2514     if (!pointers) {
  2515       pointers = new SmartPtrArray();
  2518     T* self = static_cast<T*>(aObject);
  2520     SmartPtr<T>* defer = pointers->AppendElement();
  2521     Take(*defer, self);
  2522     return pointers;
  2524   static bool
  2525   DeferredFinalize(uint32_t aSlice, void* aData)
  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;
  2533     uint32_t newLen = oldLen - aSlice;
  2534     pointers->RemoveElementsAt(newLen, aSlice);
  2535     if (newLen == 0) {
  2536       delete pointers;
  2537       return true;
  2539     return false;
  2542 public:
  2543   static void
  2544   AddForDeferredFinalization(T* aObject)
  2546     cyclecollector::DeferredFinalize(AppendDeferredFinalizePointer,
  2547                                      DeferredFinalize, aObject);
  2549 };
  2551 template<class T, template <typename> class SmartPtr>
  2552 class DeferredFinalizer<T, SmartPtr, true>
  2554 public:
  2555   static void
  2556   AddForDeferredFinalization(T* aObject)
  2558     cyclecollector::DeferredFinalize(reinterpret_cast<nsISupports*>(aObject));
  2560 };
  2562 template<class T, template <typename> class SmartPtr>
  2563 static void
  2564 AddForDeferredFinalization(T* aObject)
  2566   DeferredFinalizer<T, SmartPtr>::AddForDeferredFinalization(aObject);
  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
  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)
  2580     return T::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant();
  2582   // Helper for GetCCParticipant for classes that don't participate in CC.
  2583   template<class U>
  2584   static MOZ_CONSTEXPR nsCycleCollectionParticipant*
  2585   GetHelper(double)
  2587     return nullptr;
  2590 public:
  2591   static MOZ_CONSTEXPR nsCycleCollectionParticipant*
  2592   Get()
  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());
  2600 };
  2602 template<class T>
  2603 class GetCCParticipant<T, true>
  2605 public:
  2606   static MOZ_CONSTEXPR nsCycleCollectionParticipant*
  2607   Get()
  2609     return nullptr;
  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)
  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;
  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;
  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;
  2684   MOZ_ALWAYS_TRUE(TryPreserveWrapper(global));
  2686   MOZ_ASSERT(UnwrapDOMObjectToISupports(global));
  2688   return global;
  2691 /*
  2692  * Holds a jsid that is initialized to an interned string, with conversion to
  2693  * Handle<jsid>.
  2694  */
  2695 class InternedStringId
  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;
  2710   operator const jsid& () {
  2711     return id;
  2714   operator JS::Handle<jsid> () {
  2715     /* This is safe because we have interned the string. */
  2716     return JS::Handle<jsid>::fromMarkedLocation(&id);
  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__ */

mercurial