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.

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

mercurial