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
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /**
8 : * A common base class for representing WebIDL callback function and
9 : * callback interface types in C++.
10 : *
11 : * This class implements common functionality like lifetime
12 : * management, initialization with the JS object, and setup of the
13 : * call environment. Subclasses are responsible for providing methods
14 : * that do the call into JS as needed.
15 : */
16 :
17 : #ifndef mozilla_dom_CallbackObject_h
18 : #define mozilla_dom_CallbackObject_h
19 :
20 : #include "nsISupports.h"
21 : #include "nsISupportsImpl.h"
22 : #include "nsCycleCollectionParticipant.h"
23 : #include "jswrapper.h"
24 : #include "mozilla/Assertions.h"
25 : #include "mozilla/ErrorResult.h"
26 : #include "mozilla/HoldDropJSObjects.h"
27 : #include "mozilla/MemoryReporting.h"
28 : #include "mozilla/OwningNonNull.h"
29 : #include "mozilla/dom/ScriptSettings.h"
30 : #include "nsWrapperCache.h"
31 : #include "nsJSEnvironment.h"
32 : #include "xpcpublic.h"
33 : #include "jsapi.h"
34 : #include "js/TracingAPI.h"
35 :
36 : namespace mozilla {
37 : namespace dom {
38 :
39 : #define DOM_CALLBACKOBJECT_IID \
40 : { 0xbe74c190, 0x6d76, 0x4991, \
41 : { 0x84, 0xb9, 0x65, 0x06, 0x99, 0xe6, 0x93, 0x2b } }
42 :
43 : class CallbackObject : public nsISupports
44 : {
45 : public:
46 : NS_DECLARE_STATIC_IID_ACCESSOR(DOM_CALLBACKOBJECT_IID)
47 :
48 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
49 9498 : NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(CallbackObject)
50 :
51 : // The caller may pass a global object which will act as an override for the
52 : // incumbent script settings object when the callback is invoked (overriding
53 : // the entry point computed from aCallback). If no override is required, the
54 : // caller should pass null. |aCx| is used to capture the current
55 : // stack, which is later used as an async parent when the callback
56 : // is invoked. aCx can be nullptr, in which case no stack is
57 : // captured.
58 13 : explicit CallbackObject(JSContext* aCx, JS::Handle<JSObject*> aCallback,
59 : nsIGlobalObject* aIncumbentGlobal)
60 13 : {
61 13 : if (aCx && JS::ContextOptionsRef(aCx).asyncStack()) {
62 0 : JS::RootedObject stack(aCx);
63 0 : if (!JS::CaptureCurrentStack(aCx, &stack)) {
64 0 : JS_ClearPendingException(aCx);
65 : }
66 0 : Init(aCallback, stack, aIncumbentGlobal);
67 : } else {
68 13 : Init(aCallback, nullptr, aIncumbentGlobal);
69 : }
70 13 : }
71 :
72 : // Instead of capturing the current stack to use as an async parent when the
73 : // callback is invoked, the caller can use this overload to pass in a stack
74 : // for that purpose.
75 235 : explicit CallbackObject(JS::Handle<JSObject*> aCallback,
76 : JS::Handle<JSObject*> aAsyncStack,
77 : nsIGlobalObject* aIncumbentGlobal)
78 235 : {
79 235 : Init(aCallback, aAsyncStack, aIncumbentGlobal);
80 235 : }
81 :
82 : // This is guaranteed to be non-null from the time the CallbackObject is
83 : // created until JavaScript has had a chance to run. It will only return null
84 : // after a JavaScript caller has called nukeSandbox on a Sandbox object, and
85 : // the cycle collector has had a chance to run.
86 : //
87 : // This means that any native callee which receives a CallbackObject as an
88 : // argument can safely rely on the callback being non-null so long as it
89 : // doesn't trigger any scripts before it accesses it.
90 294 : JS::Handle<JSObject*> CallbackOrNull() const
91 : {
92 294 : mCallback.exposeToActiveJS();
93 294 : return CallbackPreserveColor();
94 : }
95 :
96 294 : JSObject* GetCreationStack() const
97 : {
98 294 : return mCreationStack;
99 : }
100 :
101 0 : void MarkForCC()
102 : {
103 0 : mCallback.exposeToActiveJS();
104 0 : mCreationStack.exposeToActiveJS();
105 0 : }
106 :
107 : /*
108 : * This getter does not change the color of the JSObject meaning that the
109 : * object returned is not guaranteed to be kept alive past the next CC.
110 : *
111 : * This should only be called if you are certain that the return value won't
112 : * be passed into a JS API function and that it won't be stored without being
113 : * rooted (or otherwise signaling the stored value to the CC).
114 : */
115 1008 : JS::Handle<JSObject*> CallbackPreserveColor() const
116 : {
117 : // Calling fromMarkedLocation() is safe because we trace our mCallback, and
118 : // because the value of mCallback cannot change after if has been set.
119 1008 : return JS::Handle<JSObject*>::fromMarkedLocation(mCallback.address());
120 : }
121 :
122 : /*
123 : * If the callback is known to be non-gray, then this method can be
124 : * used instead of CallbackOrNull() to avoid the overhead of
125 : * ExposeObjectToActiveJS().
126 : */
127 21 : JS::Handle<JSObject*> CallbackKnownNotGray() const
128 : {
129 21 : MOZ_ASSERT(JS::ObjectIsNotGray(mCallback));
130 21 : return CallbackPreserveColor();
131 : }
132 :
133 294 : nsIGlobalObject* IncumbentGlobalOrNull() const
134 : {
135 294 : return mIncumbentGlobal;
136 : }
137 :
138 : enum ExceptionHandling {
139 : // Report any exception and don't throw it to the caller code.
140 : eReportExceptions,
141 : // Throw an exception to the caller code if the thrown exception is a
142 : // binding object for a DOMError or DOMException from the caller's scope,
143 : // otherwise report it.
144 : eRethrowContentExceptions,
145 : // Throw exceptions to the caller code, unless the caller compartment is
146 : // provided, the exception is not a DOMError or DOMException from the
147 : // caller compartment, and the caller compartment does not subsume our
148 : // unwrapped callback.
149 : eRethrowExceptions
150 : };
151 :
152 0 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
153 : {
154 0 : return aMallocSizeOf(this);
155 : }
156 :
157 : protected:
158 251 : virtual ~CallbackObject()
159 502 : {
160 251 : mozilla::DropJSObjects(this);
161 251 : }
162 :
163 0 : explicit CallbackObject(CallbackObject* aCallbackObject)
164 0 : {
165 0 : Init(aCallbackObject->mCallback, aCallbackObject->mCreationStack,
166 0 : aCallbackObject->mIncumbentGlobal);
167 0 : }
168 :
169 67 : bool operator==(const CallbackObject& aOther) const
170 : {
171 67 : JSObject* wrappedThis = CallbackPreserveColor();
172 67 : JSObject* wrappedOther = aOther.CallbackPreserveColor();
173 67 : if (!wrappedThis || !wrappedOther) {
174 0 : return this == &aOther;
175 : }
176 :
177 67 : JSObject* thisObj = js::UncheckedUnwrap(wrappedThis);
178 67 : JSObject* otherObj = js::UncheckedUnwrap(wrappedOther);
179 67 : return thisObj == otherObj;
180 : }
181 :
182 : class JSObjectsDropper final
183 : {
184 : public:
185 0 : explicit JSObjectsDropper(CallbackObject* aHolder)
186 0 : : mHolder(aHolder)
187 0 : {}
188 :
189 0 : ~JSObjectsDropper()
190 0 : {
191 0 : mHolder->ClearJSObjects();
192 0 : }
193 :
194 : private:
195 : RefPtr<CallbackObject> mHolder;
196 : };
197 :
198 : private:
199 461 : inline void InitNoHold(JSObject* aCallback, JSObject* aCreationStack,
200 : nsIGlobalObject* aIncumbentGlobal)
201 : {
202 461 : MOZ_ASSERT(aCallback && !mCallback);
203 : // Set script objects before we hold, on the off chance that a GC could
204 : // somehow happen in there... (which would be pretty odd, granted).
205 461 : mCallback = aCallback;
206 461 : mCreationStack = aCreationStack;
207 461 : if (aIncumbentGlobal) {
208 235 : mIncumbentGlobal = aIncumbentGlobal;
209 235 : mIncumbentJSGlobal = aIncumbentGlobal->GetGlobalJSObject();
210 : }
211 461 : }
212 :
213 248 : inline void Init(JSObject* aCallback, JSObject* aCreationStack,
214 : nsIGlobalObject* aIncumbentGlobal)
215 : {
216 248 : InitNoHold(aCallback, aCreationStack, aIncumbentGlobal);
217 248 : mozilla::HoldJSObjects(this);
218 248 : }
219 :
220 16 : inline void ClearJSReferences()
221 : {
222 16 : mCallback = nullptr;
223 16 : mCreationStack = nullptr;
224 16 : mIncumbentJSGlobal = nullptr;
225 16 : }
226 :
227 : CallbackObject(const CallbackObject&) = delete;
228 : CallbackObject& operator =(const CallbackObject&) = delete;
229 :
230 : protected:
231 0 : void ClearJSObjects()
232 : {
233 0 : MOZ_ASSERT_IF(mIncumbentJSGlobal, mCallback);
234 0 : if (mCallback) {
235 0 : ClearJSReferences();
236 : }
237 0 : }
238 :
239 : // For use from subclasses that want to be usable with Rooted.
240 : void Trace(JSTracer* aTracer);
241 :
242 : // For use from subclasses that want to be traced for a bit then possibly
243 : // switch to HoldJSObjects and do other slow JS-related init work we might do.
244 : // If we have more than one owner, this will HoldJSObjects and do said slow
245 : // init work; otherwise it will just forget all our JS references.
246 : void FinishSlowJSInitIfMoreThanOneOwner(JSContext* aCx);
247 :
248 : // Struct used as a way to force a CallbackObject constructor to not call
249 : // HoldJSObjects. We're putting it here so that CallbackObject subclasses will
250 : // have access to it, but outside code will not.
251 : //
252 : // Places that use this need to ensure that the callback is traced (e.g. via a
253 : // Rooted) until the HoldJSObjects call happens.
254 : struct FastCallbackConstructor {
255 : };
256 :
257 : // Just like the public version without the FastCallbackConstructor argument,
258 : // except for not calling HoldJSObjects and not capturing async stacks (on the
259 : // assumption that we will do that last whenever we decide to actually
260 : // HoldJSObjects; see FinishSlowJSInitIfMoreThanOneOwner). If you use this,
261 : // you MUST ensure that the object is traced until the HoldJSObjects happens!
262 213 : CallbackObject(JS::Handle<JSObject*> aCallback,
263 : const FastCallbackConstructor&)
264 213 : {
265 213 : InitNoHold(aCallback, nullptr, nullptr);
266 213 : }
267 :
268 : // mCallback is not unwrapped, so it can be a cross-compartment-wrapper.
269 : // This is done to ensure that, if JS code can't call a callback f(), or get
270 : // its members, directly itself, this code won't call f(), or get its members,
271 : // on the code's behalf.
272 : JS::Heap<JSObject*> mCallback;
273 : JS::Heap<JSObject*> mCreationStack;
274 : // Ideally, we'd just hold a reference to the nsIGlobalObject, since that's
275 : // what we need to pass to AutoIncumbentScript. Unfortunately, that doesn't
276 : // hold the actual JS global alive. So we maintain an additional pointer to
277 : // the JS global itself so that we can trace it.
278 : //
279 : // At some point we should consider trying to make native globals hold their
280 : // scripted global alive, at which point we can get rid of the duplication
281 : // here.
282 : nsCOMPtr<nsIGlobalObject> mIncumbentGlobal;
283 : JS::TenuredHeap<JSObject*> mIncumbentJSGlobal;
284 :
285 : class MOZ_STACK_CLASS CallSetup
286 : {
287 : /**
288 : * A class that performs whatever setup we need to safely make a
289 : * call while this class is on the stack, After the constructor
290 : * returns, the call is safe to make if GetContext() returns
291 : * non-null.
292 : */
293 : public:
294 : // If aExceptionHandling == eRethrowContentExceptions then aCompartment
295 : // needs to be set to the compartment in which exceptions will be rethrown.
296 : //
297 : // If aExceptionHandling == eRethrowExceptions then aCompartment may be set
298 : // to the compartment in which exceptions will be rethrown. In that case
299 : // they will only be rethrown if that compartment's principal subsumes the
300 : // principal of our (unwrapped) callback.
301 : CallSetup(CallbackObject* aCallback, ErrorResult& aRv,
302 : const char* aExecutionReason,
303 : ExceptionHandling aExceptionHandling,
304 : JSCompartment* aCompartment = nullptr,
305 : bool aIsJSImplementedWebIDL = false);
306 : ~CallSetup();
307 :
308 696 : JSContext* GetContext() const
309 : {
310 696 : return mCx;
311 : }
312 :
313 : private:
314 : // We better not get copy-constructed
315 : CallSetup(const CallSetup&) = delete;
316 :
317 : bool ShouldRethrowException(JS::Handle<JS::Value> aException);
318 :
319 : // Members which can go away whenever
320 : JSContext* mCx;
321 :
322 : // Caller's compartment. This will only have a sensible value if
323 : // mExceptionHandling == eRethrowContentExceptions or eRethrowExceptions.
324 : JSCompartment* mCompartment;
325 :
326 : // And now members whose construction/destruction order we need to control.
327 : Maybe<AutoEntryScript> mAutoEntryScript;
328 : Maybe<AutoIncumbentScript> mAutoIncumbentScript;
329 :
330 : Maybe<JS::Rooted<JSObject*> > mRootedCallable;
331 :
332 : // Members which are used to set the async stack.
333 : Maybe<JS::Rooted<JSObject*>> mAsyncStack;
334 : Maybe<JS::AutoSetAsyncStackForNewCalls> mAsyncStackSetter;
335 :
336 : // Can't construct a JSAutoCompartment without a JSContext either. Also,
337 : // Put mAc after mAutoEntryScript so that we exit the compartment before
338 : // we pop the JSContext. Though in practice we'll often manually order
339 : // those two things.
340 : Maybe<JSAutoCompartment> mAc;
341 :
342 : // An ErrorResult to possibly re-throw exceptions on and whether
343 : // we should re-throw them.
344 : ErrorResult& mErrorResult;
345 : const ExceptionHandling mExceptionHandling;
346 : const bool mIsMainThread;
347 : };
348 : };
349 :
350 : template<class WebIDLCallbackT, class XPCOMCallbackT>
351 : class CallbackObjectHolder;
352 :
353 : template<class T, class U>
354 : void ImplCycleCollectionUnlink(CallbackObjectHolder<T, U>& aField);
355 :
356 6691 : class CallbackObjectHolderBase
357 : {
358 : protected:
359 : // Returns null on all failures
360 : already_AddRefed<nsISupports> ToXPCOMCallback(CallbackObject* aCallback,
361 : const nsIID& aIID) const;
362 : };
363 :
364 : template<class WebIDLCallbackT, class XPCOMCallbackT>
365 : class CallbackObjectHolder : CallbackObjectHolderBase
366 : {
367 : /**
368 : * A class which stores either a WebIDLCallbackT* or an XPCOMCallbackT*. Both
369 : * types must inherit from nsISupports. The pointer that's stored can be
370 : * null.
371 : *
372 : * When storing a WebIDLCallbackT*, mPtrBits is set to the pointer value.
373 : * When storing an XPCOMCallbackT*, mPtrBits is the pointer value with low bit
374 : * set.
375 : */
376 : public:
377 192 : explicit CallbackObjectHolder(WebIDLCallbackT* aCallback)
378 192 : : mPtrBits(reinterpret_cast<uintptr_t>(aCallback))
379 : {
380 192 : NS_IF_ADDREF(aCallback);
381 192 : }
382 :
383 2079 : explicit CallbackObjectHolder(XPCOMCallbackT* aCallback)
384 2079 : : mPtrBits(reinterpret_cast<uintptr_t>(aCallback) | XPCOMCallbackFlag)
385 : {
386 2079 : NS_IF_ADDREF(aCallback);
387 2079 : }
388 :
389 2356 : CallbackObjectHolder(CallbackObjectHolder&& aOther)
390 2356 : : mPtrBits(aOther.mPtrBits)
391 : {
392 2356 : aOther.mPtrBits = 0;
393 : static_assert(sizeof(CallbackObjectHolder) == sizeof(void*),
394 : "This object is expected to be as small as a pointer, and it "
395 : "is currently passed by value in various places. If it is "
396 : "bloating, we may want to pass it by reference then.");
397 2356 : }
398 :
399 : CallbackObjectHolder(const CallbackObjectHolder& aOther) = delete;
400 :
401 2064 : CallbackObjectHolder()
402 2064 : : mPtrBits(0)
403 2064 : {}
404 :
405 4970 : ~CallbackObjectHolder()
406 : {
407 4970 : UnlinkSelf();
408 4970 : }
409 :
410 : void operator=(WebIDLCallbackT* aCallback)
411 : {
412 : UnlinkSelf();
413 : mPtrBits = reinterpret_cast<uintptr_t>(aCallback);
414 : NS_IF_ADDREF(aCallback);
415 : }
416 :
417 : void operator=(XPCOMCallbackT* aCallback)
418 : {
419 : UnlinkSelf();
420 : mPtrBits = reinterpret_cast<uintptr_t>(aCallback) | XPCOMCallbackFlag;
421 : NS_IF_ADDREF(aCallback);
422 : }
423 :
424 1918 : void operator=(CallbackObjectHolder&& aOther)
425 : {
426 1918 : UnlinkSelf();
427 1918 : mPtrBits = aOther.mPtrBits;
428 1918 : aOther.mPtrBits = 0;
429 1918 : }
430 :
431 : void operator=(const CallbackObjectHolder& aOther) = delete;
432 :
433 9309 : nsISupports* GetISupports() const
434 : {
435 9309 : return reinterpret_cast<nsISupports*>(mPtrBits & ~XPCOMCallbackFlag);
436 : }
437 :
438 : // Boolean conversion operator so people can use this in boolean tests
439 2275 : explicit operator bool() const
440 : {
441 2275 : return GetISupports();
442 : }
443 :
444 146 : CallbackObjectHolder Clone() const
445 : {
446 146 : CallbackObjectHolder result;
447 146 : result.mPtrBits = mPtrBits;
448 146 : NS_IF_ADDREF(GetISupports());
449 146 : return result;
450 : }
451 :
452 : // Even if HasWebIDLCallback returns true, GetWebIDLCallback() might still
453 : // return null.
454 6865 : bool HasWebIDLCallback() const
455 : {
456 6865 : return !(mPtrBits & XPCOMCallbackFlag);
457 : }
458 :
459 306 : WebIDLCallbackT* GetWebIDLCallback() const
460 : {
461 306 : MOZ_ASSERT(HasWebIDLCallback());
462 306 : return reinterpret_cast<WebIDLCallbackT*>(mPtrBits);
463 : }
464 :
465 2815 : XPCOMCallbackT* GetXPCOMCallback() const
466 : {
467 2815 : MOZ_ASSERT(!HasWebIDLCallback());
468 2815 : return reinterpret_cast<XPCOMCallbackT*>(mPtrBits & ~XPCOMCallbackFlag);
469 : }
470 :
471 97 : bool operator==(WebIDLCallbackT* aOtherCallback) const
472 : {
473 97 : if (!aOtherCallback) {
474 : // If other is null, then we must be null to be equal.
475 0 : return !GetISupports();
476 : }
477 :
478 97 : if (!HasWebIDLCallback() || !GetWebIDLCallback()) {
479 : // If other is non-null, then we can't be equal if we have a
480 : // non-WebIDL callback or a null callback.
481 30 : return false;
482 : }
483 :
484 67 : return *GetWebIDLCallback() == *aOtherCallback;
485 : }
486 :
487 743 : bool operator==(XPCOMCallbackT* aOtherCallback) const
488 : {
489 1823 : return (!aOtherCallback && !GetISupports()) ||
490 2227 : (!HasWebIDLCallback() && GetXPCOMCallback() == aOtherCallback);
491 : }
492 :
493 840 : bool operator==(const CallbackObjectHolder& aOtherCallback) const
494 : {
495 840 : if (aOtherCallback.HasWebIDLCallback()) {
496 97 : return *this == aOtherCallback.GetWebIDLCallback();
497 : }
498 :
499 743 : return *this == aOtherCallback.GetXPCOMCallback();
500 : }
501 :
502 : // Try to return an XPCOMCallbackT version of this object.
503 0 : already_AddRefed<XPCOMCallbackT> ToXPCOMCallback() const
504 : {
505 0 : if (!HasWebIDLCallback()) {
506 0 : RefPtr<XPCOMCallbackT> callback = GetXPCOMCallback();
507 0 : return callback.forget();
508 : }
509 :
510 : nsCOMPtr<nsISupports> supp =
511 0 : CallbackObjectHolderBase::ToXPCOMCallback(GetWebIDLCallback(),
512 0 : NS_GET_TEMPLATE_IID(XPCOMCallbackT));
513 0 : if (supp) {
514 : // ToXPCOMCallback already did the right QI for us.
515 0 : return supp.forget().downcast<XPCOMCallbackT>();
516 : }
517 0 : return nullptr;
518 : }
519 :
520 : // Try to return a WebIDLCallbackT version of this object.
521 0 : already_AddRefed<WebIDLCallbackT> ToWebIDLCallback() const
522 : {
523 0 : if (HasWebIDLCallback()) {
524 0 : RefPtr<WebIDLCallbackT> callback = GetWebIDLCallback();
525 0 : return callback.forget();
526 : }
527 0 : return nullptr;
528 : }
529 :
530 : private:
531 : static const uintptr_t XPCOMCallbackFlag = 1u;
532 :
533 : friend void
534 : ImplCycleCollectionUnlink<WebIDLCallbackT,
535 : XPCOMCallbackT>(CallbackObjectHolder& aField);
536 :
537 6888 : void UnlinkSelf()
538 : {
539 : // NS_IF_RELEASE because we might have been unlinked before
540 6888 : nsISupports* ptr = GetISupports();
541 6888 : NS_IF_RELEASE(ptr);
542 6888 : mPtrBits = 0;
543 6888 : }
544 :
545 : uintptr_t mPtrBits;
546 : };
547 :
548 : NS_DEFINE_STATIC_IID_ACCESSOR(CallbackObject, DOM_CALLBACKOBJECT_IID)
549 :
550 : template<class T, class U>
551 : inline void
552 0 : ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
553 : CallbackObjectHolder<T, U>& aField,
554 : const char* aName,
555 : uint32_t aFlags = 0)
556 : {
557 0 : if (aField) {
558 0 : CycleCollectionNoteChild(aCallback, aField.GetISupports(), aName, aFlags);
559 : }
560 0 : }
561 :
562 : template<class T, class U>
563 : void
564 0 : ImplCycleCollectionUnlink(CallbackObjectHolder<T, U>& aField)
565 : {
566 0 : aField.UnlinkSelf();
567 0 : }
568 :
569 : // T is expected to be a RefPtr or OwningNonNull around a CallbackObject
570 : // subclass. This class is used in bindings to safely handle Fast* callbacks;
571 : // it ensures that the callback is traced, and that if something is holding onto
572 : // the callback when we're done with it HoldJSObjects is called.
573 : template<typename T>
574 : class MOZ_RAII RootedCallback : public JS::Rooted<T>
575 : {
576 : public:
577 213 : explicit RootedCallback(JSContext* cx)
578 : : JS::Rooted<T>(cx)
579 213 : , mCx(cx)
580 213 : {}
581 :
582 : // We need a way to make assignment from pointers (how we're normally used)
583 : // work.
584 : template<typename S>
585 213 : void operator=(S* arg)
586 : {
587 213 : this->get().operator=(arg);
588 213 : }
589 :
590 : // But nullptr can't use the above template, because it doesn't know which S
591 : // to select. So we need a special overload for nullptr.
592 0 : void operator=(decltype(nullptr) arg)
593 : {
594 0 : this->get().operator=(arg);
595 0 : }
596 :
597 : // Codegen relies on being able to do CallbackOrNull() on us.
598 0 : JS::Handle<JSObject*> CallbackOrNull() const
599 : {
600 0 : return this->get()->CallbackOrNull();
601 : }
602 :
603 213 : ~RootedCallback()
604 : {
605 : // Ensure that our callback starts holding on to its own JS objects as
606 : // needed. We really do need to check that things are initialized even when
607 : // T is OwningNonNull, because we might be running before the OwningNonNull
608 : // ever got assigned to!
609 213 : if (IsInitialized(this->get())) {
610 213 : this->get()->FinishSlowJSInitIfMoreThanOneOwner(mCx);
611 : }
612 213 : }
613 :
614 : private:
615 : template<typename U>
616 : static bool IsInitialized(U& aArg); // Not implemented
617 :
618 : template<typename U>
619 194 : static bool IsInitialized(RefPtr<U>& aRefPtr)
620 : {
621 194 : return aRefPtr;
622 : }
623 :
624 : template<typename U>
625 19 : static bool IsInitialized(OwningNonNull<U>& aOwningNonNull)
626 : {
627 19 : return aOwningNonNull.isInitialized();
628 : }
629 :
630 : JSContext* mCx;
631 : };
632 :
633 : } // namespace dom
634 : } // namespace mozilla
635 :
636 : #endif // mozilla_dom_CallbackObject_h
|