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