Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef mozilla_dom_BindingUtils_h__
8 : #define mozilla_dom_BindingUtils_h__
9 :
10 : #include "jsfriendapi.h"
11 : #include "jswrapper.h"
12 : #include "js/Conversions.h"
13 : #include "mozilla/ArrayUtils.h"
14 : #include "mozilla/Alignment.h"
15 : #include "mozilla/Array.h"
16 : #include "mozilla/Assertions.h"
17 : #include "mozilla/CycleCollectedJSContext.h"
18 : #include "mozilla/DeferredFinalize.h"
19 : #include "mozilla/dom/BindingDeclarations.h"
20 : #include "mozilla/dom/CallbackObject.h"
21 : #include "mozilla/dom/DOMJSClass.h"
22 : #include "mozilla/dom/DOMJSProxyHandler.h"
23 : #include "mozilla/dom/Exceptions.h"
24 : #include "mozilla/dom/NonRefcountedDOMObject.h"
25 : #include "mozilla/dom/Nullable.h"
26 : #include "mozilla/dom/RootedDictionary.h"
27 : #include "mozilla/SegmentedVector.h"
28 : #include "mozilla/ErrorResult.h"
29 : #include "mozilla/Likely.h"
30 : #include "mozilla/MemoryReporting.h"
31 : #include "nsAutoPtr.h"
32 : #include "nsIDocument.h"
33 : #include "nsIGlobalObject.h"
34 : #include "nsIXPConnect.h"
35 : #include "nsJSUtils.h"
36 : #include "nsISupportsImpl.h"
37 : #include "qsObjectHelper.h"
38 : #include "xpcpublic.h"
39 : #include "nsIVariant.h"
40 : #include "mozilla/dom/FakeString.h"
41 :
42 : #include "nsWrapperCacheInlines.h"
43 :
44 : class nsGenericHTMLElement;
45 : class nsIJSID;
46 :
47 : namespace mozilla {
48 :
49 : enum UseCounter : int16_t;
50 :
51 : namespace dom {
52 : class CustomElementReactionsStack;
53 : template<typename KeyType, typename ValueType> class Record;
54 :
55 : nsresult
56 : UnwrapArgImpl(JSContext* cx, JS::Handle<JSObject*> src, const nsIID& iid,
57 : void** ppArg);
58 :
59 : nsresult
60 : UnwrapWindowProxyImpl(JSContext* cx, JS::Handle<JSObject*> src,
61 : nsPIDOMWindowOuter** ppArg);
62 :
63 : /** Convert a jsval to an XPCOM pointer. Caller must not assume that src will
64 : keep the XPCOM pointer rooted. */
65 : template <class Interface>
66 : inline nsresult
67 266 : UnwrapArg(JSContext* cx, JS::Handle<JSObject*> src, Interface** ppArg)
68 : {
69 : return UnwrapArgImpl(cx, src, NS_GET_TEMPLATE_IID(Interface),
70 266 : reinterpret_cast<void**>(ppArg));
71 : }
72 :
73 : template <>
74 : inline nsresult
75 0 : UnwrapArg<nsPIDOMWindowOuter>(JSContext* cx, JS::Handle<JSObject*> src,
76 : nsPIDOMWindowOuter** ppArg)
77 : {
78 0 : return UnwrapWindowProxyImpl(cx, src, ppArg);
79 : }
80 :
81 : nsresult
82 : UnwrapXPConnectImpl(JSContext* cx, JS::MutableHandle<JS::Value> src,
83 : const nsIID& iid, void** ppArg);
84 :
85 : /*
86 : * Convert a jsval being used as a Web IDL interface implementation to an XPCOM
87 : * pointer; this is only used for Web IDL interfaces that specify
88 : * hasXPConnectImpls. This is not the same as UnwrapArg because caller _can_
89 : * assume that if unwrapping succeeds "val" will be updated so it's rooting the
90 : * XPCOM pointer. Also, UnwrapXPConnect doesn't need to worry about doing
91 : * XPCWrappedJS things.
92 : *
93 : * val must be an ObjectValue.
94 : */
95 : template<class Interface>
96 : inline nsresult
97 0 : UnwrapXPConnect(JSContext* cx, JS::MutableHandle<JS::Value> val,
98 : Interface** ppThis)
99 : {
100 : return UnwrapXPConnectImpl(cx, val, NS_GET_TEMPLATE_IID(Interface),
101 0 : reinterpret_cast<void**>(ppThis));
102 : }
103 :
104 : bool
105 : ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
106 : bool aSecurityError, const char* aInterfaceName);
107 :
108 : bool
109 : ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
110 : bool aSecurityError, prototypes::ID aProtoId);
111 :
112 : // Returns true if the JSClass is used for DOM objects.
113 : inline bool
114 29874 : IsDOMClass(const JSClass* clasp)
115 : {
116 29874 : return clasp->flags & JSCLASS_IS_DOMJSCLASS;
117 : }
118 :
119 : inline bool
120 29873 : IsDOMClass(const js::Class* clasp)
121 : {
122 29873 : return IsDOMClass(Jsvalify(clasp));
123 : }
124 :
125 : // Return true if the JSClass is used for non-proxy DOM objects.
126 : inline bool
127 : IsNonProxyDOMClass(const js::Class* clasp)
128 : {
129 : return IsDOMClass(clasp) && !clasp->isProxy();
130 : }
131 :
132 : inline bool
133 : IsNonProxyDOMClass(const JSClass* clasp)
134 : {
135 : return IsNonProxyDOMClass(js::Valueify(clasp));
136 : }
137 :
138 : // Returns true if the JSClass is used for DOM interface and interface
139 : // prototype objects.
140 : inline bool
141 1412 : IsDOMIfaceAndProtoClass(const JSClass* clasp)
142 : {
143 1412 : return clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS;
144 : }
145 :
146 : inline bool
147 1412 : IsDOMIfaceAndProtoClass(const js::Class* clasp)
148 : {
149 1412 : return IsDOMIfaceAndProtoClass(Jsvalify(clasp));
150 : }
151 :
152 : static_assert(DOM_OBJECT_SLOT == 0,
153 : "DOM_OBJECT_SLOT doesn't match the proxy private slot. "
154 : "Expect bad things");
155 : template <class T>
156 : inline T*
157 4460 : UnwrapDOMObject(JSObject* obj)
158 : {
159 4460 : MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
160 : "Don't pass non-DOM objects to this function");
161 :
162 4460 : JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
163 4460 : return static_cast<T*>(val.toPrivate());
164 : }
165 :
166 : template <class T>
167 : inline T*
168 5230 : UnwrapPossiblyNotInitializedDOMObject(JSObject* obj)
169 : {
170 : // This is used by the OjectMoved JSClass hook which can be called before
171 : // JS_NewObject has returned and so before we have a chance to set
172 : // DOM_OBJECT_SLOT to anything useful.
173 :
174 5230 : MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
175 : "Don't pass non-DOM objects to this function");
176 :
177 5230 : JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
178 5230 : if (val.isUndefined()) {
179 98 : return nullptr;
180 : }
181 5132 : return static_cast<T*>(val.toPrivate());
182 : }
183 :
184 : inline const DOMJSClass*
185 17735 : GetDOMClass(const js::Class* clasp)
186 : {
187 17735 : return IsDOMClass(clasp) ? DOMJSClass::FromJSClass(clasp) : nullptr;
188 : }
189 :
190 : inline const DOMJSClass*
191 17386 : GetDOMClass(JSObject* obj)
192 : {
193 17386 : return GetDOMClass(js::GetObjectClass(obj));
194 : }
195 :
196 : inline nsISupports*
197 7455 : UnwrapDOMObjectToISupports(JSObject* aObject)
198 : {
199 7455 : const DOMJSClass* clasp = GetDOMClass(aObject);
200 7455 : if (!clasp || !clasp->mDOMObjectIsISupports) {
201 5633 : return nullptr;
202 : }
203 :
204 1822 : return UnwrapPossiblyNotInitializedDOMObject<nsISupports>(aObject);
205 : }
206 :
207 : inline bool
208 1169 : IsDOMObject(JSObject* obj)
209 : {
210 1169 : return IsDOMClass(js::GetObjectClass(obj));
211 : }
212 :
213 : // There are two valid ways to use UNWRAP_OBJECT: Either obj needs to
214 : // be a MutableHandle<JSObject*>, or value needs to be a strong-reference
215 : // smart pointer type (OwningNonNull or RefPtr or nsCOMPtr), in which case obj
216 : // can be anything that converts to JSObject*.
217 : #define UNWRAP_OBJECT(Interface, obj, value) \
218 : mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface, \
219 : mozilla::dom::Interface##Binding::NativeType>(obj, value)
220 :
221 : // Test whether the given object is an instance of the given interface.
222 : #define IS_INSTANCE_OF(Interface, obj) \
223 : mozilla::dom::IsInstanceOf<mozilla::dom::prototypes::id::Interface, \
224 : mozilla::dom::Interface##Binding::NativeType>(obj)
225 :
226 : // Unwrap the given non-wrapper object. This can be used with any obj that
227 : // converts to JSObject*; as long as that JSObject* is live the return value
228 : // will be valid.
229 : #define UNWRAP_NON_WRAPPER_OBJECT(Interface, obj, value) \
230 : mozilla::dom::UnwrapNonWrapperObject<mozilla::dom::prototypes::id::Interface, \
231 : mozilla::dom::Interface##Binding::NativeType>(obj, value)
232 :
233 : // Some callers don't want to set an exception when unwrapping fails
234 : // (for example, overload resolution uses unwrapping to tell what sort
235 : // of thing it's looking at).
236 : // U must be something that a T* can be assigned to (e.g. T* or an RefPtr<T>).
237 : //
238 : // The obj argument will be mutated to point to CheckedUnwrap of itself if the
239 : // passed-in value is not a DOM object and CheckedUnwrap succeeds.
240 : //
241 : // If mayBeWrapper is true, there are three valid ways to invoke
242 : // UnwrapObjectInternal: Either obj needs to be a class wrapping a
243 : // MutableHandle<JSObject*>, with an assignment operator that sets the handle to
244 : // the given object, or U needs to be a strong-reference smart pointer type
245 : // (OwningNonNull or RefPtr or nsCOMPtr), or the value being stored in "value"
246 : // must not escape past being tested for falsiness immediately after the
247 : // UnwrapObjectInternal call.
248 : //
249 : // If mayBeWrapper is false, obj can just be a JSObject*, and U anything that a
250 : // T* can be assigned to.
251 : namespace binding_detail {
252 : template <class T, bool mayBeWrapper, typename U, typename V>
253 : MOZ_ALWAYS_INLINE nsresult
254 5117 : UnwrapObjectInternal(V& obj, U& value, prototypes::ID protoID,
255 : uint32_t protoDepth)
256 : {
257 : /* First check to see whether we have a DOM object */
258 5117 : const DOMJSClass* domClass = GetDOMClass(obj);
259 5117 : if (domClass) {
260 : /* This object is a DOM object. Double-check that it is safely
261 : castable to T by checking whether it claims to inherit from the
262 : class identified by protoID. */
263 4451 : if (domClass->mInterfaceChain[protoDepth] == protoID) {
264 4450 : value = UnwrapDOMObject<T>(obj);
265 4450 : return NS_OK;
266 : }
267 : }
268 :
269 : /* Maybe we have a security wrapper or outer window? */
270 667 : if (!mayBeWrapper || !js::IsWrapper(obj)) {
271 : /* Not a DOM object, not a wrapper, just bail */
272 287 : return NS_ERROR_XPC_BAD_CONVERT_JS;
273 : }
274 :
275 : JSObject* unwrappedObj =
276 380 : js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
277 380 : if (!unwrappedObj) {
278 0 : return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
279 : }
280 380 : MOZ_ASSERT(!js::IsWrapper(unwrappedObj));
281 : // Recursive call is OK, because now we're using false for mayBeWrapper and
282 : // we never reach this code if that boolean is false, so can't keep calling
283 : // ourselves.
284 : //
285 : // Unwrap into a temporary pointer, because in general unwrapping into
286 : // something of type U might trigger GC (e.g. release the value currently
287 : // stored in there, with arbitrary consequences) and invalidate the
288 : // "unwrappedObj" pointer.
289 : T* tempValue;
290 380 : nsresult rv = UnwrapObjectInternal<T, false>(unwrappedObj, tempValue,
291 380 : protoID, protoDepth);
292 380 : if (NS_SUCCEEDED(rv)) {
293 : // It's very important to not update "obj" with the "unwrappedObj" value
294 : // until we know the unwrap has succeeded. Otherwise, in a situation in
295 : // which we have an overload of object and primitive we could end up
296 : // converting to the primitive from the unwrappedObj, whereas we want to do
297 : // it from the original object.
298 380 : obj = unwrappedObj;
299 : // And now assign to "value"; at this point we don't care if a GC happens
300 : // and invalidates unwrappedObj.
301 380 : value = tempValue;
302 380 : return NS_OK;
303 : }
304 :
305 : /* It's the wrong sort of DOM object */
306 0 : return NS_ERROR_XPC_BAD_CONVERT_JS;
307 : }
308 :
309 : struct MutableObjectHandleWrapper {
310 2445 : explicit MutableObjectHandleWrapper(JS::MutableHandle<JSObject*> aHandle)
311 2445 : : mHandle(aHandle)
312 : {
313 2445 : }
314 :
315 138 : void operator=(JSObject* aObject)
316 : {
317 138 : MOZ_ASSERT(aObject);
318 138 : mHandle.set(aObject);
319 138 : }
320 :
321 5028 : operator JSObject*() const
322 : {
323 5028 : return mHandle;
324 : }
325 :
326 : private:
327 : JS::MutableHandle<JSObject*> mHandle;
328 : };
329 :
330 : struct MutableValueHandleWrapper {
331 838 : explicit MutableValueHandleWrapper(JS::MutableHandle<JS::Value> aHandle)
332 838 : : mHandle(aHandle)
333 : {
334 838 : }
335 :
336 242 : void operator=(JSObject* aObject)
337 : {
338 242 : MOZ_ASSERT(aObject);
339 242 : mHandle.setObject(*aObject);
340 242 : }
341 :
342 1918 : operator JSObject*() const
343 : {
344 1918 : return &mHandle.toObject();
345 : }
346 :
347 : private:
348 : JS::MutableHandle<JS::Value> mHandle;
349 : };
350 :
351 : } // namespace binding_detail
352 :
353 : // UnwrapObject overloads that ensure we have a MutableHandle to keep it alive.
354 : template<prototypes::ID PrototypeID, class T, typename U>
355 : MOZ_ALWAYS_INLINE nsresult
356 404 : UnwrapObject(JS::MutableHandle<JSObject*> obj, U& value)
357 : {
358 404 : binding_detail::MutableObjectHandleWrapper wrapper(obj);
359 : return binding_detail::UnwrapObjectInternal<T, true>(
360 404 : wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
361 : }
362 :
363 : template<prototypes::ID PrototypeID, class T, typename U>
364 : MOZ_ALWAYS_INLINE nsresult
365 838 : UnwrapObject(JS::MutableHandle<JS::Value> obj, U& value)
366 : {
367 838 : MOZ_ASSERT(obj.isObject());
368 838 : binding_detail::MutableValueHandleWrapper wrapper(obj);
369 : return binding_detail::UnwrapObjectInternal<T, true>(
370 838 : wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
371 : }
372 :
373 : // UnwrapObject overloads that ensure we have a strong ref to keep it alive.
374 : template<prototypes::ID PrototypeID, class T, typename U>
375 : MOZ_ALWAYS_INLINE nsresult
376 0 : UnwrapObject(JSObject* obj, RefPtr<U>& value)
377 : {
378 : return binding_detail::UnwrapObjectInternal<T, true>(
379 0 : obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
380 : }
381 :
382 : template<prototypes::ID PrototypeID, class T, typename U>
383 : MOZ_ALWAYS_INLINE nsresult
384 : UnwrapObject(JSObject* obj, nsCOMPtr<U>& value)
385 : {
386 : return binding_detail::UnwrapObjectInternal<T, true>(
387 : obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
388 : }
389 :
390 : template<prototypes::ID PrototypeID, class T, typename U>
391 : MOZ_ALWAYS_INLINE nsresult
392 0 : UnwrapObject(JSObject* obj, OwningNonNull<U>& value)
393 : {
394 : return binding_detail::UnwrapObjectInternal<T, true>(
395 0 : obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
396 : }
397 :
398 : // An UnwrapObject overload that just calls one of the JSObject* ones.
399 : template<prototypes::ID PrototypeID, class T, typename U>
400 : MOZ_ALWAYS_INLINE nsresult
401 0 : UnwrapObject(JS::Handle<JS::Value> obj, U& value)
402 : {
403 0 : MOZ_ASSERT(obj.isObject());
404 0 : return UnwrapObject<PrototypeID, T>(&obj.toObject(), value);
405 : }
406 :
407 : template<prototypes::ID PrototypeID, class T>
408 : MOZ_ALWAYS_INLINE bool
409 1 : IsInstanceOf(JSObject* obj)
410 : {
411 : void* ignored;
412 : nsresult unwrapped = binding_detail::UnwrapObjectInternal<T, true>(
413 1 : obj, ignored, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
414 1 : return NS_SUCCEEDED(unwrapped);
415 : }
416 :
417 : template<prototypes::ID PrototypeID, class T, typename U>
418 : MOZ_ALWAYS_INLINE nsresult
419 1453 : UnwrapNonWrapperObject(JSObject* obj, U& value)
420 : {
421 1453 : MOZ_ASSERT(!js::IsWrapper(obj));
422 : return binding_detail::UnwrapObjectInternal<T, false>(
423 1453 : obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
424 : }
425 :
426 : MOZ_ALWAYS_INLINE bool
427 2651 : IsConvertibleToDictionary(JS::Handle<JS::Value> val)
428 : {
429 2651 : return val.isNullOrUndefined() || val.isObject();
430 : }
431 :
432 : // The items in the protoAndIfaceCache are indexed by the prototypes::id::ID,
433 : // constructors::id::ID and namedpropertiesobjects::id::ID enums, in that order.
434 : // The end of the prototype objects should be the start of the interface
435 : // objects, and the end of the interface objects should be the start of the
436 : // named properties objects.
437 : static_assert((size_t)constructors::id::_ID_Start ==
438 : (size_t)prototypes::id::_ID_Count &&
439 : (size_t)namedpropertiesobjects::id::_ID_Start ==
440 : (size_t)constructors::id::_ID_Count,
441 : "Overlapping or discontiguous indexes.");
442 : const size_t kProtoAndIfaceCacheCount = namedpropertiesobjects::id::_ID_Count;
443 :
444 : class ProtoAndIfaceCache
445 : {
446 : // The caching strategy we use depends on what sort of global we're dealing
447 : // with. For a window-like global, we want everything to be as fast as
448 : // possible, so we use a flat array, indexed by prototype/constructor ID.
449 : // For everything else (e.g. globals for JSMs), space is more important than
450 : // speed, so we use a two-level lookup table.
451 :
452 7 : class ArrayCache : public Array<JS::Heap<JSObject*>, kProtoAndIfaceCacheCount>
453 : {
454 : public:
455 1280 : bool HasEntryInSlot(size_t i) {
456 1280 : return (*this)[i];
457 : }
458 :
459 221 : JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
460 221 : return (*this)[i];
461 : }
462 :
463 1290 : JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
464 1290 : return (*this)[i];
465 : }
466 :
467 0 : void Trace(JSTracer* aTracer) {
468 0 : for (size_t i = 0; i < ArrayLength(*this); ++i) {
469 0 : JS::TraceEdge(aTracer, &(*this)[i], "protoAndIfaceCache[i]");
470 : }
471 0 : }
472 :
473 0 : size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
474 0 : return aMallocSizeOf(this);
475 : }
476 : };
477 :
478 : class PageTableCache
479 : {
480 : public:
481 286 : PageTableCache() {
482 286 : memset(&mPages, 0, sizeof(mPages));
483 286 : }
484 :
485 0 : ~PageTableCache() {
486 0 : for (size_t i = 0; i < ArrayLength(mPages); ++i) {
487 0 : delete mPages[i];
488 : }
489 0 : }
490 :
491 2659 : bool HasEntryInSlot(size_t i) {
492 2659 : MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
493 2659 : size_t pageIndex = i / kPageSize;
494 2659 : size_t leafIndex = i % kPageSize;
495 2659 : Page* p = mPages[pageIndex];
496 2659 : if (!p) {
497 139 : return false;
498 : }
499 2520 : return (*p)[leafIndex];
500 : }
501 :
502 735 : JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
503 735 : MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
504 735 : size_t pageIndex = i / kPageSize;
505 735 : size_t leafIndex = i % kPageSize;
506 735 : Page* p = mPages[pageIndex];
507 735 : if (!p) {
508 251 : p = new Page;
509 251 : mPages[pageIndex] = p;
510 : }
511 735 : return (*p)[leafIndex];
512 : }
513 :
514 2666 : JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
515 2666 : MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
516 2666 : size_t pageIndex = i / kPageSize;
517 2666 : size_t leafIndex = i % kPageSize;
518 2666 : Page* p = mPages[pageIndex];
519 2666 : MOZ_ASSERT(p);
520 2666 : return (*p)[leafIndex];
521 : }
522 :
523 1 : void Trace(JSTracer* trc) {
524 98 : for (size_t i = 0; i < ArrayLength(mPages); ++i) {
525 97 : Page* p = mPages[i];
526 97 : if (p) {
527 102 : for (size_t j = 0; j < ArrayLength(*p); ++j) {
528 96 : JS::TraceEdge(trc, &(*p)[j], "protoAndIfaceCache[i]");
529 : }
530 : }
531 : }
532 1 : }
533 :
534 0 : size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
535 0 : size_t n = aMallocSizeOf(this);
536 0 : for (size_t i = 0; i < ArrayLength(mPages); ++i) {
537 0 : n += aMallocSizeOf(mPages[i]);
538 : }
539 0 : return n;
540 : }
541 :
542 : private:
543 : static const size_t kPageSize = 16;
544 : typedef Array<JS::Heap<JSObject*>, kPageSize> Page;
545 : static const size_t kNPages = kProtoAndIfaceCacheCount / kPageSize +
546 : size_t(bool(kProtoAndIfaceCacheCount % kPageSize));
547 : Array<Page*, kNPages> mPages;
548 : };
549 :
550 : public:
551 : enum Kind {
552 : WindowLike,
553 : NonWindowLike
554 : };
555 :
556 293 : explicit ProtoAndIfaceCache(Kind aKind) : mKind(aKind) {
557 293 : MOZ_COUNT_CTOR(ProtoAndIfaceCache);
558 293 : if (aKind == WindowLike) {
559 7 : mArrayCache = new ArrayCache();
560 : } else {
561 286 : mPageTableCache = new PageTableCache();
562 : }
563 293 : }
564 :
565 0 : ~ProtoAndIfaceCache() {
566 0 : if (mKind == WindowLike) {
567 0 : delete mArrayCache;
568 : } else {
569 0 : delete mPageTableCache;
570 : }
571 0 : MOZ_COUNT_DTOR(ProtoAndIfaceCache);
572 0 : }
573 :
574 : #define FORWARD_OPERATION(opName, args) \
575 : do { \
576 : if (mKind == WindowLike) { \
577 : return mArrayCache->opName args; \
578 : } else { \
579 : return mPageTableCache->opName args; \
580 : } \
581 : } while(0)
582 :
583 : // Return whether slot i contains an object. This doesn't return the object
584 : // itself because in practice consumers just want to know whether it's there
585 : // or not, and that doesn't require barriering, which returning the object
586 : // pointer does.
587 3939 : bool HasEntryInSlot(size_t i) {
588 3939 : FORWARD_OPERATION(HasEntryInSlot, (i));
589 : }
590 :
591 : // Return a reference to slot i, creating it if necessary. There
592 : // may not be an object in the returned slot.
593 956 : JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
594 956 : FORWARD_OPERATION(EntrySlotOrCreate, (i));
595 : }
596 :
597 : // Return a reference to slot i, which is guaranteed to already
598 : // exist. There may not be an object in the slot, if prototype and
599 : // constructor initialization for one of our bindings failed.
600 3956 : JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
601 3956 : FORWARD_OPERATION(EntrySlotMustExist, (i));
602 : }
603 :
604 1 : void Trace(JSTracer *aTracer) {
605 1 : FORWARD_OPERATION(Trace, (aTracer));
606 : }
607 :
608 0 : size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
609 0 : size_t n = aMallocSizeOf(this);
610 0 : n += (mKind == WindowLike
611 0 : ? mArrayCache->SizeOfIncludingThis(aMallocSizeOf)
612 0 : : mPageTableCache->SizeOfIncludingThis(aMallocSizeOf));
613 0 : return n;
614 : }
615 : #undef FORWARD_OPERATION
616 :
617 : private:
618 : union {
619 : ArrayCache *mArrayCache;
620 : PageTableCache *mPageTableCache;
621 : };
622 : Kind mKind;
623 : };
624 :
625 : inline void
626 293 : AllocateProtoAndIfaceCache(JSObject* obj, ProtoAndIfaceCache::Kind aKind)
627 : {
628 293 : MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
629 293 : MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
630 :
631 293 : ProtoAndIfaceCache* protoAndIfaceCache = new ProtoAndIfaceCache(aKind);
632 :
633 : js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
634 293 : JS::PrivateValue(protoAndIfaceCache));
635 293 : }
636 :
637 : #ifdef DEBUG
638 : struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JS::CallbackTracer
639 : {
640 : bool ok;
641 :
642 25 : explicit VerifyTraceProtoAndIfaceCacheCalledTracer(JSContext* cx)
643 25 : : JS::CallbackTracer(cx), ok(false)
644 25 : {}
645 :
646 100 : void onChild(const JS::GCCellPtr&) override {
647 : // We don't do anything here, we only want to verify that
648 : // TraceProtoAndIfaceCache was called.
649 100 : }
650 :
651 425 : TracerKind getTracerKind() const override { return TracerKind::VerifyTraceProtoAndIface; }
652 : };
653 : #endif
654 :
655 : inline void
656 26 : TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
657 : {
658 26 : MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
659 :
660 : #ifdef DEBUG
661 51 : if (trc->isCallbackTracer() &&
662 25 : (trc->asCallbackTracer()->getTracerKind() ==
663 : JS::CallbackTracer::TracerKind::VerifyTraceProtoAndIface)) {
664 : // We don't do anything here, we only want to verify that
665 : // TraceProtoAndIfaceCache was called.
666 25 : static_cast<VerifyTraceProtoAndIfaceCacheCalledTracer*>(trc)->ok = true;
667 25 : return;
668 : }
669 : #endif
670 :
671 1 : if (!DOMGlobalHasProtoAndIFaceCache(obj))
672 0 : return;
673 1 : ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
674 1 : protoAndIfaceCache->Trace(trc);
675 : }
676 :
677 : inline void
678 0 : DestroyProtoAndIfaceCache(JSObject* obj)
679 : {
680 0 : MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
681 :
682 0 : if (!DOMGlobalHasProtoAndIFaceCache(obj)) {
683 0 : return;
684 : }
685 :
686 0 : ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
687 :
688 0 : delete protoAndIfaceCache;
689 : }
690 :
691 : /**
692 : * Add constants to an object.
693 : */
694 : bool
695 : DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
696 : const ConstantSpec* cs);
697 :
698 : struct JSNativeHolder
699 : {
700 : JSNative mNative;
701 : const NativePropertyHooks* mPropertyHooks;
702 : };
703 :
704 : struct NamedConstructor
705 : {
706 : const char* mName;
707 : const JSNativeHolder mHolder;
708 : unsigned mNargs;
709 : };
710 :
711 : /*
712 : * Create a DOM interface object (if constructorClass is non-null) and/or a
713 : * DOM interface prototype object (if protoClass is non-null).
714 : *
715 : * global is used as the parent of the interface object and the interface
716 : * prototype object
717 : * protoProto is the prototype to use for the interface prototype object.
718 : * interfaceProto is the prototype to use for the interface object. This can be
719 : * null if both constructorClass and constructor are null (as in,
720 : * if we're not creating an interface object at all).
721 : * protoClass is the JSClass to use for the interface prototype object.
722 : * This is null if we should not create an interface prototype
723 : * object.
724 : * protoCache a pointer to a JSObject pointer where we should cache the
725 : * interface prototype object. This must be null if protoClass is and
726 : * vice versa.
727 : * constructorClass is the JSClass to use for the interface object.
728 : * This is null if we should not create an interface object or
729 : * if it should be a function object.
730 : * constructor holds the JSNative to back the interface object which should be a
731 : * Function, unless constructorClass is non-null in which case it is
732 : * ignored. If this is null and constructorClass is also null then
733 : * we should not create an interface object at all.
734 : * ctorNargs is the length of the constructor function; 0 if no constructor
735 : * constructorCache a pointer to a JSObject pointer where we should cache the
736 : * interface object. This must be null if both constructorClass
737 : * and constructor are null, and non-null otherwise.
738 : * properties contains the methods, attributes and constants to be defined on
739 : * objects in any compartment.
740 : * chromeProperties contains the methods, attributes and constants to be defined
741 : * on objects in chrome compartments. This must be null if the
742 : * interface doesn't have any ChromeOnly properties or if the
743 : * object is being created in non-chrome compartment.
744 : * defineOnGlobal controls whether properties should be defined on the given
745 : * global for the interface object (if any) and named
746 : * constructors (if any) for this interface. This can be
747 : * false in situations where we want the properties to only
748 : * appear on privileged Xrays but not on the unprivileged
749 : * underlying global.
750 : * unscopableNames if not null it points to a null-terminated list of const
751 : * char* names of the unscopable properties for this interface.
752 : * isGlobal if true, we're creating interface objects for a [Global] or
753 : * [PrimaryGlobal] interface, and hence shouldn't define properties on
754 : * the prototype object.
755 : *
756 : * At least one of protoClass, constructorClass or constructor should be
757 : * non-null. If constructorClass or constructor are non-null, the resulting
758 : * interface object will be defined on the given global with property name
759 : * |name|, which must also be non-null.
760 : */
761 : void
762 : CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
763 : JS::Handle<JSObject*> protoProto,
764 : const js::Class* protoClass, JS::Heap<JSObject*>* protoCache,
765 : JS::Handle<JSObject*> interfaceProto,
766 : const js::Class* constructorClass,
767 : unsigned ctorNargs, const NamedConstructor* namedConstructors,
768 : JS::Heap<JSObject*>* constructorCache,
769 : const NativeProperties* regularProperties,
770 : const NativeProperties* chromeOnlyProperties,
771 : const char* name, bool defineOnGlobal,
772 : const char* const* unscopableNames,
773 : bool isGlobal);
774 :
775 : /**
776 : * Define the properties (regular and chrome-only) on obj.
777 : *
778 : * obj the object to instal the properties on. This should be the interface
779 : * prototype object for regular interfaces and the instance object for
780 : * interfaces marked with Global.
781 : * properties contains the methods, attributes and constants to be defined on
782 : * objects in any compartment.
783 : * chromeProperties contains the methods, attributes and constants to be defined
784 : * on objects in chrome compartments. This must be null if the
785 : * interface doesn't have any ChromeOnly properties or if the
786 : * object is being created in non-chrome compartment.
787 : */
788 : bool
789 : DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
790 : const NativeProperties* properties,
791 : const NativeProperties* chromeOnlyProperties);
792 :
793 : /*
794 : * Define the unforgeable methods on an object.
795 : */
796 : bool
797 : DefineUnforgeableMethods(JSContext* cx, JS::Handle<JSObject*> obj,
798 : const Prefable<const JSFunctionSpec>* props);
799 :
800 : /*
801 : * Define the unforgeable attributes on an object.
802 : */
803 : bool
804 : DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
805 : const Prefable<const JSPropertySpec>* props);
806 :
807 : #define HAS_MEMBER_TYPEDEFS \
808 : private: \
809 : typedef char yes[1]; \
810 : typedef char no[2]
811 :
812 : #ifdef _MSC_VER
813 : #define HAS_MEMBER_CHECK(_name) \
814 : template<typename V> static yes& Check##_name(char (*)[(&V::_name == 0) + 1])
815 : #else
816 : #define HAS_MEMBER_CHECK(_name) \
817 : template<typename V> static yes& Check##_name(char (*)[sizeof(&V::_name) + 1])
818 : #endif
819 :
820 : #define HAS_MEMBER(_memberName, _valueName) \
821 : private: \
822 : HAS_MEMBER_CHECK(_memberName); \
823 : template<typename V> static no& Check##_memberName(...); \
824 : \
825 : public: \
826 : static bool const _valueName = \
827 : sizeof(Check##_memberName<T>(nullptr)) == sizeof(yes)
828 :
829 : template<class T>
830 : struct NativeHasMember
831 : {
832 : HAS_MEMBER_TYPEDEFS;
833 :
834 : HAS_MEMBER(GetParentObject, GetParentObject);
835 : HAS_MEMBER(WrapObject, WrapObject);
836 : };
837 :
838 : template<class T>
839 : struct IsSmartPtr
840 : {
841 : HAS_MEMBER_TYPEDEFS;
842 :
843 : HAS_MEMBER(get, value);
844 : };
845 :
846 : template<class T>
847 : struct IsRefcounted
848 : {
849 : HAS_MEMBER_TYPEDEFS;
850 :
851 : HAS_MEMBER(AddRef, HasAddref);
852 : HAS_MEMBER(Release, HasRelease);
853 :
854 : public:
855 : static bool const value = HasAddref && HasRelease;
856 :
857 : private:
858 : // This struct only works if T is fully declared (not just forward declared).
859 : // The IsBaseOf check will ensure that, we don't really need it for any other
860 : // reason (the static assert will of course always be true).
861 : static_assert(!IsBaseOf<nsISupports, T>::value || IsRefcounted::value,
862 : "Classes derived from nsISupports are refcounted!");
863 :
864 : };
865 :
866 : #undef HAS_MEMBER
867 : #undef HAS_MEMBER_CHECK
868 : #undef HAS_MEMBER_TYPEDEFS
869 :
870 : #ifdef DEBUG
871 : template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
872 : struct
873 : CheckWrapperCacheCast
874 : {
875 0 : static bool Check()
876 : {
877 : return reinterpret_cast<uintptr_t>(
878 : static_cast<nsWrapperCache*>(
879 0 : reinterpret_cast<T*>(1))) == 1;
880 : }
881 : };
882 : template <class T>
883 : struct
884 : CheckWrapperCacheCast<T, true>
885 : {
886 4420 : static bool Check()
887 : {
888 4420 : return true;
889 : }
890 : };
891 : #endif
892 :
893 : MOZ_ALWAYS_INLINE bool
894 7 : CouldBeDOMBinding(void*)
895 : {
896 7 : return true;
897 : }
898 :
899 : MOZ_ALWAYS_INLINE bool
900 4416 : CouldBeDOMBinding(nsWrapperCache* aCache)
901 : {
902 4416 : return aCache->IsDOMBinding();
903 : }
904 :
905 : inline bool
906 347 : TryToOuterize(JS::MutableHandle<JS::Value> rval)
907 : {
908 347 : if (js::IsWindow(&rval.toObject())) {
909 31 : JSObject* obj = js::ToWindowProxyIfWindow(&rval.toObject());
910 31 : MOZ_ASSERT(obj);
911 31 : rval.set(JS::ObjectValue(*obj));
912 : }
913 :
914 347 : return true;
915 : }
916 :
917 : // Make sure to wrap the given string value into the right compartment, as
918 : // needed.
919 : MOZ_ALWAYS_INLINE
920 : bool
921 5 : MaybeWrapStringValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
922 : {
923 5 : MOZ_ASSERT(rval.isString());
924 5 : JSString* str = rval.toString();
925 5 : if (JS::GetStringZone(str) != js::GetContextZone(cx)) {
926 1 : return JS_WrapValue(cx, rval);
927 : }
928 4 : return true;
929 : }
930 :
931 : // Make sure to wrap the given object value into the right compartment as
932 : // needed. This will work correctly, but possibly slowly, on all objects.
933 : MOZ_ALWAYS_INLINE
934 : bool
935 567 : MaybeWrapObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
936 : {
937 567 : MOZ_ASSERT(rval.isObject());
938 :
939 : // Cross-compartment always requires wrapping.
940 567 : JSObject* obj = &rval.toObject();
941 567 : if (js::GetObjectCompartment(obj) != js::GetContextCompartment(cx)) {
942 53 : return JS_WrapValue(cx, rval);
943 : }
944 :
945 : // We're same-compartment, but even then we might need to wrap
946 : // objects specially. Check for that.
947 514 : if (IsDOMObject(obj)) {
948 295 : return TryToOuterize(rval);
949 : }
950 :
951 : // It's not a WebIDL object, so it's OK to just leave it as-is: only WebIDL
952 : // objects (specifically only windows) require outerization.
953 219 : return true;
954 : }
955 :
956 : // Like MaybeWrapObjectValue, but also allows null
957 : MOZ_ALWAYS_INLINE
958 : bool
959 0 : MaybeWrapObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
960 : {
961 0 : MOZ_ASSERT(rval.isObjectOrNull());
962 0 : if (rval.isNull()) {
963 0 : return true;
964 : }
965 0 : return MaybeWrapObjectValue(cx, rval);
966 : }
967 :
968 : // Wrapping for objects that are known to not be DOM or XPConnect objects
969 : MOZ_ALWAYS_INLINE
970 : bool
971 0 : MaybeWrapNonDOMObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
972 : {
973 0 : MOZ_ASSERT(rval.isObject());
974 0 : MOZ_ASSERT(!GetDOMClass(&rval.toObject()));
975 0 : MOZ_ASSERT(!(js::GetObjectClass(&rval.toObject())->flags &
976 : JSCLASS_PRIVATE_IS_NSISUPPORTS));
977 :
978 0 : JSObject* obj = &rval.toObject();
979 0 : if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) {
980 0 : return true;
981 : }
982 0 : return JS_WrapValue(cx, rval);
983 : }
984 :
985 : // Like MaybeWrapNonDOMObjectValue but allows null
986 : MOZ_ALWAYS_INLINE
987 : bool
988 0 : MaybeWrapNonDOMObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
989 : {
990 0 : MOZ_ASSERT(rval.isObjectOrNull());
991 0 : if (rval.isNull()) {
992 0 : return true;
993 : }
994 0 : return MaybeWrapNonDOMObjectValue(cx, rval);
995 : }
996 :
997 : // If rval is a gcthing and is not in the compartment of cx, wrap rval
998 : // into the compartment of cx (typically by replacing it with an Xray or
999 : // cross-compartment wrapper around the original object).
1000 : MOZ_ALWAYS_INLINE bool
1001 603 : MaybeWrapValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
1002 : {
1003 603 : if (rval.isGCThing()) {
1004 571 : if (rval.isString()) {
1005 5 : return MaybeWrapStringValue(cx, rval);
1006 : }
1007 566 : if (rval.isObject()) {
1008 566 : return MaybeWrapObjectValue(cx, rval);
1009 : }
1010 0 : MOZ_ASSERT(rval.isSymbol());
1011 0 : JS_MarkCrossZoneId(cx, SYMBOL_TO_JSID(rval.toSymbol()));
1012 : }
1013 32 : return true;
1014 : }
1015 :
1016 : namespace binding_detail {
1017 : enum GetOrCreateReflectorWrapBehavior {
1018 : eWrapIntoContextCompartment,
1019 : eDontWrapIntoContextCompartment
1020 : };
1021 :
1022 : template <class T>
1023 : struct TypeNeedsOuterization
1024 : {
1025 : // We only need to outerize Window objects, so anything inheriting from
1026 : // nsGlobalWindow (which inherits from EventTarget itself).
1027 : static const bool value =
1028 : IsBaseOf<nsGlobalWindow, T>::value || IsSame<EventTarget, T>::value;
1029 : };
1030 :
1031 : #ifdef DEBUG
1032 : template<typename T, bool isISupports=IsBaseOf<nsISupports, T>::value>
1033 : struct CheckWrapperCacheTracing
1034 : {
1035 0 : static inline void Check(T* aObject)
1036 : {
1037 0 : }
1038 : };
1039 :
1040 : template<typename T>
1041 : struct CheckWrapperCacheTracing<T, true>
1042 : {
1043 2313 : static void Check(T* aObject)
1044 : {
1045 : // Rooting analysis thinks QueryInterface may GC, but we're dealing with
1046 : // a subset of QueryInterface, C++ only types here.
1047 4626 : JS::AutoSuppressGCAnalysis nogc;
1048 :
1049 2313 : nsWrapperCache* wrapperCacheFromQI = nullptr;
1050 2313 : aObject->QueryInterface(NS_GET_IID(nsWrapperCache),
1051 : reinterpret_cast<void**>(&wrapperCacheFromQI));
1052 :
1053 2313 : MOZ_ASSERT(wrapperCacheFromQI,
1054 : "Missing nsWrapperCache from QueryInterface implementation?");
1055 :
1056 2313 : if (!wrapperCacheFromQI->GetWrapperPreserveColor()) {
1057 : // Can't assert that we trace the wrapper, since we don't have any
1058 : // wrapper to trace.
1059 0 : return;
1060 : }
1061 :
1062 2313 : nsISupports* ccISupports = nullptr;
1063 2313 : aObject->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
1064 : reinterpret_cast<void**>(&ccISupports));
1065 2313 : MOZ_ASSERT(ccISupports,
1066 : "nsWrapperCache object which isn't cycle collectable?");
1067 :
1068 2313 : nsXPCOMCycleCollectionParticipant* participant = nullptr;
1069 2313 : CallQueryInterface(ccISupports, &participant);
1070 2313 : MOZ_ASSERT(participant, "Can't QI to CycleCollectionParticipant?");
1071 :
1072 2313 : bool wasPreservingWrapper = wrapperCacheFromQI->PreservingWrapper();
1073 2313 : wrapperCacheFromQI->SetPreservingWrapper(true);
1074 2313 : wrapperCacheFromQI->CheckCCWrapperTraversal(ccISupports, participant);
1075 2313 : wrapperCacheFromQI->SetPreservingWrapper(wasPreservingWrapper);
1076 : }
1077 : };
1078 :
1079 : void
1080 : AssertReflectorHasGivenProto(JSContext* aCx, JSObject* aReflector,
1081 : JS::Handle<JSObject*> aGivenProto);
1082 : #endif // DEBUG
1083 :
1084 : template <class T, GetOrCreateReflectorWrapBehavior wrapBehavior>
1085 : MOZ_ALWAYS_INLINE bool
1086 4423 : DoGetOrCreateDOMReflector(JSContext* cx, T* value,
1087 : JS::Handle<JSObject*> givenProto,
1088 : JS::MutableHandle<JS::Value> rval)
1089 : {
1090 4423 : MOZ_ASSERT(value);
1091 4423 : MOZ_ASSERT_IF(givenProto, js::IsObjectInContextCompartment(givenProto, cx));
1092 : // We can get rid of this when we remove support for hasXPConnectImpls.
1093 4423 : bool couldBeDOMBinding = CouldBeDOMBinding(value);
1094 4423 : JSObject* obj = value->GetWrapper();
1095 4423 : if (obj) {
1096 : #ifdef DEBUG
1097 2103 : AssertReflectorHasGivenProto(cx, obj, givenProto);
1098 : // Have to reget obj because AssertReflectorHasGivenProto can
1099 : // trigger gc so the pointer may now be invalid.
1100 2103 : obj = value->GetWrapper();
1101 : #endif
1102 : } else {
1103 : // Inline this here while we have non-dom objects in wrapper caches.
1104 2320 : if (!couldBeDOMBinding) {
1105 0 : return false;
1106 : }
1107 :
1108 2320 : obj = value->WrapObject(cx, givenProto);
1109 2320 : if (!obj) {
1110 : // At this point, obj is null, so just return false.
1111 : // Callers seem to be testing JS_IsExceptionPending(cx) to
1112 : // figure out whether WrapObject() threw.
1113 0 : return false;
1114 : }
1115 :
1116 : #ifdef DEBUG
1117 : if (IsBaseOf<nsWrapperCache, T>::value) {
1118 2313 : CheckWrapperCacheTracing<T>::Check(value);
1119 : }
1120 : #endif
1121 : }
1122 :
1123 : #ifdef DEBUG
1124 4423 : const DOMJSClass* clasp = GetDOMClass(obj);
1125 : // clasp can be null if the cache contained a non-DOM object.
1126 4423 : if (clasp) {
1127 : // Some sanity asserts about our object. Specifically:
1128 : // 1) If our class claims we're nsISupports, we better be nsISupports
1129 : // XXXbz ideally, we could assert that reinterpret_cast to nsISupports
1130 : // does the right thing, but I don't see a way to do it. :(
1131 : // 2) If our class doesn't claim we're nsISupports we better be
1132 : // reinterpret_castable to nsWrapperCache.
1133 4420 : MOZ_ASSERT(clasp, "What happened here?");
1134 4420 : MOZ_ASSERT_IF(clasp->mDOMObjectIsISupports, (IsBaseOf<nsISupports, T>::value));
1135 4420 : MOZ_ASSERT(CheckWrapperCacheCast<T>::Check());
1136 : }
1137 : #endif
1138 :
1139 4423 : rval.set(JS::ObjectValue(*obj));
1140 :
1141 : bool sameCompartment =
1142 4423 : js::GetObjectCompartment(obj) == js::GetContextCompartment(cx);
1143 4423 : if (sameCompartment && couldBeDOMBinding) {
1144 4393 : return TypeNeedsOuterization<T>::value ? TryToOuterize(rval) : true;
1145 : }
1146 :
1147 : if (wrapBehavior == eDontWrapIntoContextCompartment) {
1148 : if (TypeNeedsOuterization<T>::value) {
1149 : JSAutoCompartment ac(cx, obj);
1150 : return TryToOuterize(rval);
1151 : }
1152 :
1153 0 : return true;
1154 : }
1155 :
1156 30 : return JS_WrapValue(cx, rval);
1157 : }
1158 :
1159 : } // namespace binding_detail
1160 :
1161 : // Create a JSObject wrapping "value", if there isn't one already, and store it
1162 : // in rval. "value" must be a concrete class that implements a
1163 : // GetWrapperPreserveColor() which can return its existing wrapper, if any, and
1164 : // a WrapObject() which will try to create a wrapper. Typically, this is done by
1165 : // having "value" inherit from nsWrapperCache.
1166 : //
1167 : // The value stored in rval will be ready to be exposed to whatever JS
1168 : // is running on cx right now. In particular, it will be in the
1169 : // compartment of cx, and outerized as needed.
1170 : template <class T>
1171 : MOZ_ALWAYS_INLINE bool
1172 4406 : GetOrCreateDOMReflector(JSContext* cx, T* value,
1173 : JS::MutableHandle<JS::Value> rval,
1174 : JS::Handle<JSObject*> givenProto = nullptr)
1175 : {
1176 : using namespace binding_detail;
1177 : return DoGetOrCreateDOMReflector<T, eWrapIntoContextCompartment>(cx, value,
1178 : givenProto,
1179 4406 : rval);
1180 : }
1181 :
1182 : // Like GetOrCreateDOMReflector but doesn't wrap into the context compartment,
1183 : // and hence does not actually require cx to be in a compartment.
1184 : template <class T>
1185 : MOZ_ALWAYS_INLINE bool
1186 17 : GetOrCreateDOMReflectorNoWrap(JSContext* cx, T* value,
1187 : JS::MutableHandle<JS::Value> rval)
1188 : {
1189 : using namespace binding_detail;
1190 34 : return DoGetOrCreateDOMReflector<T, eDontWrapIntoContextCompartment>(cx,
1191 : value,
1192 : nullptr,
1193 34 : rval);
1194 : }
1195 :
1196 : // Create a JSObject wrapping "value", for cases when "value" is a
1197 : // non-wrapper-cached object using WebIDL bindings. "value" must implement a
1198 : // WrapObject() method taking a JSContext and a scope.
1199 : template <class T>
1200 : inline bool
1201 0 : WrapNewBindingNonWrapperCachedObject(JSContext* cx,
1202 : JS::Handle<JSObject*> scopeArg,
1203 : T* value,
1204 : JS::MutableHandle<JS::Value> rval,
1205 : JS::Handle<JSObject*> givenProto = nullptr)
1206 : {
1207 : static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
1208 0 : MOZ_ASSERT(value);
1209 : // We try to wrap in the compartment of the underlying object of "scope"
1210 0 : JS::Rooted<JSObject*> obj(cx);
1211 : {
1212 : // scope for the JSAutoCompartment so that we restore the compartment
1213 : // before we call JS_WrapValue.
1214 0 : Maybe<JSAutoCompartment> ac;
1215 : // Maybe<Handle> doesn't so much work, and in any case, adding
1216 : // more Maybe (one for a Rooted and one for a Handle) adds more
1217 : // code (and branches!) than just adding a single rooted.
1218 0 : JS::Rooted<JSObject*> scope(cx, scopeArg);
1219 0 : JS::Rooted<JSObject*> proto(cx, givenProto);
1220 0 : if (js::IsWrapper(scope)) {
1221 0 : scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
1222 0 : if (!scope)
1223 0 : return false;
1224 0 : ac.emplace(cx, scope);
1225 0 : if (!JS_WrapObject(cx, &proto)) {
1226 0 : return false;
1227 : }
1228 : }
1229 :
1230 0 : MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
1231 0 : if (!value->WrapObject(cx, proto, &obj)) {
1232 0 : return false;
1233 : }
1234 : }
1235 :
1236 : // We can end up here in all sorts of compartments, per above. Make
1237 : // sure to JS_WrapValue!
1238 0 : rval.set(JS::ObjectValue(*obj));
1239 0 : return MaybeWrapObjectValue(cx, rval);
1240 : }
1241 :
1242 : // Create a JSObject wrapping "value", for cases when "value" is a
1243 : // non-wrapper-cached owned object using WebIDL bindings. "value" must implement a
1244 : // WrapObject() method taking a JSContext, a scope, and a boolean outparam that
1245 : // is true if the JSObject took ownership
1246 : template <class T>
1247 : inline bool
1248 0 : WrapNewBindingNonWrapperCachedObject(JSContext* cx,
1249 : JS::Handle<JSObject*> scopeArg,
1250 : nsAutoPtr<T>& value,
1251 : JS::MutableHandle<JS::Value> rval,
1252 : JS::Handle<JSObject*> givenProto = nullptr)
1253 : {
1254 : static_assert(!IsRefcounted<T>::value, "Only pass owned classes in here.");
1255 : // We do a runtime check on value, because otherwise we might in
1256 : // fact end up wrapping a null and invoking methods on it later.
1257 0 : if (!value) {
1258 0 : MOZ_CRASH("Don't try to wrap null objects");
1259 : }
1260 : // We try to wrap in the compartment of the underlying object of "scope"
1261 0 : JS::Rooted<JSObject*> obj(cx);
1262 : {
1263 : // scope for the JSAutoCompartment so that we restore the compartment
1264 : // before we call JS_WrapValue.
1265 0 : Maybe<JSAutoCompartment> ac;
1266 : // Maybe<Handle> doesn't so much work, and in any case, adding
1267 : // more Maybe (one for a Rooted and one for a Handle) adds more
1268 : // code (and branches!) than just adding a single rooted.
1269 0 : JS::Rooted<JSObject*> scope(cx, scopeArg);
1270 0 : JS::Rooted<JSObject*> proto(cx, givenProto);
1271 0 : if (js::IsWrapper(scope)) {
1272 0 : scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
1273 0 : if (!scope)
1274 0 : return false;
1275 0 : ac.emplace(cx, scope);
1276 0 : if (!JS_WrapObject(cx, &proto)) {
1277 0 : return false;
1278 : }
1279 : }
1280 :
1281 0 : MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
1282 0 : if (!value->WrapObject(cx, proto, &obj)) {
1283 0 : return false;
1284 : }
1285 :
1286 0 : value.forget();
1287 : }
1288 :
1289 : // We can end up here in all sorts of compartments, per above. Make
1290 : // sure to JS_WrapValue!
1291 0 : rval.set(JS::ObjectValue(*obj));
1292 0 : return MaybeWrapObjectValue(cx, rval);
1293 : }
1294 :
1295 : // Helper for smart pointers (nsRefPtr/nsCOMPtr).
1296 : template <template <typename> class SmartPtr, typename T,
1297 : typename U=typename EnableIf<IsRefcounted<T>::value, T>::Type,
1298 : typename V=typename EnableIf<IsSmartPtr<SmartPtr<T>>::value, T>::Type>
1299 : inline bool
1300 0 : WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
1301 : const SmartPtr<T>& value,
1302 : JS::MutableHandle<JS::Value> rval,
1303 : JS::Handle<JSObject*> givenProto = nullptr)
1304 : {
1305 0 : return WrapNewBindingNonWrapperCachedObject(cx, scope, value.get(), rval,
1306 0 : givenProto);
1307 : }
1308 :
1309 : // Helper for object references (as opposed to pointers).
1310 : template <typename T,
1311 : typename U=typename EnableIf<!IsSmartPtr<T>::value, T>::Type>
1312 : inline bool
1313 : WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
1314 : T& value,
1315 : JS::MutableHandle<JS::Value> rval,
1316 : JS::Handle<JSObject*> givenProto = nullptr)
1317 : {
1318 : return WrapNewBindingNonWrapperCachedObject(cx, scope, &value, rval,
1319 : givenProto);
1320 : }
1321 :
1322 : // Only set allowNativeWrapper to false if you really know you need it, if in
1323 : // doubt use true. Setting it to false disables security wrappers.
1324 : bool
1325 : NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
1326 : JS::Handle<JSObject*> aScope,
1327 : JS::MutableHandle<JS::Value> aRetval,
1328 : xpcObjectHelper& aHelper,
1329 : const nsIID* aIID,
1330 : bool aAllowNativeWrapper);
1331 :
1332 : /**
1333 : * A method to handle new-binding wrap failure, by possibly falling back to
1334 : * wrapping as a non-new-binding object.
1335 : */
1336 : template <class T>
1337 : MOZ_ALWAYS_INLINE bool
1338 0 : HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
1339 : T* value, JS::MutableHandle<JS::Value> rval)
1340 : {
1341 0 : if (JS_IsExceptionPending(cx)) {
1342 0 : return false;
1343 : }
1344 :
1345 0 : qsObjectHelper helper(value, GetWrapperCache(value));
1346 : return NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval,
1347 0 : helper, nullptr, true);
1348 : }
1349 :
1350 : // Helper for calling HandleNewBindingWrappingFailure with smart pointers
1351 : // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
1352 :
1353 : template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
1354 : struct HandleNewBindingWrappingFailureHelper
1355 : {
1356 0 : static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
1357 : const T& value, JS::MutableHandle<JS::Value> rval)
1358 : {
1359 0 : return HandleNewBindingWrappingFailure(cx, scope, value.get(), rval);
1360 : }
1361 : };
1362 :
1363 : template <class T>
1364 : struct HandleNewBindingWrappingFailureHelper<T, false>
1365 : {
1366 : static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope, T& value,
1367 : JS::MutableHandle<JS::Value> rval)
1368 : {
1369 : return HandleNewBindingWrappingFailure(cx, scope, &value, rval);
1370 : }
1371 : };
1372 :
1373 : template<class T>
1374 : inline bool
1375 0 : HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
1376 : T& value, JS::MutableHandle<JS::Value> rval)
1377 : {
1378 0 : return HandleNewBindingWrappingFailureHelper<T>::Wrap(cx, scope, value, rval);
1379 : }
1380 :
1381 : template<bool Fatal>
1382 : inline bool
1383 : EnumValueNotFound(JSContext* cx, JS::HandleString str, const char* type,
1384 : const char* sourceDescription);
1385 :
1386 : template<>
1387 : inline bool
1388 0 : EnumValueNotFound<false>(JSContext* cx, JS::HandleString str, const char* type,
1389 : const char* sourceDescription)
1390 : {
1391 : // TODO: Log a warning to the console.
1392 0 : return true;
1393 : }
1394 :
1395 : template<>
1396 : inline bool
1397 0 : EnumValueNotFound<true>(JSContext* cx, JS::HandleString str, const char* type,
1398 : const char* sourceDescription)
1399 : {
1400 0 : JSAutoByteString deflated;
1401 0 : if (!deflated.encodeUtf8(cx, str)) {
1402 0 : return false;
1403 : }
1404 : return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
1405 0 : deflated.ptr(), type);
1406 : }
1407 :
1408 : template<typename CharT>
1409 : inline int
1410 3 : FindEnumStringIndexImpl(const CharT* chars, size_t length, const EnumEntry* values)
1411 : {
1412 3 : int i = 0;
1413 18 : for (const EnumEntry* value = values; value->value; ++value, ++i) {
1414 18 : if (length != value->length) {
1415 9 : continue;
1416 : }
1417 :
1418 9 : bool equal = true;
1419 9 : const char* val = value->value;
1420 21 : for (size_t j = 0; j != length; ++j) {
1421 18 : if (unsigned(val[j]) != unsigned(chars[j])) {
1422 6 : equal = false;
1423 6 : break;
1424 : }
1425 : }
1426 :
1427 9 : if (equal) {
1428 3 : return i;
1429 : }
1430 : }
1431 :
1432 0 : return -1;
1433 : }
1434 :
1435 : template<bool InvalidValueFatal>
1436 : inline bool
1437 3 : FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* values,
1438 : const char* type, const char* sourceDescription, int* index)
1439 : {
1440 : // JS_StringEqualsAscii is slow as molasses, so don't use it here.
1441 6 : JS::RootedString str(cx, JS::ToString(cx, v));
1442 3 : if (!str) {
1443 0 : return false;
1444 : }
1445 :
1446 : {
1447 : size_t length;
1448 3 : JS::AutoCheckCannotGC nogc;
1449 3 : if (js::StringHasLatin1Chars(str)) {
1450 3 : const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str,
1451 3 : &length);
1452 3 : if (!chars) {
1453 0 : return false;
1454 : }
1455 3 : *index = FindEnumStringIndexImpl(chars, length, values);
1456 : } else {
1457 0 : const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, str,
1458 0 : &length);
1459 0 : if (!chars) {
1460 0 : return false;
1461 : }
1462 0 : *index = FindEnumStringIndexImpl(chars, length, values);
1463 : }
1464 3 : if (*index >= 0) {
1465 3 : return true;
1466 : }
1467 : }
1468 :
1469 0 : return EnumValueNotFound<InvalidValueFatal>(cx, str, type, sourceDescription);
1470 : }
1471 :
1472 : inline nsWrapperCache*
1473 400 : GetWrapperCache(const ParentObject& aParentObject)
1474 : {
1475 400 : return aParentObject.mWrapperCache;
1476 : }
1477 :
1478 : template<class T>
1479 : inline T*
1480 2079 : GetParentPointer(T* aObject)
1481 : {
1482 2079 : return aObject;
1483 : }
1484 :
1485 : inline nsISupports*
1486 400 : GetParentPointer(const ParentObject& aObject)
1487 : {
1488 400 : return aObject.mObject;
1489 : }
1490 :
1491 : template <typename T>
1492 : inline bool
1493 2079 : GetUseXBLScope(T* aParentObject)
1494 : {
1495 2079 : return false;
1496 : }
1497 :
1498 : inline bool
1499 400 : GetUseXBLScope(const ParentObject& aParentObject)
1500 : {
1501 400 : return aParentObject.mUseXBLScope;
1502 : }
1503 :
1504 : template<class T>
1505 : inline void
1506 58 : ClearWrapper(T* p, nsWrapperCache* cache, JSObject* obj)
1507 : {
1508 116 : JS::AutoAssertGCCallback inCallback;
1509 58 : cache->ClearWrapper(obj);
1510 58 : }
1511 :
1512 : template<class T>
1513 : inline void
1514 0 : ClearWrapper(T* p, void*, JSObject* obj)
1515 : {
1516 0 : JS::AutoAssertGCCallback inCallback;
1517 : nsWrapperCache* cache;
1518 0 : CallQueryInterface(p, &cache);
1519 0 : ClearWrapper(p, cache, obj);
1520 0 : }
1521 :
1522 : template<class T>
1523 : inline void
1524 3 : UpdateWrapper(T* p, nsWrapperCache* cache, JSObject* obj, const JSObject* old)
1525 : {
1526 6 : JS::AutoAssertGCCallback inCallback;
1527 3 : cache->UpdateWrapper(obj, old);
1528 3 : }
1529 :
1530 : template<class T>
1531 : inline void
1532 0 : UpdateWrapper(T* p, void*, JSObject* obj, const JSObject* old)
1533 : {
1534 0 : JS::AutoAssertGCCallback inCallback;
1535 : nsWrapperCache* cache;
1536 0 : CallQueryInterface(p, &cache);
1537 0 : UpdateWrapper(p, cache, obj, old);
1538 0 : }
1539 :
1540 : // Attempt to preserve the wrapper, if any, for a Paris DOM bindings object.
1541 : // Return true if we successfully preserved the wrapper, or there is no wrapper
1542 : // to preserve. In the latter case we don't need to preserve the wrapper, because
1543 : // the object can only be obtained by JS once, or they cannot be meaningfully
1544 : // owned from the native side.
1545 : //
1546 : // This operation will return false only for non-nsISupports cycle-collected
1547 : // objects, because we cannot determine if they are wrappercached or not.
1548 : bool
1549 : TryPreserveWrapper(JSObject* obj);
1550 :
1551 : // Can only be called with a DOM JSClass.
1552 : bool
1553 : InstanceClassHasProtoAtDepth(const js::Class* clasp,
1554 : uint32_t protoID, uint32_t depth);
1555 :
1556 : // Only set allowNativeWrapper to false if you really know you need it, if in
1557 : // doubt use true. Setting it to false disables security wrappers.
1558 : bool
1559 : XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
1560 : xpcObjectHelper& helper, const nsIID* iid,
1561 : bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval);
1562 :
1563 : // Special-cased wrapping for variants
1564 : bool
1565 : VariantToJsval(JSContext* aCx, nsIVariant* aVariant,
1566 : JS::MutableHandle<JS::Value> aRetval);
1567 :
1568 : // Wrap an object "p" which is not using WebIDL bindings yet. This _will_
1569 : // actually work on WebIDL binding objects that are wrappercached, but will be
1570 : // much slower than GetOrCreateDOMReflector. "cache" must either be null or be
1571 : // the nsWrapperCache for "p".
1572 : template<class T>
1573 : inline bool
1574 266 : WrapObject(JSContext* cx, T* p, nsWrapperCache* cache, const nsIID* iid,
1575 : JS::MutableHandle<JS::Value> rval)
1576 : {
1577 266 : if (xpc_FastGetCachedWrapper(cx, cache, rval))
1578 0 : return true;
1579 532 : qsObjectHelper helper(p, cache);
1580 532 : JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
1581 266 : return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval);
1582 : }
1583 :
1584 : // A specialization of the above for nsIVariant, because that needs to
1585 : // do something different.
1586 : template<>
1587 : inline bool
1588 0 : WrapObject<nsIVariant>(JSContext* cx, nsIVariant* p,
1589 : nsWrapperCache* cache, const nsIID* iid,
1590 : JS::MutableHandle<JS::Value> rval)
1591 : {
1592 0 : MOZ_ASSERT(iid);
1593 0 : MOZ_ASSERT(iid->Equals(NS_GET_IID(nsIVariant)));
1594 0 : return VariantToJsval(cx, p, rval);
1595 : }
1596 :
1597 : // Wrap an object "p" which is not using WebIDL bindings yet. Just like the
1598 : // variant that takes an nsWrapperCache above, but will try to auto-derive the
1599 : // nsWrapperCache* from "p".
1600 : template<class T>
1601 : inline bool
1602 266 : WrapObject(JSContext* cx, T* p, const nsIID* iid,
1603 : JS::MutableHandle<JS::Value> rval)
1604 : {
1605 266 : return WrapObject(cx, p, GetWrapperCache(p), iid, rval);
1606 : }
1607 :
1608 : // Just like the WrapObject above, but without requiring you to pick which
1609 : // interface you're wrapping as. This should only be used for objects that have
1610 : // classinfo, for which it doesn't matter what IID is used to wrap.
1611 : template<class T>
1612 : inline bool
1613 52 : WrapObject(JSContext* cx, T* p, JS::MutableHandle<JS::Value> rval)
1614 : {
1615 52 : return WrapObject(cx, p, nullptr, rval);
1616 : }
1617 :
1618 : // Helper to make it possible to wrap directly out of an nsCOMPtr
1619 : template<class T>
1620 : inline bool
1621 0 : WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
1622 : const nsIID* iid, JS::MutableHandle<JS::Value> rval)
1623 : {
1624 0 : return WrapObject(cx, p.get(), iid, rval);
1625 : }
1626 :
1627 : // Helper to make it possible to wrap directly out of an nsCOMPtr
1628 : template<class T>
1629 : inline bool
1630 0 : WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
1631 : JS::MutableHandle<JS::Value> rval)
1632 : {
1633 0 : return WrapObject(cx, p, nullptr, rval);
1634 : }
1635 :
1636 : // Helper to make it possible to wrap directly out of an nsRefPtr
1637 : template<class T>
1638 : inline bool
1639 157 : WrapObject(JSContext* cx, const RefPtr<T>& p,
1640 : const nsIID* iid, JS::MutableHandle<JS::Value> rval)
1641 : {
1642 157 : return WrapObject(cx, p.get(), iid, rval);
1643 : }
1644 :
1645 : // Helper to make it possible to wrap directly out of an nsRefPtr
1646 : template<class T>
1647 : inline bool
1648 20 : WrapObject(JSContext* cx, const RefPtr<T>& p,
1649 : JS::MutableHandle<JS::Value> rval)
1650 : {
1651 20 : return WrapObject(cx, p, nullptr, rval);
1652 : }
1653 :
1654 : // Specialization to make it easy to use WrapObject in codegen.
1655 : template<>
1656 : inline bool
1657 : WrapObject<JSObject>(JSContext* cx, JSObject* p,
1658 : JS::MutableHandle<JS::Value> rval)
1659 : {
1660 : rval.set(JS::ObjectOrNullValue(p));
1661 : return true;
1662 : }
1663 :
1664 : inline bool
1665 : WrapObject(JSContext* cx, JSObject& p, JS::MutableHandle<JS::Value> rval)
1666 : {
1667 : rval.set(JS::ObjectValue(p));
1668 : return true;
1669 : }
1670 :
1671 : // Given an object "p" that inherits from nsISupports, wrap it and return the
1672 : // result. Null is returned on wrapping failure. This is somewhat similar to
1673 : // WrapObject() above, but does NOT allow Xrays around the result, since we
1674 : // don't want those for our parent object.
1675 : template<typename T>
1676 : static inline JSObject*
1677 421 : WrapNativeISupports(JSContext* cx, T* p, nsWrapperCache* cache)
1678 : {
1679 842 : qsObjectHelper helper(ToSupports(p), cache);
1680 842 : JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
1681 842 : JS::Rooted<JS::Value> v(cx);
1682 842 : return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
1683 : v.toObjectOrNull() :
1684 842 : nullptr;
1685 : }
1686 :
1687 :
1688 : // Fallback for when our parent is not a WebIDL binding object.
1689 : template<typename T, bool isISupports=IsBaseOf<nsISupports, T>::value>
1690 : struct WrapNativeFallback
1691 : {
1692 0 : static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
1693 : {
1694 0 : return nullptr;
1695 : }
1696 : };
1697 :
1698 : // Fallback for when our parent is not a WebIDL binding object but _is_ an
1699 : // nsISupports object.
1700 : template<typename T >
1701 : struct WrapNativeFallback<T, true >
1702 : {
1703 0 : static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
1704 : {
1705 0 : return WrapNativeISupports(cx, parent, cache);
1706 : }
1707 : };
1708 :
1709 : // Wrapping of our native parent, for cases when it's a WebIDL object (though
1710 : // possibly preffed off).
1711 : template<typename T, bool hasWrapObject=NativeHasMember<T>::WrapObject>
1712 : struct WrapNativeHelper
1713 : {
1714 59 : static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
1715 : {
1716 59 : MOZ_ASSERT(cache);
1717 :
1718 : JSObject* obj;
1719 59 : if ((obj = cache->GetWrapper())) {
1720 : // GetWrapper always unmarks gray.
1721 59 : MOZ_ASSERT(JS::ObjectIsNotGray(obj));
1722 59 : return obj;
1723 : }
1724 :
1725 : // Inline this here while we have non-dom objects in wrapper caches.
1726 0 : if (!CouldBeDOMBinding(parent)) {
1727 : // WrapNativeFallback never returns a gray thing.
1728 0 : obj = WrapNativeFallback<T>::Wrap(cx, parent, cache);
1729 0 : MOZ_ASSERT(JS::ObjectIsNotGray(obj));
1730 : } else {
1731 : // WrapObject never returns a gray thing.
1732 0 : obj = parent->WrapObject(cx, nullptr);
1733 0 : MOZ_ASSERT(JS::ObjectIsNotGray(obj));
1734 : }
1735 :
1736 0 : return obj;
1737 : }
1738 : };
1739 :
1740 : // Wrapping of our native parent, for cases when it's not a WebIDL object. In
1741 : // this case it must be nsISupports.
1742 : template<typename T>
1743 : struct WrapNativeHelper<T, false>
1744 : {
1745 421 : static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
1746 : {
1747 : JSObject* obj;
1748 421 : if (cache && (obj = cache->GetWrapper())) {
1749 : #ifdef DEBUG
1750 800 : JS::Rooted<JSObject*> rootedObj(cx, obj);
1751 400 : NS_ASSERTION(WrapNativeISupports(cx, parent, cache) == rootedObj,
1752 : "Unexpected object in nsWrapperCache");
1753 400 : obj = rootedObj;
1754 : #endif
1755 400 : MOZ_ASSERT(JS::ObjectIsNotGray(obj));
1756 400 : return obj;
1757 : }
1758 :
1759 21 : obj = WrapNativeISupports(cx, parent, cache);
1760 21 : MOZ_ASSERT(JS::ObjectIsNotGray(obj));
1761 21 : return obj;
1762 : }
1763 : };
1764 :
1765 : // Finding the associated global for an object.
1766 : template<typename T>
1767 : static inline JSObject*
1768 2479 : FindAssociatedGlobal(JSContext* cx, T* p, nsWrapperCache* cache,
1769 : bool useXBLScope = false)
1770 : {
1771 2479 : if (!p) {
1772 1999 : return JS::CurrentGlobalOrNull(cx);
1773 : }
1774 :
1775 480 : JSObject* obj = WrapNativeHelper<T>::Wrap(cx, p, cache);
1776 480 : if (!obj) {
1777 0 : return nullptr;
1778 : }
1779 480 : MOZ_ASSERT(JS::ObjectIsNotGray(obj));
1780 :
1781 480 : obj = js::GetGlobalForObjectCrossCompartment(obj);
1782 :
1783 480 : if (!useXBLScope) {
1784 398 : return obj;
1785 : }
1786 :
1787 : // If useXBLScope is true, it means that the canonical reflector for this
1788 : // native object should live in the content XBL scope. Note that we never put
1789 : // anonymous content inside an add-on scope.
1790 82 : if (xpc::IsInContentXBLScope(obj)) {
1791 0 : return obj;
1792 : }
1793 164 : JS::Rooted<JSObject*> rootedObj(cx, obj);
1794 82 : JSObject* xblScope = xpc::GetXBLScope(cx, rootedObj);
1795 82 : MOZ_ASSERT_IF(xblScope, JS_IsGlobalObject(xblScope));
1796 82 : MOZ_ASSERT(JS::ObjectIsNotGray(xblScope));
1797 82 : return xblScope;
1798 : }
1799 :
1800 : // Finding of the associated global for an object, when we don't want to
1801 : // explicitly pass in things like the nsWrapperCache for it.
1802 : template<typename T>
1803 : static inline JSObject*
1804 2479 : FindAssociatedGlobal(JSContext* cx, const T& p)
1805 : {
1806 2479 : return FindAssociatedGlobal(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
1807 : }
1808 :
1809 : // Specialization for the case of nsIGlobalObject, since in that case
1810 : // we can just get the JSObject* directly.
1811 : template<>
1812 : inline JSObject*
1813 73 : FindAssociatedGlobal(JSContext* cx, nsIGlobalObject* const& p)
1814 : {
1815 73 : if (!p) {
1816 2 : return JS::CurrentGlobalOrNull(cx);
1817 : }
1818 :
1819 71 : JSObject* global = p->GetGlobalJSObject();
1820 71 : if (!global) {
1821 0 : return nullptr;
1822 : }
1823 :
1824 71 : MOZ_ASSERT(JS_IsGlobalObject(global));
1825 : // This object could be gray if the nsIGlobalObject is the only thing keeping
1826 : // it alive.
1827 71 : JS::ExposeObjectToActiveJS(global);
1828 71 : return global;
1829 : }
1830 :
1831 : template<typename T,
1832 : bool hasAssociatedGlobal=NativeHasMember<T>::GetParentObject>
1833 : struct FindAssociatedGlobalForNative
1834 : {
1835 0 : static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
1836 : {
1837 0 : MOZ_ASSERT(js::IsObjectInContextCompartment(obj, cx));
1838 0 : T* native = UnwrapDOMObject<T>(obj);
1839 0 : return FindAssociatedGlobal(cx, native->GetParentObject());
1840 : }
1841 : };
1842 :
1843 : template<typename T>
1844 : struct FindAssociatedGlobalForNative<T, false>
1845 : {
1846 0 : static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
1847 : {
1848 0 : MOZ_CRASH();
1849 : return nullptr;
1850 : }
1851 : };
1852 :
1853 : // Helper for calling GetOrCreateDOMReflector with smart pointers
1854 : // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
1855 : template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
1856 : struct GetOrCreateDOMReflectorHelper
1857 : {
1858 131 : static inline bool GetOrCreate(JSContext* cx, const T& value,
1859 : JS::Handle<JSObject*> givenProto,
1860 : JS::MutableHandle<JS::Value> rval)
1861 : {
1862 131 : return GetOrCreateDOMReflector(cx, value.get(), rval, givenProto);
1863 : }
1864 : };
1865 :
1866 : template <class T>
1867 : struct GetOrCreateDOMReflectorHelper<T, false>
1868 : {
1869 81 : static inline bool GetOrCreate(JSContext* cx, T& value,
1870 : JS::Handle<JSObject*> givenProto,
1871 : JS::MutableHandle<JS::Value> rval)
1872 : {
1873 : static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
1874 81 : return GetOrCreateDOMReflector(cx, &value, rval, givenProto);
1875 : }
1876 : };
1877 :
1878 : template<class T>
1879 : inline bool
1880 212 : GetOrCreateDOMReflector(JSContext* cx, T& value,
1881 : JS::MutableHandle<JS::Value> rval,
1882 : JS::Handle<JSObject*> givenProto = nullptr)
1883 : {
1884 : return GetOrCreateDOMReflectorHelper<T>::GetOrCreate(cx, value, givenProto,
1885 212 : rval);
1886 : }
1887 :
1888 : // Helper for calling GetOrCreateDOMReflectorNoWrap with smart pointers
1889 : // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
1890 : template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
1891 : struct GetOrCreateDOMReflectorNoWrapHelper
1892 : {
1893 17 : static inline bool GetOrCreate(JSContext* cx, const T& value,
1894 : JS::MutableHandle<JS::Value> rval)
1895 : {
1896 17 : return GetOrCreateDOMReflectorNoWrap(cx, value.get(), rval);
1897 : }
1898 : };
1899 :
1900 : template <class T>
1901 : struct GetOrCreateDOMReflectorNoWrapHelper<T, false>
1902 : {
1903 : static inline bool GetOrCreate(JSContext* cx, T& value,
1904 : JS::MutableHandle<JS::Value> rval)
1905 : {
1906 : return GetOrCreateDOMReflectorNoWrap(cx, &value, rval);
1907 : }
1908 : };
1909 :
1910 : template<class T>
1911 : inline bool
1912 17 : GetOrCreateDOMReflectorNoWrap(JSContext* cx, T& value,
1913 : JS::MutableHandle<JS::Value> rval)
1914 : {
1915 : return
1916 17 : GetOrCreateDOMReflectorNoWrapHelper<T>::GetOrCreate(cx, value, rval);
1917 : }
1918 :
1919 : template <class T>
1920 : inline JSObject*
1921 0 : GetCallbackFromCallbackObject(T* aObj)
1922 : {
1923 0 : return aObj->CallbackOrNull();
1924 : }
1925 :
1926 : // Helper for getting the callback JSObject* of a smart ptr around a
1927 : // CallbackObject or a reference to a CallbackObject or something like
1928 : // that.
1929 : template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
1930 : struct GetCallbackFromCallbackObjectHelper
1931 : {
1932 0 : static inline JSObject* Get(const T& aObj)
1933 : {
1934 0 : return GetCallbackFromCallbackObject(aObj.get());
1935 : }
1936 : };
1937 :
1938 : template <class T>
1939 : struct GetCallbackFromCallbackObjectHelper<T, false>
1940 : {
1941 0 : static inline JSObject* Get(T& aObj)
1942 : {
1943 0 : return GetCallbackFromCallbackObject(&aObj);
1944 : }
1945 : };
1946 :
1947 : template<class T>
1948 : inline JSObject*
1949 0 : GetCallbackFromCallbackObject(T& aObj)
1950 : {
1951 0 : return GetCallbackFromCallbackObjectHelper<T>::Get(aObj);
1952 : }
1953 :
1954 : static inline bool
1955 147 : AtomizeAndPinJSString(JSContext* cx, jsid& id, const char* chars)
1956 : {
1957 147 : if (JSString *str = ::JS_AtomizeAndPinString(cx, chars)) {
1958 147 : id = INTERNED_STRING_TO_JSID(cx, str);
1959 147 : return true;
1960 : }
1961 0 : return false;
1962 : }
1963 :
1964 : bool
1965 : InitIds(JSContext* cx, const NativeProperties* properties);
1966 :
1967 : bool
1968 : QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
1969 :
1970 : template <class T>
1971 : struct
1972 : WantsQueryInterface
1973 : {
1974 : static_assert(IsBaseOf<nsISupports, T>::value,
1975 : "QueryInterface can't work without an nsISupports.");
1976 77 : static bool Enabled(JSContext* aCx, JSObject* aGlobal)
1977 : {
1978 77 : return NS_IsMainThread() && IsChromeOrXBL(aCx, aGlobal);
1979 : }
1980 : };
1981 :
1982 : void
1983 : GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
1984 : nsWrapperCache* aCache, nsIJSID* aIID,
1985 : JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError);
1986 :
1987 : template<class T>
1988 : void
1989 39 : GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID,
1990 : JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
1991 : {
1992 39 : GetInterfaceImpl(aCx, aThis, aThis, aIID, aRetval, aError);
1993 39 : }
1994 :
1995 : bool
1996 : ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
1997 :
1998 : bool
1999 : ThrowConstructorWithoutNew(JSContext* cx, const char* name);
2000 :
2001 : bool
2002 : GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
2003 : JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
2004 : bool* found, JS::MutableHandle<JS::Value> vp);
2005 :
2006 : //
2007 : bool
2008 : HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
2009 : JS::Handle<jsid> id, bool* has);
2010 :
2011 :
2012 : // Append the property names in "names" to "props". If
2013 : // shadowPrototypeProperties is false then skip properties that are also
2014 : // present on the proto chain of proxy. If shadowPrototypeProperties is true,
2015 : // then the "proxy" argument is ignored.
2016 : bool
2017 : AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
2018 : nsTArray<nsString>& names,
2019 : bool shadowPrototypeProperties, JS::AutoIdVector& props);
2020 :
2021 : enum StringificationBehavior {
2022 : eStringify,
2023 : eEmpty,
2024 : eNull
2025 : };
2026 :
2027 : template<typename T>
2028 : static inline bool
2029 1748 : ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
2030 : StringificationBehavior nullBehavior,
2031 : StringificationBehavior undefinedBehavior,
2032 : T& result)
2033 : {
2034 : JSString *s;
2035 1748 : if (v.isString()) {
2036 1725 : s = v.toString();
2037 : } else {
2038 : StringificationBehavior behavior;
2039 23 : if (v.isNull()) {
2040 0 : behavior = nullBehavior;
2041 23 : } else if (v.isUndefined()) {
2042 0 : behavior = undefinedBehavior;
2043 : } else {
2044 23 : behavior = eStringify;
2045 : }
2046 :
2047 23 : if (behavior != eStringify) {
2048 0 : if (behavior == eEmpty) {
2049 0 : result.Truncate();
2050 : } else {
2051 0 : result.SetIsVoid(true);
2052 : }
2053 0 : return true;
2054 : }
2055 :
2056 23 : s = JS::ToString(cx, v);
2057 23 : if (!s) {
2058 0 : return false;
2059 : }
2060 : }
2061 :
2062 1748 : return AssignJSString(cx, result, s);
2063 : }
2064 :
2065 : template<typename T>
2066 : static inline bool
2067 0 : ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
2068 : {
2069 0 : return ConvertJSValueToString(cx, v, eStringify, eStringify, result);
2070 : }
2071 :
2072 : void
2073 : NormalizeUSVString(nsAString& aString);
2074 :
2075 : void
2076 : NormalizeUSVString(binding_detail::FakeString& aString);
2077 :
2078 : template<typename T>
2079 : static inline bool
2080 0 : ConvertJSValueToUSVString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
2081 : {
2082 0 : if (!ConvertJSValueToString(cx, v, eStringify, eStringify, result)) {
2083 0 : return false;
2084 : }
2085 :
2086 0 : NormalizeUSVString(result);
2087 0 : return true;
2088 : }
2089 :
2090 : template<typename T>
2091 : inline bool
2092 6 : ConvertIdToString(JSContext* cx, JS::HandleId id, T& result, bool& isSymbol)
2093 : {
2094 6 : if (MOZ_LIKELY(JSID_IS_STRING(id))) {
2095 6 : if (!AssignJSString(cx, result, JSID_TO_STRING(id))) {
2096 0 : return false;
2097 : }
2098 0 : } else if (JSID_IS_SYMBOL(id)) {
2099 0 : isSymbol = true;
2100 0 : return true;
2101 : } else {
2102 0 : JS::RootedValue nameVal(cx, js::IdToValue(id));
2103 0 : if (!ConvertJSValueToString(cx, nameVal, eStringify, eStringify, result)) {
2104 0 : return false;
2105 : }
2106 : }
2107 6 : isSymbol = false;
2108 6 : return true;
2109 : }
2110 :
2111 : bool
2112 : ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
2113 : bool nullable, nsACString& result);
2114 :
2115 : inline bool
2116 0 : ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
2117 : nsACString& result)
2118 : {
2119 0 : return ConvertJSValueToByteString(cx, v, false, result);
2120 : }
2121 :
2122 : template<typename T>
2123 : void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
2124 : template<typename T>
2125 : void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
2126 :
2127 : // Class used to trace sequences, with specializations for various
2128 : // sequence types.
2129 : template<typename T,
2130 : bool isDictionary=IsBaseOf<DictionaryBase, T>::value,
2131 : bool isTypedArray=IsBaseOf<AllTypedArraysBase, T>::value,
2132 : bool isOwningUnion=IsBaseOf<AllOwningUnionBase, T>::value>
2133 : class SequenceTracer
2134 : {
2135 : explicit SequenceTracer() = delete; // Should never be instantiated
2136 : };
2137 :
2138 : // sequence<object> or sequence<object?>
2139 : template<>
2140 : class SequenceTracer<JSObject*, false, false, false>
2141 : {
2142 : explicit SequenceTracer() = delete; // Should never be instantiated
2143 :
2144 : public:
2145 0 : static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
2146 0 : for (; objp != end; ++objp) {
2147 0 : JS::UnsafeTraceRoot(trc, objp, "sequence<object>");
2148 : }
2149 0 : }
2150 : };
2151 :
2152 : // sequence<any>
2153 : template<>
2154 : class SequenceTracer<JS::Value, false, false, false>
2155 : {
2156 : explicit SequenceTracer() = delete; // Should never be instantiated
2157 :
2158 : public:
2159 0 : static void TraceSequence(JSTracer* trc, JS::Value* valp, JS::Value* end) {
2160 0 : for (; valp != end; ++valp) {
2161 0 : JS::UnsafeTraceRoot(trc, valp, "sequence<any>");
2162 : }
2163 0 : }
2164 : };
2165 :
2166 : // sequence<sequence<T>>
2167 : template<typename T>
2168 : class SequenceTracer<Sequence<T>, false, false, false>
2169 : {
2170 : explicit SequenceTracer() = delete; // Should never be instantiated
2171 :
2172 : public:
2173 : static void TraceSequence(JSTracer* trc, Sequence<T>* seqp, Sequence<T>* end) {
2174 : for (; seqp != end; ++seqp) {
2175 : DoTraceSequence(trc, *seqp);
2176 : }
2177 : }
2178 : };
2179 :
2180 : // sequence<sequence<T>> as return value
2181 : template<typename T>
2182 : class SequenceTracer<nsTArray<T>, false, false, false>
2183 : {
2184 : explicit SequenceTracer() = delete; // Should never be instantiated
2185 :
2186 : public:
2187 : static void TraceSequence(JSTracer* trc, nsTArray<T>* seqp, nsTArray<T>* end) {
2188 : for (; seqp != end; ++seqp) {
2189 : DoTraceSequence(trc, *seqp);
2190 : }
2191 : }
2192 : };
2193 :
2194 : // sequence<someDictionary>
2195 : template<typename T>
2196 : class SequenceTracer<T, true, false, false>
2197 : {
2198 : explicit SequenceTracer() = delete; // Should never be instantiated
2199 :
2200 : public:
2201 0 : static void TraceSequence(JSTracer* trc, T* dictp, T* end) {
2202 0 : for (; dictp != end; ++dictp) {
2203 0 : dictp->TraceDictionary(trc);
2204 : }
2205 0 : }
2206 : };
2207 :
2208 : // sequence<SomeTypedArray>
2209 : template<typename T>
2210 : class SequenceTracer<T, false, true, false>
2211 : {
2212 : explicit SequenceTracer() = delete; // Should never be instantiated
2213 :
2214 : public:
2215 : static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
2216 : for (; arrayp != end; ++arrayp) {
2217 : arrayp->TraceSelf(trc);
2218 : }
2219 : }
2220 : };
2221 :
2222 : // sequence<SomeOwningUnion>
2223 : template<typename T>
2224 : class SequenceTracer<T, false, false, true>
2225 : {
2226 : explicit SequenceTracer() = delete; // Should never be instantiated
2227 :
2228 : public:
2229 0 : static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
2230 0 : for (; arrayp != end; ++arrayp) {
2231 0 : arrayp->TraceUnion(trc);
2232 : }
2233 0 : }
2234 : };
2235 :
2236 : // sequence<T?> with T? being a Nullable<T>
2237 : template<typename T>
2238 : class SequenceTracer<Nullable<T>, false, false, false>
2239 : {
2240 : explicit SequenceTracer() = delete; // Should never be instantiated
2241 :
2242 : public:
2243 : static void TraceSequence(JSTracer* trc, Nullable<T>* seqp,
2244 : Nullable<T>* end) {
2245 : for (; seqp != end; ++seqp) {
2246 : if (!seqp->IsNull()) {
2247 : // Pretend like we actually have a length-one sequence here so
2248 : // we can do template instantiation correctly for T.
2249 : T& val = seqp->Value();
2250 : T* ptr = &val;
2251 : SequenceTracer<T>::TraceSequence(trc, ptr, ptr+1);
2252 : }
2253 : }
2254 : }
2255 : };
2256 :
2257 : template<typename K, typename V>
2258 0 : void TraceRecord(JSTracer* trc, Record<K, V>& record)
2259 : {
2260 0 : for (auto& entry : record.Entries()) {
2261 : // Act like it's a one-element sequence to leverage all that infrastructure.
2262 0 : SequenceTracer<V>::TraceSequence(trc, &entry.mValue, &entry.mValue + 1);
2263 : }
2264 0 : }
2265 :
2266 : // sequence<record>
2267 : template<typename K, typename V>
2268 : class SequenceTracer<Record<K, V>, false, false, false>
2269 : {
2270 : explicit SequenceTracer() = delete; // Should never be instantiated
2271 :
2272 : public:
2273 : static void TraceSequence(JSTracer* trc, Record<K, V>* seqp,
2274 : Record<K, V>* end) {
2275 : for (; seqp != end; ++seqp) {
2276 : TraceRecord(trc, *seqp);
2277 : }
2278 : }
2279 : };
2280 :
2281 : template<typename T>
2282 0 : void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq)
2283 : {
2284 0 : SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
2285 0 : seq.Elements() + seq.Length());
2286 0 : }
2287 :
2288 : template<typename T>
2289 0 : void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq)
2290 : {
2291 0 : SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
2292 0 : seq.Elements() + seq.Length());
2293 0 : }
2294 :
2295 : // Rooter class for sequences; this is what we mostly use in the codegen
2296 : template<typename T>
2297 13 : class MOZ_RAII SequenceRooter final : private JS::CustomAutoRooter
2298 : {
2299 : public:
2300 0 : SequenceRooter(JSContext *aCx, FallibleTArray<T>* aSequence
2301 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2302 0 : : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2303 : mFallibleArray(aSequence),
2304 0 : mSequenceType(eFallibleArray)
2305 : {
2306 0 : }
2307 :
2308 13 : SequenceRooter(JSContext *aCx, InfallibleTArray<T>* aSequence
2309 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2310 13 : : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2311 : mInfallibleArray(aSequence),
2312 13 : mSequenceType(eInfallibleArray)
2313 : {
2314 13 : }
2315 :
2316 : SequenceRooter(JSContext *aCx, Nullable<nsTArray<T> >* aSequence
2317 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2318 : : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2319 : mNullableArray(aSequence),
2320 : mSequenceType(eNullableArray)
2321 : {
2322 : }
2323 :
2324 : private:
2325 : enum SequenceType {
2326 : eInfallibleArray,
2327 : eFallibleArray,
2328 : eNullableArray
2329 : };
2330 :
2331 0 : virtual void trace(JSTracer *trc) override
2332 : {
2333 0 : if (mSequenceType == eFallibleArray) {
2334 0 : DoTraceSequence(trc, *mFallibleArray);
2335 0 : } else if (mSequenceType == eInfallibleArray) {
2336 0 : DoTraceSequence(trc, *mInfallibleArray);
2337 : } else {
2338 0 : MOZ_ASSERT(mSequenceType == eNullableArray);
2339 0 : if (!mNullableArray->IsNull()) {
2340 0 : DoTraceSequence(trc, mNullableArray->Value());
2341 : }
2342 : }
2343 0 : }
2344 :
2345 : union {
2346 : InfallibleTArray<T>* mInfallibleArray;
2347 : FallibleTArray<T>* mFallibleArray;
2348 : Nullable<nsTArray<T> >* mNullableArray;
2349 : };
2350 :
2351 : SequenceType mSequenceType;
2352 : };
2353 :
2354 : // Rooter class for Record; this is what we mostly use in the codegen.
2355 : template<typename K, typename V>
2356 0 : class MOZ_RAII RecordRooter final : private JS::CustomAutoRooter
2357 : {
2358 : public:
2359 0 : RecordRooter(JSContext *aCx, Record<K, V>* aRecord
2360 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2361 0 : : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2362 : mRecord(aRecord),
2363 0 : mRecordType(eRecord)
2364 : {
2365 0 : }
2366 :
2367 : RecordRooter(JSContext *aCx, Nullable<Record<K, V>>* aRecord
2368 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2369 : : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
2370 : mNullableRecord(aRecord),
2371 : mRecordType(eNullableRecord)
2372 : {
2373 : }
2374 :
2375 : private:
2376 : enum RecordType {
2377 : eRecord,
2378 : eNullableRecord
2379 : };
2380 :
2381 0 : virtual void trace(JSTracer *trc) override
2382 : {
2383 0 : if (mRecordType == eRecord) {
2384 0 : TraceRecord(trc, *mRecord);
2385 : } else {
2386 0 : MOZ_ASSERT(mRecordType == eNullableRecord);
2387 0 : if (!mNullableRecord->IsNull()) {
2388 0 : TraceRecord(trc, mNullableRecord->Value());
2389 : }
2390 : }
2391 0 : }
2392 :
2393 : union {
2394 : Record<K, V>* mRecord;
2395 : Nullable<Record<K, V>>* mNullableRecord;
2396 : };
2397 :
2398 : RecordType mRecordType;
2399 : };
2400 :
2401 : template<typename T>
2402 : class MOZ_RAII RootedUnion : public T,
2403 : private JS::CustomAutoRooter
2404 : {
2405 : public:
2406 : explicit RootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
2407 : T(),
2408 : JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
2409 : {
2410 : }
2411 :
2412 : virtual void trace(JSTracer *trc) override
2413 : {
2414 : this->TraceUnion(trc);
2415 : }
2416 : };
2417 :
2418 : template<typename T>
2419 : class MOZ_STACK_CLASS NullableRootedUnion : public Nullable<T>,
2420 : private JS::CustomAutoRooter
2421 : {
2422 : public:
2423 : explicit NullableRootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
2424 : Nullable<T>(),
2425 : JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
2426 : {
2427 : }
2428 :
2429 : virtual void trace(JSTracer *trc) override
2430 : {
2431 : if (!this->IsNull()) {
2432 : this->Value().TraceUnion(trc);
2433 : }
2434 : }
2435 : };
2436 :
2437 : inline bool
2438 189 : IdEquals(jsid id, const char* string)
2439 : {
2440 378 : return JSID_IS_STRING(id) &&
2441 378 : JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
2442 : }
2443 :
2444 : inline bool
2445 0 : AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector, const char* name)
2446 : {
2447 0 : return vector.growBy(1) &&
2448 0 : AtomizeAndPinJSString(cx, *(vector[vector.length() - 1]).address(), name);
2449 : }
2450 :
2451 : // We use one constructor JSNative to represent all DOM interface objects (so
2452 : // we can easily detect when we need to wrap them in an Xray wrapper). We store
2453 : // the real JSNative in the mNative member of a JSNativeHolder in the
2454 : // CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction object for a
2455 : // specific interface object. We also store the NativeProperties in the
2456 : // JSNativeHolder.
2457 : // Note that some interface objects are not yet a JSFunction but a normal
2458 : // JSObject with a DOMJSClass, those do not use these slots.
2459 :
2460 : enum {
2461 : CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT = 0
2462 : };
2463 :
2464 : bool
2465 : Constructor(JSContext* cx, unsigned argc, JS::Value* vp);
2466 :
2467 : // Implementation of the bits that XrayWrapper needs
2468 :
2469 : /**
2470 : * This resolves operations, attributes and constants of the interfaces for obj.
2471 : *
2472 : * wrapper is the Xray JS object.
2473 : * obj is the target object of the Xray, a binding's instance object or a
2474 : * interface or interface prototype object.
2475 : */
2476 : bool
2477 : XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
2478 : JS::Handle<JSObject*> obj,
2479 : JS::Handle<jsid> id,
2480 : JS::MutableHandle<JS::PropertyDescriptor> desc,
2481 : bool& cacheOnHolder);
2482 :
2483 : /**
2484 : * Define a property on obj through an Xray wrapper.
2485 : *
2486 : * wrapper is the Xray JS object.
2487 : * obj is the target object of the Xray, a binding's instance object or a
2488 : * interface or interface prototype object.
2489 : * id and desc are the parameters for the property to be defined.
2490 : * result is the out-parameter indicating success (read it only if
2491 : * this returns true and also sets *defined to true).
2492 : * defined will be set to true if a property was set as a result of this call.
2493 : */
2494 : bool
2495 : XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
2496 : JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
2497 : JS::Handle<JS::PropertyDescriptor> desc,
2498 : JS::ObjectOpResult &result,
2499 : bool *defined);
2500 :
2501 : /**
2502 : * Add to props the property keys of all indexed or named properties of obj and
2503 : * operations, attributes and constants of the interfaces for obj.
2504 : *
2505 : * wrapper is the Xray JS object.
2506 : * obj is the target object of the Xray, a binding's instance object or a
2507 : * interface or interface prototype object.
2508 : * flags are JSITER_* flags.
2509 : */
2510 : bool
2511 : XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
2512 : JS::Handle<JSObject*> obj,
2513 : unsigned flags, JS::AutoIdVector& props);
2514 :
2515 : /**
2516 : * Returns the prototype to use for an Xray for a DOM object, wrapped in cx's
2517 : * compartment. This always returns the prototype that would be used for a DOM
2518 : * object if we ignore any changes that might have been done to the prototype
2519 : * chain by JS, the XBL code or plugins.
2520 : *
2521 : * cx should be in the Xray's compartment.
2522 : * obj is the target object of the Xray, a binding's instance object or an
2523 : * interface or interface prototype object.
2524 : */
2525 : inline bool
2526 46 : XrayGetNativeProto(JSContext* cx, JS::Handle<JSObject*> obj,
2527 : JS::MutableHandle<JSObject*> protop)
2528 : {
2529 92 : JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
2530 : {
2531 92 : JSAutoCompartment ac(cx, global);
2532 46 : const DOMJSClass* domClass = GetDOMClass(obj);
2533 46 : if (domClass) {
2534 28 : ProtoHandleGetter protoGetter = domClass->mGetProto;
2535 28 : if (protoGetter) {
2536 28 : protop.set(protoGetter(cx));
2537 : } else {
2538 0 : protop.set(JS::GetRealmObjectPrototype(cx));
2539 : }
2540 18 : } else if (JS_ObjectIsFunction(cx, obj)) {
2541 0 : MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
2542 0 : protop.set(JS::GetRealmFunctionPrototype(cx));
2543 : } else {
2544 18 : const js::Class* clasp = js::GetObjectClass(obj);
2545 18 : MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
2546 : ProtoGetter protoGetter =
2547 18 : DOMIfaceAndProtoJSClass::FromJSClass(clasp)->mGetParentProto;
2548 18 : protop.set(protoGetter(cx));
2549 : }
2550 : }
2551 :
2552 92 : return JS_WrapObject(cx, protop);
2553 : }
2554 :
2555 : /**
2556 : * Get the Xray expando class to use for the given DOM object.
2557 : */
2558 : const JSClass*
2559 : XrayGetExpandoClass(JSContext* cx, JS::Handle<JSObject*> obj);
2560 :
2561 : /**
2562 : * Delete a named property, if any. Return value is false if exception thrown,
2563 : * true otherwise. The caller should not do any more work after calling this
2564 : * function, because it has no way whether a deletion was performed and hence
2565 : * opresult already has state set on it. If callers ever need to change that,
2566 : * add a "bool* found" argument and change the generated DeleteNamedProperty to
2567 : * use it instead of a local variable.
2568 : */
2569 : bool
2570 : XrayDeleteNamedProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
2571 : JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
2572 : JS::ObjectOpResult& opresult);
2573 :
2574 : /**
2575 : * Get the object which should be used to cache the return value of a property
2576 : * getter in the case of a [Cached] or [StoreInSlot] property. `obj` is the
2577 : * `this` value for our property getter that we're working with.
2578 : *
2579 : * This function can return null on failure to allocate the object, throwing on
2580 : * the JSContext in the process.
2581 : *
2582 : * The isXray outparam will be set to true if obj is an Xray and false
2583 : * otherwise.
2584 : *
2585 : * Note that the Slow version should only be called from
2586 : * GetCachedSlotStorageObject.
2587 : */
2588 : JSObject*
2589 : GetCachedSlotStorageObjectSlow(JSContext* cx, JS::Handle<JSObject*> obj,
2590 : bool* isXray);
2591 :
2592 : inline JSObject*
2593 2 : GetCachedSlotStorageObject(JSContext* cx, JS::Handle<JSObject*> obj,
2594 : bool* isXray) {
2595 2 : if (IsDOMObject(obj)) {
2596 2 : *isXray = false;
2597 2 : return obj;
2598 : }
2599 :
2600 0 : return GetCachedSlotStorageObjectSlow(cx, obj, isXray);
2601 : }
2602 :
2603 : extern NativePropertyHooks sEmptyNativePropertyHooks;
2604 :
2605 : extern const js::ClassOps sBoringInterfaceObjectClassClassOps;
2606 :
2607 : extern const js::ObjectOps sInterfaceObjectClassObjectOps;
2608 :
2609 : inline bool
2610 1272 : UseDOMXray(JSObject* obj)
2611 : {
2612 1272 : const js::Class* clasp = js::GetObjectClass(obj);
2613 2453 : return IsDOMClass(clasp) ||
2614 2453 : JS_IsNativeFunction(obj, Constructor) ||
2615 2453 : IsDOMIfaceAndProtoClass(clasp);
2616 : }
2617 :
2618 : #ifdef DEBUG
2619 : inline bool
2620 1 : HasConstructor(JSObject* obj)
2621 : {
2622 2 : return JS_IsNativeFunction(obj, Constructor) ||
2623 2 : js::GetObjectClass(obj)->getConstruct();
2624 : }
2625 : #endif
2626 :
2627 : // Helpers for creating a const version of a type.
2628 : template<typename T>
2629 2426 : const T& Constify(T& arg)
2630 : {
2631 2426 : return arg;
2632 : }
2633 :
2634 : // Helper for turning (Owning)NonNull<T> into T&
2635 : template<typename T>
2636 70 : T& NonNullHelper(T& aArg)
2637 : {
2638 70 : return aArg;
2639 : }
2640 :
2641 : template<typename T>
2642 109 : T& NonNullHelper(NonNull<T>& aArg)
2643 : {
2644 109 : return aArg;
2645 : }
2646 :
2647 : template<typename T>
2648 : const T& NonNullHelper(const NonNull<T>& aArg)
2649 : {
2650 : return aArg;
2651 : }
2652 :
2653 : template<typename T>
2654 0 : T& NonNullHelper(OwningNonNull<T>& aArg)
2655 : {
2656 0 : return aArg;
2657 : }
2658 :
2659 : template<typename T>
2660 : const T& NonNullHelper(const OwningNonNull<T>& aArg)
2661 : {
2662 : return aArg;
2663 : }
2664 :
2665 : inline
2666 : void NonNullHelper(NonNull<binding_detail::FakeString>& aArg)
2667 : {
2668 : // This overload is here to make sure that we never end up applying
2669 : // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
2670 : // try to, it should fail to compile, since presumably the caller will try to
2671 : // use our nonexistent return value.
2672 : }
2673 :
2674 : inline
2675 : void NonNullHelper(const NonNull<binding_detail::FakeString>& aArg)
2676 : {
2677 : // This overload is here to make sure that we never end up applying
2678 : // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
2679 : // try to, it should fail to compile, since presumably the caller will try to
2680 : // use our nonexistent return value.
2681 : }
2682 :
2683 : inline
2684 : void NonNullHelper(binding_detail::FakeString& aArg)
2685 : {
2686 : // This overload is here to make sure that we never end up applying
2687 : // NonNullHelper to a FakeString before we've constified it. If we
2688 : // try to, it should fail to compile, since presumably the caller will try to
2689 : // use our nonexistent return value.
2690 : }
2691 :
2692 : MOZ_ALWAYS_INLINE
2693 1726 : const nsAString& NonNullHelper(const binding_detail::FakeString& aArg)
2694 : {
2695 1726 : return aArg;
2696 : }
2697 :
2698 : // Reparent the wrapper of aObj to whatever its native now thinks its
2699 : // parent should be.
2700 : nsresult
2701 : ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObj);
2702 :
2703 : /**
2704 : * Used to implement the Symbol.hasInstance property of an interface object.
2705 : */
2706 : bool
2707 : InterfaceHasInstance(JSContext* cx, unsigned argc, JS::Value* vp);
2708 :
2709 : bool
2710 : InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
2711 : JS::Handle<JSObject*> instance,
2712 : bool* bp);
2713 :
2714 : // Helper for lenient getters/setters to report to console. If this
2715 : // returns false, we couldn't even get a global.
2716 : bool
2717 : ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj);
2718 :
2719 : // Given a JSObject* that represents the chrome side of a JS-implemented WebIDL
2720 : // interface, get the nsIGlobalObject corresponding to the content side, if any.
2721 : // A false return means an exception was thrown.
2722 : bool
2723 : GetContentGlobalForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
2724 : nsIGlobalObject** global);
2725 :
2726 : void
2727 : ConstructJSImplementation(const char* aContractId,
2728 : nsIGlobalObject* aGlobal,
2729 : JS::MutableHandle<JSObject*> aObject,
2730 : ErrorResult& aRv);
2731 :
2732 : already_AddRefed<nsIGlobalObject>
2733 : ConstructJSImplementation(const char* aContractId,
2734 : const GlobalObject& aGlobal,
2735 : JS::MutableHandle<JSObject*> aObject,
2736 : ErrorResult& aRv);
2737 :
2738 : /**
2739 : * Convert an nsCString to jsval, returning true on success.
2740 : * These functions are intended for ByteString implementations.
2741 : * As such, the string is not UTF-8 encoded. Any UTF8 strings passed to these
2742 : * methods will be mangled.
2743 : */
2744 : bool NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
2745 : JS::MutableHandle<JS::Value> rval);
2746 0 : inline bool ByteStringToJsval(JSContext *cx, const nsACString &str,
2747 : JS::MutableHandle<JS::Value> rval)
2748 : {
2749 0 : if (str.IsVoid()) {
2750 0 : rval.setNull();
2751 0 : return true;
2752 : }
2753 0 : return NonVoidByteStringToJsval(cx, str, rval);
2754 : }
2755 :
2756 : template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
2757 : struct PreserveWrapperHelper
2758 : {
2759 0 : static void PreserveWrapper(T* aObject)
2760 : {
2761 0 : aObject->PreserveWrapper(aObject, NS_CYCLE_COLLECTION_PARTICIPANT(T));
2762 0 : }
2763 : };
2764 :
2765 : template<class T>
2766 : struct PreserveWrapperHelper<T, true>
2767 : {
2768 164 : static void PreserveWrapper(T* aObject)
2769 : {
2770 164 : aObject->PreserveWrapper(reinterpret_cast<nsISupports*>(aObject));
2771 164 : }
2772 : };
2773 :
2774 : template<class T>
2775 164 : void PreserveWrapper(T* aObject)
2776 : {
2777 164 : PreserveWrapperHelper<T>::PreserveWrapper(aObject);
2778 164 : }
2779 :
2780 : template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
2781 : struct CastingAssertions
2782 : {
2783 0 : static bool ToSupportsIsCorrect(T*)
2784 : {
2785 0 : return true;
2786 : }
2787 0 : static bool ToSupportsIsOnPrimaryInheritanceChain(T*, nsWrapperCache*)
2788 : {
2789 0 : return true;
2790 : }
2791 : };
2792 :
2793 : template<class T>
2794 : struct CastingAssertions<T, true>
2795 : {
2796 2560 : static bool ToSupportsIsCorrect(T* aObject)
2797 : {
2798 2560 : return ToSupports(aObject) == reinterpret_cast<nsISupports*>(aObject);
2799 : }
2800 2560 : static bool ToSupportsIsOnPrimaryInheritanceChain(T* aObject,
2801 : nsWrapperCache* aCache)
2802 : {
2803 2560 : return reinterpret_cast<void*>(aObject) != aCache;
2804 : }
2805 : };
2806 :
2807 : template<class T>
2808 : bool
2809 2560 : ToSupportsIsCorrect(T* aObject)
2810 : {
2811 2560 : return CastingAssertions<T>::ToSupportsIsCorrect(aObject);
2812 : }
2813 :
2814 : template<class T>
2815 : bool
2816 2560 : ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache)
2817 : {
2818 : return CastingAssertions<T>::ToSupportsIsOnPrimaryInheritanceChain(aObject,
2819 2560 : aCache);
2820 : }
2821 :
2822 : // The BindingJSObjectCreator class is supposed to be used by a caller that
2823 : // wants to create and initialise a binding JSObject. After initialisation has
2824 : // been successfully completed it should call ForgetObject().
2825 : // The BindingJSObjectCreator object will root the JSObject until ForgetObject()
2826 : // is called on it. If the native object for the binding is refcounted it will
2827 : // also hold a strong reference to it, that reference is transferred to the
2828 : // JSObject (which holds the native in a slot) when ForgetObject() is called. If
2829 : // the BindingJSObjectCreator object is destroyed and ForgetObject() was never
2830 : // called on it then the JSObject's slot holding the native will be set to
2831 : // undefined, and for a refcounted native the strong reference will be released.
2832 : template<class T>
2833 : class MOZ_STACK_CLASS BindingJSObjectCreator
2834 : {
2835 : public:
2836 2552 : explicit BindingJSObjectCreator(JSContext* aCx)
2837 2552 : : mReflector(aCx)
2838 : {
2839 2552 : }
2840 :
2841 2552 : ~BindingJSObjectCreator()
2842 : {
2843 2552 : if (mReflector) {
2844 0 : js::SetReservedSlot(mReflector, DOM_OBJECT_SLOT, JS::UndefinedValue());
2845 : }
2846 2552 : }
2847 :
2848 : void
2849 53 : CreateProxyObject(JSContext* aCx, const js::Class* aClass,
2850 : const DOMProxyHandler* aHandler,
2851 : JS::Handle<JSObject*> aProto, T* aNative,
2852 : JS::Handle<JS::Value> aExpandoValue,
2853 : JS::MutableHandle<JSObject*> aReflector)
2854 : {
2855 53 : js::ProxyOptions options;
2856 53 : options.setClass(aClass);
2857 53 : aReflector.set(js::NewProxyObject(aCx, aHandler, aExpandoValue, aProto,
2858 : options));
2859 53 : if (aReflector) {
2860 53 : js::SetProxyReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
2861 53 : mNative = aNative;
2862 53 : mReflector = aReflector;
2863 : }
2864 53 : }
2865 :
2866 : void
2867 2499 : CreateObject(JSContext* aCx, const JSClass* aClass,
2868 : JS::Handle<JSObject*> aProto,
2869 : T* aNative, JS::MutableHandle<JSObject*> aReflector)
2870 : {
2871 2499 : aReflector.set(JS_NewObjectWithGivenProto(aCx, aClass, aProto));
2872 2499 : if (aReflector) {
2873 2499 : js::SetReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
2874 2499 : mNative = aNative;
2875 2499 : mReflector = aReflector;
2876 : }
2877 2499 : }
2878 :
2879 : void
2880 2552 : InitializationSucceeded()
2881 : {
2882 : void* dummy;
2883 2552 : mNative.forget(&dummy);
2884 2552 : mReflector = nullptr;
2885 2552 : }
2886 :
2887 : private:
2888 : struct OwnedNative
2889 : {
2890 : // Make sure the native objects inherit from NonRefcountedDOMObject so
2891 : // that we log their ctor and dtor.
2892 : static_assert(IsBaseOf<NonRefcountedDOMObject, T>::value,
2893 : "Non-refcounted objects with DOM bindings should inherit "
2894 : "from NonRefcountedDOMObject.");
2895 :
2896 : OwnedNative&
2897 0 : operator=(T* aNative)
2898 : {
2899 0 : return *this;
2900 : }
2901 :
2902 : // This signature sucks, but it's the only one that will make a nsRefPtr
2903 : // just forget about its pointer without warning.
2904 : void
2905 0 : forget(void**)
2906 : {
2907 0 : }
2908 : };
2909 :
2910 : JS::Rooted<JSObject*> mReflector;
2911 : typename Conditional<IsRefcounted<T>::value, RefPtr<T>, OwnedNative>::Type mNative;
2912 : };
2913 :
2914 : template<class T>
2915 : struct DeferredFinalizerImpl
2916 : {
2917 : typedef typename Conditional<IsSame<T, nsISupports>::value,
2918 : nsCOMPtr<T>,
2919 : typename Conditional<IsRefcounted<T>::value,
2920 : RefPtr<T>,
2921 : nsAutoPtr<T>>::Type>::Type SmartPtr;
2922 : typedef SegmentedVector<SmartPtr> SmartPtrArray;
2923 :
2924 : static_assert(IsSame<T, nsISupports>::value || !IsBaseOf<nsISupports, T>::value,
2925 : "nsISupports classes should all use the nsISupports instantiation");
2926 :
2927 : static inline void
2928 58 : AppendAndTake(SegmentedVector<nsCOMPtr<nsISupports>>& smartPtrArray, nsISupports* ptr)
2929 : {
2930 58 : smartPtrArray.InfallibleAppend(dont_AddRef(ptr));
2931 58 : }
2932 : template<class U>
2933 : static inline void
2934 0 : AppendAndTake(SegmentedVector<RefPtr<U>>& smartPtrArray, U* ptr)
2935 : {
2936 0 : smartPtrArray.InfallibleAppend(dont_AddRef(ptr));
2937 0 : }
2938 : template<class U>
2939 : static inline void
2940 0 : AppendAndTake(SegmentedVector<nsAutoPtr<U>>& smartPtrArray, U* ptr)
2941 : {
2942 0 : smartPtrArray.InfallibleAppend(ptr);
2943 0 : }
2944 :
2945 : static void*
2946 58 : AppendDeferredFinalizePointer(void* aData, void* aObject)
2947 : {
2948 58 : SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
2949 58 : if (!pointers) {
2950 1 : pointers = new SmartPtrArray();
2951 : }
2952 58 : AppendAndTake(*pointers, static_cast<T*>(aObject));
2953 58 : return pointers;
2954 : }
2955 : static bool
2956 0 : DeferredFinalize(uint32_t aSlice, void* aData)
2957 : {
2958 0 : MOZ_ASSERT(aSlice > 0, "nonsensical/useless call with aSlice == 0");
2959 0 : SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
2960 0 : uint32_t oldLen = pointers->Length();
2961 0 : if (oldLen < aSlice) {
2962 0 : aSlice = oldLen;
2963 : }
2964 0 : uint32_t newLen = oldLen - aSlice;
2965 0 : pointers->PopLastN(aSlice);
2966 0 : if (newLen == 0) {
2967 0 : delete pointers;
2968 0 : return true;
2969 : }
2970 0 : return false;
2971 : }
2972 : };
2973 :
2974 : template<class T,
2975 : bool isISupports=IsBaseOf<nsISupports, T>::value>
2976 : struct DeferredFinalizer
2977 : {
2978 : static void
2979 0 : AddForDeferredFinalization(T* aObject)
2980 : {
2981 : typedef DeferredFinalizerImpl<T> Impl;
2982 0 : DeferredFinalize(Impl::AppendDeferredFinalizePointer,
2983 : Impl::DeferredFinalize, aObject);
2984 0 : }
2985 : };
2986 :
2987 : template<class T>
2988 : struct DeferredFinalizer<T, true>
2989 : {
2990 : static void
2991 58 : AddForDeferredFinalization(T* aObject)
2992 : {
2993 58 : DeferredFinalize(reinterpret_cast<nsISupports*>(aObject));
2994 58 : }
2995 : };
2996 :
2997 : template<class T>
2998 : static void
2999 58 : AddForDeferredFinalization(T* aObject)
3000 : {
3001 58 : DeferredFinalizer<T>::AddForDeferredFinalization(aObject);
3002 58 : }
3003 :
3004 : // This returns T's CC participant if it participates in CC or null if it
3005 : // doesn't. This also returns null for classes that don't inherit from
3006 : // nsISupports (QI should be used to get the participant for those).
3007 : template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
3008 : class GetCCParticipant
3009 : {
3010 : // Helper for GetCCParticipant for classes that participate in CC.
3011 : template<class U>
3012 : static constexpr nsCycleCollectionParticipant*
3013 : GetHelper(int, typename U::NS_CYCLE_COLLECTION_INNERCLASS* dummy=nullptr)
3014 : {
3015 : return T::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant();
3016 : }
3017 : // Helper for GetCCParticipant for classes that don't participate in CC.
3018 : template<class U>
3019 : static constexpr nsCycleCollectionParticipant*
3020 : GetHelper(double)
3021 : {
3022 : return nullptr;
3023 : }
3024 :
3025 : public:
3026 : static constexpr nsCycleCollectionParticipant*
3027 : Get()
3028 : {
3029 : // Passing int() here will try to call the GetHelper that takes an int as
3030 : // its firt argument. If T doesn't participate in CC then substitution for
3031 : // the second argument (with a default value) will fail and because of
3032 : // SFINAE the next best match (the variant taking a double) will be called.
3033 : return GetHelper<T>(int());
3034 : }
3035 : };
3036 :
3037 : template<class T>
3038 : class GetCCParticipant<T, true>
3039 : {
3040 : public:
3041 : static constexpr nsCycleCollectionParticipant*
3042 : Get()
3043 : {
3044 : return nullptr;
3045 : }
3046 : };
3047 :
3048 : void
3049 : FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
3050 :
3051 : bool
3052 : ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
3053 : JS::Handle<jsid> aId, bool* aResolvedp);
3054 :
3055 : bool
3056 : MayResolveGlobal(const JSAtomState& aNames, jsid aId, JSObject* aMaybeObj);
3057 :
3058 : bool
3059 : EnumerateGlobal(JSContext* aCx, JS::HandleObject aObj,
3060 : JS::AutoIdVector& aProperties, bool aEnumerableOnly);
3061 :
3062 : template <class T>
3063 : struct CreateGlobalOptions
3064 : {
3065 : static constexpr ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
3066 : ProtoAndIfaceCache::NonWindowLike;
3067 0 : static void TraceGlobal(JSTracer* aTrc, JSObject* aObj)
3068 : {
3069 0 : mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
3070 0 : }
3071 1 : static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
3072 : {
3073 1 : MOZ_ALWAYS_TRUE(TryPreserveWrapper(aGlobal));
3074 :
3075 1 : return true;
3076 : }
3077 : };
3078 :
3079 : template <>
3080 : struct CreateGlobalOptions<nsGlobalWindow>
3081 : {
3082 : static constexpr ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
3083 : ProtoAndIfaceCache::WindowLike;
3084 : static void TraceGlobal(JSTracer* aTrc, JSObject* aObj);
3085 : static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
3086 : };
3087 :
3088 : nsresult
3089 : RegisterDOMNames();
3090 :
3091 : // The return value is true if we created and successfully performed our part of
3092 : // the setup for the global, false otherwise.
3093 : //
3094 : // Typically this method's caller will want to ensure that
3095 : // xpc::InitGlobalObjectOptions is called before, and xpc::InitGlobalObject is
3096 : // called after, this method, to ensure that this global object and its
3097 : // compartment are consistent with other global objects.
3098 : template <class T, ProtoHandleGetter GetProto>
3099 : bool
3100 8 : CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
3101 : const JSClass* aClass, JS::CompartmentOptions& aOptions,
3102 : JSPrincipals* aPrincipal, bool aInitStandardClasses,
3103 : JS::MutableHandle<JSObject*> aGlobal)
3104 : {
3105 8 : aOptions.creationOptions().setTrace(CreateGlobalOptions<T>::TraceGlobal);
3106 8 : if (xpc::SharedMemoryEnabled()) {
3107 8 : aOptions.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
3108 : }
3109 :
3110 8 : aGlobal.set(JS_NewGlobalObject(aCx, aClass, aPrincipal,
3111 : JS::DontFireOnNewGlobalHook, aOptions));
3112 8 : if (!aGlobal) {
3113 0 : NS_WARNING("Failed to create global");
3114 0 : return false;
3115 : }
3116 :
3117 16 : JSAutoCompartment ac(aCx, aGlobal);
3118 :
3119 : {
3120 8 : js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
3121 8 : NS_ADDREF(aNative);
3122 :
3123 8 : aCache->SetWrapper(aGlobal);
3124 :
3125 8 : dom::AllocateProtoAndIfaceCache(aGlobal,
3126 : CreateGlobalOptions<T>::ProtoAndIfaceCacheKind);
3127 :
3128 8 : if (!CreateGlobalOptions<T>::PostCreateGlobal(aCx, aGlobal)) {
3129 0 : return false;
3130 : }
3131 : }
3132 :
3133 25 : if (aInitStandardClasses &&
3134 11 : !JS_InitStandardClasses(aCx, aGlobal)) {
3135 0 : NS_WARNING("Failed to init standard classes");
3136 0 : return false;
3137 : }
3138 :
3139 8 : JS::Handle<JSObject*> proto = GetProto(aCx);
3140 8 : if (!proto || !JS_SplicePrototype(aCx, aGlobal, proto)) {
3141 0 : NS_WARNING("Failed to set proto");
3142 0 : return false;
3143 : }
3144 :
3145 : bool succeeded;
3146 8 : if (!JS_SetImmutablePrototype(aCx, aGlobal, &succeeded)) {
3147 0 : return false;
3148 : }
3149 8 : MOZ_ASSERT(succeeded,
3150 : "making a fresh global object's [[Prototype]] immutable can "
3151 : "internally fail, but it should never be unsuccessful");
3152 :
3153 8 : return true;
3154 : }
3155 :
3156 : /*
3157 : * Holds a jsid that is initialized to a pinned string, with automatic
3158 : * conversion to Handle<jsid>, as it is held live forever by pinning.
3159 : */
3160 : class PinnedStringId
3161 : {
3162 : jsid id;
3163 :
3164 : public:
3165 8884 : PinnedStringId() : id(JSID_VOID) {}
3166 :
3167 73 : bool init(JSContext *cx, const char *string) {
3168 73 : JSString* str = JS_AtomizeAndPinString(cx, string);
3169 73 : if (!str)
3170 0 : return false;
3171 73 : id = INTERNED_STRING_TO_JSID(cx, str);
3172 73 : return true;
3173 : }
3174 :
3175 : operator const jsid& () {
3176 : return id;
3177 : }
3178 :
3179 132 : operator JS::Handle<jsid> () {
3180 : /* This is safe because we have pinned the string. */
3181 132 : return JS::Handle<jsid>::fromMarkedLocation(&id);
3182 : }
3183 : };
3184 :
3185 : bool
3186 : GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp);
3187 :
3188 : bool
3189 : GenericPromiseReturningBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp);
3190 :
3191 : bool
3192 : GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp);
3193 :
3194 : bool
3195 : GenericBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp);
3196 :
3197 : bool
3198 : GenericPromiseReturningBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp);
3199 :
3200 : bool
3201 : StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp);
3202 :
3203 : // ConvertExceptionToPromise should only be called when we have an error
3204 : // condition (e.g. returned false from a JSAPI method). Note that there may be
3205 : // no exception on cx, in which case this is an uncatchable failure that will
3206 : // simply be propagated. Otherwise this method will attempt to convert the
3207 : // exception to a Promise rejected with the exception that it will store in
3208 : // rval.
3209 : //
3210 : // promiseScope should be the scope in which the Promise should be created.
3211 : bool
3212 : ConvertExceptionToPromise(JSContext* cx,
3213 : JSObject* promiseScope,
3214 : JS::MutableHandle<JS::Value> rval);
3215 :
3216 : #ifdef DEBUG
3217 : void
3218 : AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
3219 : JS::Handle<JS::Value> aValue);
3220 : #endif
3221 :
3222 : // This function is called by the bindings layer for methods/getters/setters
3223 : // that are not safe to be called in prerendering mode. It checks to make sure
3224 : // that the |this| object is not running in a global that is in prerendering
3225 : // mode. Otherwise, it aborts execution of timers and event handlers, and
3226 : // returns false which gets converted to an uncatchable exception by the
3227 : // bindings layer.
3228 : bool
3229 : EnforceNotInPrerendering(JSContext* aCx, JSObject* aObj);
3230 :
3231 : // Handles the violation of a blacklisted action in prerendering mode by
3232 : // aborting the scripts, and preventing timers and event handlers from running
3233 : // in the window in the future.
3234 : void
3235 : HandlePrerenderingViolation(nsPIDOMWindowInner* aWindow);
3236 :
3237 : bool
3238 : CallerSubsumes(JSObject* aObject);
3239 :
3240 : MOZ_ALWAYS_INLINE bool
3241 0 : CallerSubsumes(JS::Handle<JS::Value> aValue)
3242 : {
3243 0 : if (!aValue.isObject()) {
3244 0 : return true;
3245 : }
3246 0 : return CallerSubsumes(&aValue.toObject());
3247 : }
3248 :
3249 : template<class T>
3250 : inline bool
3251 : WrappedJSToDictionary(JSContext* aCx, nsISupports* aObject, T& aDictionary)
3252 : {
3253 : nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
3254 : if (!wrappedObj) {
3255 : return false;
3256 : }
3257 :
3258 : JS::Rooted<JSObject*> obj(aCx, wrappedObj->GetJSObject());
3259 : if (!obj) {
3260 : return false;
3261 : }
3262 :
3263 : JSAutoCompartment ac(aCx, obj);
3264 : JS::Rooted<JS::Value> v(aCx, JS::ObjectValue(*obj));
3265 : return aDictionary.Init(aCx, v);
3266 : }
3267 :
3268 : template<class T>
3269 : inline bool
3270 : WrappedJSToDictionary(nsISupports* aObject, T& aDictionary)
3271 : {
3272 : nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
3273 : NS_ENSURE_TRUE(wrappedObj, false);
3274 : JS::Rooted<JSObject*> obj(RootingCx(), wrappedObj->GetJSObject());
3275 : NS_ENSURE_TRUE(obj, false);
3276 :
3277 : nsIGlobalObject* global = xpc::NativeGlobal(obj);
3278 : NS_ENSURE_TRUE(global, false);
3279 :
3280 : // we need this AutoEntryScript here because the spec requires us to execute
3281 : // getters when parsing a dictionary
3282 : AutoEntryScript aes(global, "WebIDL dictionary creation");
3283 :
3284 : JS::Rooted<JS::Value> v(aes.cx(), JS::ObjectValue(*obj));
3285 : return aDictionary.Init(aes.cx(), v);
3286 : }
3287 :
3288 :
3289 : template<class T, class S>
3290 : inline RefPtr<T>
3291 239 : StrongOrRawPtr(already_AddRefed<S>&& aPtr)
3292 : {
3293 239 : return aPtr.template downcast<T>();
3294 : }
3295 :
3296 : template<class T,
3297 : class ReturnType=typename Conditional<IsRefcounted<T>::value, T*,
3298 : nsAutoPtr<T>>::Type>
3299 : inline ReturnType
3300 804 : StrongOrRawPtr(T* aPtr)
3301 : {
3302 804 : return ReturnType(aPtr);
3303 : }
3304 :
3305 : template<class T, template<typename> class SmartPtr, class S>
3306 : inline void
3307 : StrongOrRawPtr(SmartPtr<S>&& aPtr) = delete;
3308 :
3309 : template<class T>
3310 : struct StrongPtrForMember
3311 : {
3312 : typedef typename Conditional<IsRefcounted<T>::value,
3313 : RefPtr<T>, nsAutoPtr<T>>::Type Type;
3314 : };
3315 :
3316 : namespace binding_detail {
3317 : inline
3318 : JSObject*
3319 2 : GetHackedNamespaceProtoObject(JSContext* aCx)
3320 : {
3321 2 : return JS_NewPlainObject(aCx);
3322 : }
3323 : } // namespace binding_detail
3324 :
3325 : // Resolve an id on the given global object that wants to be included in
3326 : // Exposed=System webidl annotations. False return value means exception
3327 : // thrown.
3328 : bool SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
3329 : JS::Handle<jsid> id, bool* resolvedp);
3330 :
3331 : // Enumerate all ids on the given global object that wants to be included in
3332 : // Exposed=System webidl annotations. False return value means exception
3333 : // thrown.
3334 : bool SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj);
3335 :
3336 : // Slot indexes for maplike/setlike forEach functions
3337 : #define FOREACH_CALLBACK_SLOT 0
3338 : #define FOREACH_MAPLIKEORSETLIKEOBJ_SLOT 1
3339 :
3340 : // Backing function for running .forEach() on maplike/setlike interfaces.
3341 : // Unpacks callback and maplike/setlike object from reserved slots, then runs
3342 : // callback for each key (and value, for maplikes)
3343 : bool ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
3344 :
3345 : // Unpacks backing object (ES6 map/set) from the reserved slot of a reflector
3346 : // for a maplike/setlike interface. If backing object does not exist, creates
3347 : // backing object in the compartment of the reflector involved, making this safe
3348 : // to use across compartments/via xrays. Return values of these methods will
3349 : // always be in the context compartment.
3350 : bool GetMaplikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
3351 : size_t aSlotIndex,
3352 : JS::MutableHandle<JSObject*> aBackingObj,
3353 : bool* aBackingObjCreated);
3354 : bool GetSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
3355 : size_t aSlotIndex,
3356 : JS::MutableHandle<JSObject*> aBackingObj,
3357 : bool* aBackingObjCreated);
3358 :
3359 : // Get the desired prototype object for an object construction from the given
3360 : // CallArgs. Null is returned if the default prototype should be used.
3361 : bool
3362 : GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
3363 : JS::MutableHandle<JSObject*> aDesiredProto);
3364 :
3365 : // Get the CustomElementReactionsStack for the docgroup of the global
3366 : // of the underlying object of aObj. This can be null if aObj can't
3367 : // be CheckUnwrapped, or if the global of the result has no docgroup
3368 : // (e.g. because it's not a Window global).
3369 : CustomElementReactionsStack*
3370 : GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj);
3371 : // This function is expected to be called from the constructor function for an
3372 : // HTML element interface; the global/callargs need to be whatever was passed to
3373 : // that constructor function.
3374 : already_AddRefed<nsGenericHTMLElement>
3375 : CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
3376 : ErrorResult& aRv);
3377 :
3378 : void
3379 : SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject,
3380 : UseCounter aUseCounter);
3381 :
3382 : // Warnings
3383 : void
3384 : DeprecationWarning(JSContext* aCx, JSObject* aObject,
3385 : nsIDocument::DeprecatedOperations aOperation);
3386 :
3387 : void
3388 : DeprecationWarning(const GlobalObject& aGlobal,
3389 : nsIDocument::DeprecatedOperations aOperation);
3390 :
3391 : // A callback to perform funToString on an interface object
3392 : JSString*
3393 : InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
3394 : unsigned /* indent */);
3395 :
3396 : namespace binding_detail {
3397 : // Get a JS global object that can be used for some temporary allocations. The
3398 : // idea is that this should be used for situations when you need to operate in
3399 : // _some_ compartment but don't care which one. A typical example is when you
3400 : // have non-JS input, non-JS output, but have to go through some sort of JS
3401 : // representation in the middle, so need a compartment to allocate things in.
3402 : //
3403 : // It's VERY important that any consumers of this function only do things that
3404 : // are guaranteed to be side-effect-free, even in the face of a script
3405 : // environment controlled by a hostile adversary. This is because in the worker
3406 : // case the global is in fact the worker global, so it and its standard objects
3407 : // are controlled by the worker script. This is why this function is in the
3408 : // binding_detail namespace. Any use of this function MUST be very carefully
3409 : // reviewed by someone who is sufficiently devious and has a very good
3410 : // understanding of all the code that will run while we're using the return
3411 : // value, including the SpiderMonkey parts.
3412 : JSObject* UnprivilegedJunkScopeOrWorkerGlobal();
3413 : } // namespace binding_detail
3414 :
3415 : } // namespace dom
3416 : } // namespace mozilla
3417 :
3418 : #endif /* mozilla_dom_BindingUtils_h__ */
|