1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http:mozilla.org/MPL/2.0/. */
4 
5 #include <type_traits>
6 
7 #include "nsComponentManagerUtils.h"
8 #include "nsIThread.h"
9 #include "nsThreadUtils.h"
10 #include "mozilla/IdleTaskRunner.h"
11 #include "mozilla/RefCounted.h"
12 #include "mozilla/SpinEventLoopUntil.h"
13 #include "mozilla/UniquePtr.h"
14 
15 #include "gtest/gtest.h"
16 
17 using namespace mozilla;
18 
19 enum {
20   TEST_CALL_VOID_ARG_VOID_RETURN,
21   TEST_CALL_VOID_ARG_VOID_RETURN_CONST,
22   TEST_CALL_VOID_ARG_NONVOID_RETURN,
23   TEST_CALL_NONVOID_ARG_VOID_RETURN,
24   TEST_CALL_NONVOID_ARG_NONVOID_RETURN,
25   TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT,
26   TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT,
27 #ifdef HAVE_STDCALL
28   TEST_STDCALL_VOID_ARG_VOID_RETURN,
29   TEST_STDCALL_VOID_ARG_NONVOID_RETURN,
30   TEST_STDCALL_NONVOID_ARG_VOID_RETURN,
31   TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN,
32   TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT,
33 #endif
34   TEST_CALL_NEWTHREAD_SUICIDAL,
35   MAX_TESTS
36 };
37 
38 bool gRunnableExecuted[MAX_TESTS];
39 
40 class nsFoo : public nsISupports {
41   NS_DECL_ISUPPORTS
DoFoo(bool * aBool)42   nsresult DoFoo(bool* aBool) {
43     *aBool = true;
44     return NS_OK;
45   }
46 
47  private:
48   virtual ~nsFoo() = default;
49 };
50 
51 NS_IMPL_ISUPPORTS0(nsFoo)
52 
53 class TestSuicide : public mozilla::Runnable {
54  public:
TestSuicide()55   TestSuicide() : mozilla::Runnable("TestSuicide") {}
Run()56   NS_IMETHOD Run() override {
57     // Runs first time on thread "Suicide", then dies on MainThread
58     if (!NS_IsMainThread()) {
59       mThread = do_GetCurrentThread();
60       NS_DispatchToMainThread(this);
61       return NS_OK;
62     }
63     MOZ_RELEASE_ASSERT(mThread);
64     mThread->Shutdown();
65     gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL] = true;
66     return NS_OK;
67   }
68 
69  private:
70   nsCOMPtr<nsIThread> mThread;
71 };
72 
73 class nsBar : public nsISupports {
74   virtual ~nsBar() = default;
75 
76  public:
77   NS_DECL_ISUPPORTS
DoBar1(void)78   void DoBar1(void) {
79     gRunnableExecuted[TEST_CALL_VOID_ARG_VOID_RETURN] = true;
80   }
DoBar1Const(void) const81   void DoBar1Const(void) const {
82     gRunnableExecuted[TEST_CALL_VOID_ARG_VOID_RETURN_CONST] = true;
83   }
DoBar2(void)84   nsresult DoBar2(void) {
85     gRunnableExecuted[TEST_CALL_VOID_ARG_NONVOID_RETURN] = true;
86     return NS_OK;
87   }
DoBar3(nsFoo * aFoo)88   void DoBar3(nsFoo* aFoo) {
89     aFoo->DoFoo(&gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN]);
90   }
DoBar4(nsFoo * aFoo)91   nsresult DoBar4(nsFoo* aFoo) {
92     return aFoo->DoFoo(
93         &gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN]);
94   }
DoBar5(nsFoo * aFoo)95   void DoBar5(nsFoo* aFoo) {
96     if (aFoo)
97       gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true;
98   }
DoBar6(char * aFoo)99   nsresult DoBar6(char* aFoo) {
100     if (strlen(aFoo))
101       gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT] = true;
102     return NS_OK;
103   }
104 #ifdef HAVE_STDCALL
DoBar1std(void)105   void __stdcall DoBar1std(void) {
106     gRunnableExecuted[TEST_STDCALL_VOID_ARG_VOID_RETURN] = true;
107   }
DoBar2std(void)108   nsresult __stdcall DoBar2std(void) {
109     gRunnableExecuted[TEST_STDCALL_VOID_ARG_NONVOID_RETURN] = true;
110     return NS_OK;
111   }
DoBar3std(nsFoo * aFoo)112   void __stdcall DoBar3std(nsFoo* aFoo) {
113     aFoo->DoFoo(&gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN]);
114   }
DoBar4std(nsFoo * aFoo)115   nsresult __stdcall DoBar4std(nsFoo* aFoo) {
116     return aFoo->DoFoo(
117         &gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN]);
118   }
DoBar5std(nsFoo * aFoo)119   void __stdcall DoBar5std(nsFoo* aFoo) {
120     if (aFoo)
121       gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true;
122   }
DoBar6std(char * aFoo)123   nsresult __stdcall DoBar6std(char* aFoo) {
124     if (strlen(aFoo))
125       gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true;
126     return NS_OK;
127   }
128 #endif
129 };
130 
131 NS_IMPL_ISUPPORTS0(nsBar)
132 
133 struct TestCopyWithNoMove {
TestCopyWithNoMoveTestCopyWithNoMove134   explicit TestCopyWithNoMove(int* aCopyCounter) : mCopyCounter(aCopyCounter) {}
TestCopyWithNoMoveTestCopyWithNoMove135   TestCopyWithNoMove(const TestCopyWithNoMove& a)
136       : mCopyCounter(a.mCopyCounter) {
137     *mCopyCounter += 1;
138   };
139   // No 'move' declaration, allows passing object by rvalue copy.
140   // Destructor nulls member variable...
~TestCopyWithNoMoveTestCopyWithNoMove141   ~TestCopyWithNoMove() { mCopyCounter = nullptr; }
142   // ... so we can check that the object is called when still alive.
operator ()TestCopyWithNoMove143   void operator()() { MOZ_RELEASE_ASSERT(mCopyCounter); }
144   int* mCopyCounter;
145 };
146 struct TestCopyWithDeletedMove {
TestCopyWithDeletedMoveTestCopyWithDeletedMove147   explicit TestCopyWithDeletedMove(int* aCopyCounter)
148       : mCopyCounter(aCopyCounter) {}
TestCopyWithDeletedMoveTestCopyWithDeletedMove149   TestCopyWithDeletedMove(const TestCopyWithDeletedMove& a)
150       : mCopyCounter(a.mCopyCounter) {
151     *mCopyCounter += 1;
152   };
153   // Deleted move prevents passing by rvalue (even if copy would work)
154   TestCopyWithDeletedMove(TestCopyWithDeletedMove&&) = delete;
~TestCopyWithDeletedMoveTestCopyWithDeletedMove155   ~TestCopyWithDeletedMove() { mCopyCounter = nullptr; }
operator ()TestCopyWithDeletedMove156   void operator()() { MOZ_RELEASE_ASSERT(mCopyCounter); }
157   int* mCopyCounter;
158 };
159 struct TestMove {
TestMoveTestMove160   explicit TestMove(int* aMoveCounter) : mMoveCounter(aMoveCounter) {}
161   TestMove(const TestMove&) = delete;
TestMoveTestMove162   TestMove(TestMove&& a) : mMoveCounter(a.mMoveCounter) {
163     a.mMoveCounter = nullptr;
164     *mMoveCounter += 1;
165   }
~TestMoveTestMove166   ~TestMove() { mMoveCounter = nullptr; }
operator ()TestMove167   void operator()() { MOZ_RELEASE_ASSERT(mMoveCounter); }
168   int* mMoveCounter;
169 };
170 struct TestCopyMove {
TestCopyMoveTestCopyMove171   TestCopyMove(int* aCopyCounter, int* aMoveCounter)
172       : mCopyCounter(aCopyCounter), mMoveCounter(aMoveCounter) {}
TestCopyMoveTestCopyMove173   TestCopyMove(const TestCopyMove& a)
174       : mCopyCounter(a.mCopyCounter), mMoveCounter(a.mMoveCounter) {
175     *mCopyCounter += 1;
176   };
TestCopyMoveTestCopyMove177   TestCopyMove(TestCopyMove&& a)
178       : mCopyCounter(a.mCopyCounter), mMoveCounter(a.mMoveCounter) {
179     a.mMoveCounter = nullptr;
180     *mMoveCounter += 1;
181   }
~TestCopyMoveTestCopyMove182   ~TestCopyMove() {
183     mCopyCounter = nullptr;
184     mMoveCounter = nullptr;
185   }
operator ()TestCopyMove186   void operator()() {
187     MOZ_RELEASE_ASSERT(mCopyCounter);
188     MOZ_RELEASE_ASSERT(mMoveCounter);
189   }
190   int* mCopyCounter;
191   int* mMoveCounter;
192 };
193 
194 struct TestRefCounted : RefCounted<TestRefCounted> {
195   MOZ_DECLARE_REFCOUNTED_TYPENAME(TestRefCounted);
196 };
197 
Expect(const char * aContext,int aCounter,int aMaxExpected)198 static void Expect(const char* aContext, int aCounter, int aMaxExpected) {
199   EXPECT_LE(aCounter, aMaxExpected) << aContext;
200 }
201 
ExpectRunnableName(Runnable * aRunnable,const char * aExpectedName)202 static void ExpectRunnableName(Runnable* aRunnable, const char* aExpectedName) {
203 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
204   nsAutoCString name;
205   EXPECT_TRUE(NS_SUCCEEDED(aRunnable->GetName(name))) << "Runnable::GetName()";
206   EXPECT_TRUE(name.EqualsASCII(aExpectedName)) << "Verify Runnable name";
207 #endif
208 }
209 
210 struct BasicRunnableFactory {
211   static constexpr bool SupportsCopyWithDeletedMove = true;
212 
213   template <typename Function>
CreateBasicRunnableFactory214   static auto Create(const char* aName, Function&& aFunc) {
215     return NS_NewRunnableFunction(aName, std::forward<Function>(aFunc));
216   }
217 };
218 
219 struct CancelableRunnableFactory {
220   static constexpr bool SupportsCopyWithDeletedMove = false;
221 
222   template <typename Function>
CreateCancelableRunnableFactory223   static auto Create(const char* aName, Function&& aFunc) {
224     return NS_NewCancelableRunnableFunction(aName,
225                                             std::forward<Function>(aFunc));
226   }
227 };
228 
229 template <typename RunnableFactory>
TestRunnableFactory(bool aNamed)230 static void TestRunnableFactory(bool aNamed) {
231   // Test RunnableFactory with copyable-only function object.
232   {
233     int copyCounter = 0;
234     {
235       nsCOMPtr<nsIRunnable> trackedRunnable;
236       {
237         TestCopyWithNoMove tracker(&copyCounter);
238         trackedRunnable = aNamed ? RunnableFactory::Create("unused", tracker)
239                                  : RunnableFactory::Create(
240                                        "TestNewRunnableFunction", tracker);
241         // Original 'tracker' is destroyed here.
242       }
243       // Verify that the runnable contains a non-destroyed function object.
244       trackedRunnable->Run();
245     }
246     Expect(
247         "RunnableFactory with copyable-only (and no move) function, "
248         "copies",
249         copyCounter, 1);
250   }
251   {
252     int copyCounter = 0;
253     {
254       nsCOMPtr<nsIRunnable> trackedRunnable;
255       {
256         // Passing as rvalue, but using copy.
257         // (TestCopyWithDeletedMove wouldn't allow this.)
258         trackedRunnable =
259             aNamed ? RunnableFactory::Create("unused",
260                                              TestCopyWithNoMove(&copyCounter))
261                    : RunnableFactory::Create("TestNewRunnableFunction",
262                                              TestCopyWithNoMove(&copyCounter));
263       }
264       trackedRunnable->Run();
265     }
266     Expect(
267         "RunnableFactory with copyable-only (and no move) function "
268         "rvalue, copies",
269         copyCounter, 1);
270   }
271   if constexpr (RunnableFactory::SupportsCopyWithDeletedMove) {
272     int copyCounter = 0;
273     {
274       nsCOMPtr<nsIRunnable> trackedRunnable;
275       {
276         TestCopyWithDeletedMove tracker(&copyCounter);
277         trackedRunnable = aNamed ? RunnableFactory::Create("unused", tracker)
278                                  : RunnableFactory::Create(
279                                        "TestNewRunnableFunction", tracker);
280       }
281       trackedRunnable->Run();
282     }
283     Expect(
284         "RunnableFactory with copyable-only (and deleted move) "
285         "function, copies",
286         copyCounter, 1);
287   }
288 
289   // Test RunnableFactory with movable-only function object.
290   {
291     int moveCounter = 0;
292     {
293       nsCOMPtr<nsIRunnable> trackedRunnable;
294       {
295         TestMove tracker(&moveCounter);
296         trackedRunnable =
297             aNamed ? RunnableFactory::Create("unused", std::move(tracker))
298                    : RunnableFactory::Create("TestNewRunnableFunction",
299                                              std::move(tracker));
300       }
301       trackedRunnable->Run();
302     }
303     Expect("RunnableFactory with movable-only function, moves", moveCounter, 1);
304   }
305   {
306     int moveCounter = 0;
307     {
308       nsCOMPtr<nsIRunnable> trackedRunnable;
309       {
310         trackedRunnable =
311             aNamed ? RunnableFactory::Create("unused", TestMove(&moveCounter))
312                    : RunnableFactory::Create("TestNewRunnableFunction",
313                                              TestMove(&moveCounter));
314       }
315       trackedRunnable->Run();
316     }
317     Expect("RunnableFactory with movable-only function rvalue, moves",
318            moveCounter, 1);
319   }
320 
321   // Test RunnableFactory with copyable&movable function object.
322   {
323     int copyCounter = 0;
324     int moveCounter = 0;
325     {
326       nsCOMPtr<nsIRunnable> trackedRunnable;
327       {
328         TestCopyMove tracker(&copyCounter, &moveCounter);
329         trackedRunnable =
330             aNamed ? RunnableFactory::Create("unused", std::move(tracker))
331                    : RunnableFactory::Create("TestNewRunnableFunction",
332                                              std::move(tracker));
333       }
334       trackedRunnable->Run();
335     }
336     Expect("RunnableFactory with copyable&movable function, copies",
337            copyCounter, 0);
338     Expect("RunnableFactory with copyable&movable function, moves", moveCounter,
339            1);
340   }
341   {
342     int copyCounter = 0;
343     int moveCounter = 0;
344     {
345       nsCOMPtr<nsIRunnable> trackedRunnable;
346       {
347         trackedRunnable =
348             aNamed ? RunnableFactory::Create(
349                          "unused", TestCopyMove(&copyCounter, &moveCounter))
350                    : RunnableFactory::Create(
351                          "TestNewRunnableFunction",
352                          TestCopyMove(&copyCounter, &moveCounter));
353       }
354       trackedRunnable->Run();
355     }
356     Expect("RunnableFactory with copyable&movable function rvalue, copies",
357            copyCounter, 0);
358     Expect("RunnableFactory with copyable&movable function rvalue, moves",
359            moveCounter, 1);
360   }
361 
362   // Test RunnableFactory with copyable-only lambda capture.
363   {
364     int copyCounter = 0;
365     {
366       nsCOMPtr<nsIRunnable> trackedRunnable;
367       {
368         TestCopyWithNoMove tracker(&copyCounter);
369         // Expect 2 copies (here -> local lambda -> runnable lambda).
370         trackedRunnable =
371             aNamed
372                 ? RunnableFactory::Create("unused",
373                                           [tracker]() mutable { tracker(); })
374                 : RunnableFactory::Create("TestNewRunnableFunction",
375                                           [tracker]() mutable { tracker(); });
376       }
377       trackedRunnable->Run();
378     }
379     Expect(
380         "RunnableFactory with copyable-only (and no move) capture, "
381         "copies",
382         copyCounter, 2);
383   }
384   {
385     int copyCounter = 0;
386     {
387       nsCOMPtr<nsIRunnable> trackedRunnable;
388       {
389         TestCopyWithDeletedMove tracker(&copyCounter);
390         // Expect 2 copies (here -> local lambda -> runnable lambda).
391         trackedRunnable =
392             aNamed
393                 ? RunnableFactory::Create("unused",
394                                           [tracker]() mutable { tracker(); })
395                 : RunnableFactory::Create("TestNewRunnableFunction",
396                                           [tracker]() mutable { tracker(); });
397       }
398       trackedRunnable->Run();
399     }
400     Expect(
401         "RunnableFactory with copyable-only (and deleted move) capture, "
402         "copies",
403         copyCounter, 2);
404   }
405 
406   // Note: Not possible to use move-only captures.
407   // (Until we can use C++14 generalized lambda captures)
408 
409   // Test RunnableFactory with copyable&movable lambda capture.
410   {
411     int copyCounter = 0;
412     int moveCounter = 0;
413     {
414       nsCOMPtr<nsIRunnable> trackedRunnable;
415       {
416         TestCopyMove tracker(&copyCounter, &moveCounter);
417         trackedRunnable =
418             aNamed
419                 ? RunnableFactory::Create("unused",
420                                           [tracker]() mutable { tracker(); })
421                 : RunnableFactory::Create("TestNewRunnableFunction",
422                                           [tracker]() mutable { tracker(); });
423         // Expect 1 copy (here -> local lambda) and 1 move (local -> runnable
424         // lambda).
425       }
426       trackedRunnable->Run();
427     }
428     Expect("RunnableFactory with copyable&movable capture, copies", copyCounter,
429            1);
430     Expect("RunnableFactory with copyable&movable capture, moves", moveCounter,
431            1);
432   }
433 }
434 
TEST(ThreadUtils,NewRunnableFunction)435 TEST(ThreadUtils, NewRunnableFunction)
436 { TestRunnableFactory<BasicRunnableFactory>(/*aNamed*/ false); }
437 
TEST(ThreadUtils,NewNamedRunnableFunction)438 TEST(ThreadUtils, NewNamedRunnableFunction)
439 {
440   // The named overload shall behave identical to the non-named counterpart.
441   TestRunnableFactory<BasicRunnableFactory>(/*aNamed*/ true);
442 
443   // Test naming.
444   {
445     const char* expectedName = "NamedRunnable";
446     RefPtr<Runnable> NamedRunnable =
447         NS_NewRunnableFunction(expectedName, [] {});
448     ExpectRunnableName(NamedRunnable, expectedName);
449   }
450 }
451 
TEST(ThreadUtils,NewCancelableRunnableFunction)452 TEST(ThreadUtils, NewCancelableRunnableFunction)
453 { TestRunnableFactory<CancelableRunnableFactory>(/*aNamed*/ false); }
454 
TEST(ThreadUtils,NewNamedCancelableRunnableFunction)455 TEST(ThreadUtils, NewNamedCancelableRunnableFunction)
456 {
457   // The named overload shall behave identical to the non-named counterpart.
458   TestRunnableFactory<CancelableRunnableFactory>(/*aNamed*/ true);
459 
460   // Test naming.
461   {
462     const char* expectedName = "NamedRunnable";
463     RefPtr<Runnable> NamedRunnable =
464         NS_NewCancelableRunnableFunction(expectedName, [] {});
465     ExpectRunnableName(NamedRunnable, expectedName);
466   }
467 
468   // Test release on cancelation.
469   {
470     auto foo = MakeRefPtr<TestRefCounted>();
471     bool ran = false;
472 
473     RefPtr<CancelableRunnable> func =
474         NS_NewCancelableRunnableFunction("unused", [foo, &ran] { ran = true; });
475 
476     EXPECT_EQ(foo->refCount(), 2u);
477     func->Cancel();
478 
479     EXPECT_EQ(foo->refCount(), 1u);
480     EXPECT_FALSE(ran);
481   }
482 
483   // Test no-op after cancelation.
484   {
485     auto foo = MakeRefPtr<TestRefCounted>();
486     bool ran = false;
487 
488     RefPtr<CancelableRunnable> func =
489         NS_NewCancelableRunnableFunction("unused", [foo, &ran] { ran = true; });
490 
491     EXPECT_EQ(foo->refCount(), 2u);
492     func->Cancel();
493     func->Run();
494 
495     EXPECT_FALSE(ran);
496   }
497 }
498 
TestNewRunnableMethod(bool aNamed)499 static void TestNewRunnableMethod(bool aNamed) {
500   memset(gRunnableExecuted, false, MAX_TESTS * sizeof(bool));
501   // Scope the smart ptrs so that the runnables need to hold on to whatever they
502   // need
503   {
504     RefPtr<nsFoo> foo = new nsFoo();
505     RefPtr<nsBar> bar = new nsBar();
506     RefPtr<const nsBar> constBar = bar;
507 
508     // This pointer will be freed at the end of the block
509     // Do not dereference this pointer in the runnable method!
510     RefPtr<nsFoo> rawFoo = new nsFoo();
511 
512     // Read only string. Dereferencing in runnable method to check this works.
513     char* message = (char*)"Test message";
514 
515     {
516       auto bar = MakeRefPtr<nsBar>();
517 
518       NS_DispatchToMainThread(
519           aNamed ? NewRunnableMethod("unused", std::move(bar), &nsBar::DoBar1)
520                  : NewRunnableMethod("nsBar::DoBar1", std::move(bar),
521                                      &nsBar::DoBar1));
522     }
523 
524     NS_DispatchToMainThread(
525         aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar1)
526                : NewRunnableMethod("nsBar::DoBar1", bar, &nsBar::DoBar1));
527     NS_DispatchToMainThread(
528         aNamed ? NewRunnableMethod("unused", constBar, &nsBar::DoBar1Const)
529                : NewRunnableMethod("nsBar::DoBar1Const", constBar,
530                                    &nsBar::DoBar1Const));
531     NS_DispatchToMainThread(
532         aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar2)
533                : NewRunnableMethod("nsBar::DoBar2", bar, &nsBar::DoBar2));
534     NS_DispatchToMainThread(
535         aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar, &nsBar::DoBar3,
536                                                   foo)
537                : NewRunnableMethod<RefPtr<nsFoo>>("nsBar::DoBar3", bar,
538                                                   &nsBar::DoBar3, foo));
539     NS_DispatchToMainThread(
540         aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar, &nsBar::DoBar4,
541                                                   foo)
542                : NewRunnableMethod<RefPtr<nsFoo>>("nsBar::DoBar4", bar,
543                                                   &nsBar::DoBar4, foo));
544     NS_DispatchToMainThread(
545         aNamed
546             ? NewRunnableMethod<nsFoo*>("unused", bar, &nsBar::DoBar5, rawFoo)
547             : NewRunnableMethod<nsFoo*>("nsBar::DoBar5", bar, &nsBar::DoBar5,
548                                         rawFoo));
549     NS_DispatchToMainThread(
550         aNamed
551             ? NewRunnableMethod<char*>("unused", bar, &nsBar::DoBar6, message)
552             : NewRunnableMethod<char*>("nsBar::DoBar6", bar, &nsBar::DoBar6,
553                                        message));
554 #ifdef HAVE_STDCALL
555     NS_DispatchToMainThread(
556         aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar1std)
557                : NewRunnableMethod(bar, &nsBar::DoBar1std));
558     NS_DispatchToMainThread(
559         aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar2std)
560                : NewRunnableMethod(bar, &nsBar::DoBar2std));
561     NS_DispatchToMainThread(
562         aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar,
563                                                   &nsBar::DoBar3std, foo)
564                : NewRunnableMethod<RefPtr<nsFoo>>(bar, &nsBar::DoBar3std, foo));
565     NS_DispatchToMainThread(
566         aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar,
567                                                   &nsBar::DoBar4std, foo)
568                : NewRunnableMethod<RefPtr<nsFoo>>(bar, &nsBar::DoBar4std, foo));
569     NS_DispatchToMainThread(
570         aNamed ? NewRunnableMethod<nsFoo*>("unused", bar, &nsBar::DoBar5std,
571                                            rawFoo)
572                : NewRunnableMethod<nsFoo*>(bar, &nsBar::DoBar5std, rawFoo));
573     NS_DispatchToMainThread(
574         aNamed ? NewRunnableMethod<char*>("unused", bar, &nsBar::DoBar6std,
575                                           message)
576                : NewRunnableMethod<char*>(bar, &nsBar::DoBar6std, message));
577 #endif
578   }
579 
580   // Spin the event loop
581   NS_ProcessPendingEvents(nullptr);
582 
583   // Now test a suicidal event in NS_New(Named)Thread
584   nsCOMPtr<nsIThread> thread;
585   NS_NewNamedThread("SuicideThread", getter_AddRefs(thread), new TestSuicide());
586   ASSERT_TRUE(thread);
587 
588   while (!gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL]) {
589     NS_ProcessPendingEvents(nullptr);
590   }
591 
592   for (uint32_t i = 0; i < MAX_TESTS; i++) {
593     EXPECT_TRUE(gRunnableExecuted[i]) << "Error in test " << i;
594   }
595 }
596 
TEST(ThreadUtils,RunnableMethod)597 TEST(ThreadUtils, RunnableMethod)
598 { TestNewRunnableMethod(/* aNamed */ false); }
599 
TEST(ThreadUtils,NamedRunnableMethod)600 TEST(ThreadUtils, NamedRunnableMethod)
601 {
602   // The named overloads shall behave identical to the non-named counterparts.
603   TestNewRunnableMethod(/* aNamed */ true);
604 
605   // Test naming.
606   {
607     RefPtr<nsFoo> foo = new nsFoo();
608     const char* expectedName = "NamedRunnable";
609     bool unused;
610     RefPtr<Runnable> NamedRunnable =
611         NewRunnableMethod<bool*>(expectedName, foo, &nsFoo::DoFoo, &unused);
612     ExpectRunnableName(NamedRunnable, expectedName);
613   }
614 }
615 
616 class IdleObjectWithoutSetDeadline final {
617  public:
618   NS_INLINE_DECL_REFCOUNTING(IdleObjectWithoutSetDeadline)
IdleObjectWithoutSetDeadline()619   IdleObjectWithoutSetDeadline() : mRunnableExecuted(false) {}
Method()620   void Method() { mRunnableExecuted = true; }
621   bool mRunnableExecuted;
622 
623  private:
624   ~IdleObjectWithoutSetDeadline() = default;
625 };
626 
627 class IdleObjectParentWithSetDeadline {
628  public:
IdleObjectParentWithSetDeadline()629   IdleObjectParentWithSetDeadline() : mSetDeadlineCalled(false) {}
SetDeadline(TimeStamp aDeadline)630   void SetDeadline(TimeStamp aDeadline) { mSetDeadlineCalled = true; }
631   bool mSetDeadlineCalled;
632 };
633 
634 class IdleObjectInheritedSetDeadline final
635     : public IdleObjectParentWithSetDeadline {
636  public:
637   NS_INLINE_DECL_REFCOUNTING(IdleObjectInheritedSetDeadline)
IdleObjectInheritedSetDeadline()638   IdleObjectInheritedSetDeadline() : mRunnableExecuted(false) {}
Method()639   void Method() { mRunnableExecuted = true; }
640   bool mRunnableExecuted;
641 
642  private:
643   ~IdleObjectInheritedSetDeadline() = default;
644 };
645 
646 class IdleObject final {
647  public:
648   NS_INLINE_DECL_REFCOUNTING(IdleObject)
IdleObject()649   IdleObject() {
650     for (uint32_t index = 0; index < ArrayLength(mRunnableExecuted); ++index) {
651       mRunnableExecuted[index] = false;
652       mSetIdleDeadlineCalled = false;
653     }
654   }
SetDeadline(TimeStamp aTimeStamp)655   void SetDeadline(TimeStamp aTimeStamp) { mSetIdleDeadlineCalled = true; }
656 
CheckExecutedMethods(const char * aKey,uint32_t aNumExecuted)657   void CheckExecutedMethods(const char* aKey, uint32_t aNumExecuted) {
658     uint32_t index;
659     for (index = 0; index < aNumExecuted; ++index) {
660       ASSERT_TRUE(mRunnableExecuted[index])
661       << aKey << ": Method" << index << " should've executed";
662     }
663 
664     for (; index < ArrayLength(mRunnableExecuted); ++index) {
665       ASSERT_FALSE(mRunnableExecuted[index])
666       << aKey << ": Method" << index << " shouldn't have executed";
667     }
668   }
669 
Method0()670   void Method0() {
671     CheckExecutedMethods("Method0", 0);
672     mRunnableExecuted[0] = true;
673     mSetIdleDeadlineCalled = false;
674   }
675 
Method1()676   void Method1() {
677     CheckExecutedMethods("Method1", 1);
678     ASSERT_TRUE(mSetIdleDeadlineCalled);
679     mRunnableExecuted[1] = true;
680     mSetIdleDeadlineCalled = false;
681   }
682 
Method2()683   void Method2() {
684     CheckExecutedMethods("Method2", 2);
685     ASSERT_TRUE(mSetIdleDeadlineCalled);
686     mRunnableExecuted[2] = true;
687     mSetIdleDeadlineCalled = false;
688     NS_DispatchToCurrentThread(
689         NewRunnableMethod("IdleObject::Method3", this, &IdleObject::Method3));
690   }
691 
Method3()692   void Method3() {
693     CheckExecutedMethods("Method3", 3);
694 
695     NS_NewTimerWithFuncCallback(getter_AddRefs(mTimer), Method4, this, 10,
696                                 nsITimer::TYPE_ONE_SHOT, "IdleObject::Method3");
697     NS_DispatchToCurrentThreadQueue(
698         NewIdleRunnableMethodWithTimer("IdleObject::Method5", this,
699                                        &IdleObject::Method5),
700         50, EventQueuePriority::Idle);
701     NS_DispatchToCurrentThreadQueue(
702         NewRunnableMethod("IdleObject::Method6", this, &IdleObject::Method6),
703         100, EventQueuePriority::Idle);
704 
705     PR_Sleep(PR_MillisecondsToInterval(200));
706     mRunnableExecuted[3] = true;
707     mSetIdleDeadlineCalled = false;
708   }
709 
Method4(nsITimer * aTimer,void * aClosure)710   static void Method4(nsITimer* aTimer, void* aClosure) {
711     RefPtr<IdleObject> self = static_cast<IdleObject*>(aClosure);
712     self->CheckExecutedMethods("Method4", 4);
713     self->mRunnableExecuted[4] = true;
714     self->mSetIdleDeadlineCalled = false;
715   }
716 
Method5()717   void Method5() {
718     CheckExecutedMethods("Method5", 5);
719     ASSERT_TRUE(mSetIdleDeadlineCalled);
720     mRunnableExecuted[5] = true;
721     mSetIdleDeadlineCalled = false;
722   }
723 
Method6()724   void Method6() {
725     CheckExecutedMethods("Method6", 6);
726     mRunnableExecuted[6] = true;
727     mSetIdleDeadlineCalled = false;
728   }
729 
Method7()730   void Method7() {
731     CheckExecutedMethods("Method7", 7);
732     ASSERT_TRUE(mSetIdleDeadlineCalled);
733     mRunnableExecuted[7] = true;
734     mSetIdleDeadlineCalled = false;
735   }
736 
737  private:
738   nsCOMPtr<nsITimer> mTimer;
739   bool mRunnableExecuted[8];
740   bool mSetIdleDeadlineCalled;
741   ~IdleObject() = default;
742 };
743 
744 // Disable test due to frequent failures
745 #if 0
746 // because test fails on multiple platforms
747 TEST(ThreadUtils, IdleRunnableMethod)
748 {
749   {
750     RefPtr<IdleObject> idle = new IdleObject();
751     RefPtr<IdleObjectWithoutSetDeadline> idleNoSetDeadline =
752         new IdleObjectWithoutSetDeadline();
753     RefPtr<IdleObjectInheritedSetDeadline> idleInheritedSetDeadline =
754         new IdleObjectInheritedSetDeadline();
755 
756     NS_DispatchToCurrentThread(
757         NewRunnableMethod("IdleObject::Method0", idle, &IdleObject::Method0));
758     NS_DispatchToCurrentThreadQueue(
759         NewIdleRunnableMethod("IdleObject::Method1", idle,
760                               &IdleObject::Method1),
761         EventQueuePriority::Idle);
762     NS_DispatchToCurrentThreadQueue(
763         NewIdleRunnableMethodWithTimer("IdleObject::Method2", idle,
764                                        &IdleObject::Method2),
765         60000, EventQueuePriority::Idle);
766     NS_DispatchToCurrentThreadQueue(
767         NewIdleRunnableMethod("IdleObject::Method7", idle,
768                               &IdleObject::Method7),
769         EventQueuePriority::Idle);
770     NS_DispatchToCurrentThreadQueue(
771         NewIdleRunnableMethod<const char*, uint32_t>(
772             "IdleObject::CheckExecutedMethods", idle,
773             &IdleObject::CheckExecutedMethods, "final", 8),
774         EventQueuePriority::Idle);
775     NS_DispatchToCurrentThreadQueue(
776         NewIdleRunnableMethod("IdleObjectWithoutSetDeadline::Method",
777                               idleNoSetDeadline,
778                               &IdleObjectWithoutSetDeadline::Method),
779         EventQueuePriority::Idle);
780     NS_DispatchToCurrentThreadQueue(
781         NewIdleRunnableMethod("IdleObjectInheritedSetDeadline::Method",
782                               idleInheritedSetDeadline,
783                               &IdleObjectInheritedSetDeadline::Method),
784         EventQueuePriority::Idle);
785 
786     NS_ProcessPendingEvents(nullptr);
787 
788     ASSERT_TRUE(idleNoSetDeadline->mRunnableExecuted);
789     ASSERT_TRUE(idleInheritedSetDeadline->mRunnableExecuted);
790     ASSERT_TRUE(idleInheritedSetDeadline->mSetDeadlineCalled);
791   }
792 }
793 #endif
794 
TEST(ThreadUtils,IdleTaskRunner)795 TEST(ThreadUtils, IdleTaskRunner)
796 {
797   using namespace mozilla;
798 
799   // Repeating.
800   int cnt1 = 0;
801   RefPtr<IdleTaskRunner> runner1 = IdleTaskRunner::Create(
802       [&cnt1](TimeStamp) {
803         cnt1++;
804         return true;
805       },
806       "runner1", 0, TimeDuration::FromMilliseconds(10),
807       TimeDuration::FromMilliseconds(3), true, nullptr);
808 
809   // Non-repeating but callback always return false so it's still repeating.
810   int cnt2 = 0;
811   RefPtr<IdleTaskRunner> runner2 = IdleTaskRunner::Create(
812       [&cnt2](TimeStamp) {
813         cnt2++;
814         return false;
815       },
816       "runner2", 0, TimeDuration::FromMilliseconds(10),
817       TimeDuration::FromMilliseconds(3), false, nullptr);
818 
819   // Repeating until cnt3 >= 2 by returning 'true' in MayStopProcessing
820   // callback. The strategy is to stop repeating as early as possible so that we
821   // are more probable to catch the bug if it didn't stop as expected.
822   int cnt3 = 0;
823   RefPtr<IdleTaskRunner> runner3 = IdleTaskRunner::Create(
824       [&cnt3](TimeStamp) {
825         cnt3++;
826         return true;
827       },
828       "runner3", 0, TimeDuration::FromMilliseconds(10),
829       TimeDuration::FromMilliseconds(3), true, [&cnt3] { return cnt3 >= 2; });
830 
831   // Non-repeating can callback return true so the callback will
832   // be only run once.
833   int cnt4 = 0;
834   RefPtr<IdleTaskRunner> runner4 = IdleTaskRunner::Create(
835       [&cnt4](TimeStamp) {
836         cnt4++;
837         return true;
838       },
839       "runner4", 0, TimeDuration::FromMilliseconds(10),
840       TimeDuration::FromMilliseconds(3), false, nullptr);
841 
842   // Firstly we wait until the two repeating tasks reach their limits.
843   MOZ_ALWAYS_TRUE(
844       SpinEventLoopUntil("xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt1"_ns,
845                          [&]() { return cnt1 >= 100; }));
846   MOZ_ALWAYS_TRUE(
847       SpinEventLoopUntil("xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt2"_ns,
848                          [&]() { return cnt2 >= 100; }));
849 
850   // At any point ==> 0 <= cnt3 <= 2 since MayStopProcessing() would return
851   // true when cnt3 >= 2.
852   MOZ_ALWAYS_TRUE(SpinEventLoopUntil(
853       "xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt3"_ns, [&]() {
854         if (cnt3 > 2) {
855           EXPECT_TRUE(false) << "MaybeContinueProcess() doesn't work.";
856           return true;  // Stop on failure.
857         }
858         return cnt3 == 2;  // Stop finish if we have reached its max value.
859       }));
860 
861   // At any point ==> 0 <= cnt4 <= 1 since this is a non-repeating
862   // idle runner.
863   MOZ_ALWAYS_TRUE(SpinEventLoopUntil(
864       "xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt4"_ns, [&]() {
865         // At any point: 0 <= cnt4 <= 1
866         if (cnt4 > 1) {
867           EXPECT_TRUE(false) << "The 'mRepeating' flag doesn't work.";
868           return true;  // Stop on failure.
869         }
870         return cnt4 == 1;
871       }));
872 
873   // The repeating timers require an explicit Cancel() call.
874   runner1->Cancel();
875   runner2->Cancel();
876 }
877 
878 // {9e70a320-be02-11d1-8031-006008159b5a}
879 #define NS_IFOO_IID                                  \
880   {                                                  \
881     0x9e70a320, 0xbe02, 0x11d1, {                    \
882       0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a \
883     }                                                \
884   }
885 
TEST(ThreadUtils,TypeTraits)886 TEST(ThreadUtils, TypeTraits)
887 {
888   static_assert(!mozilla::IsRefcountedSmartPointer<int>::value,
889                 "IsRefcountedSmartPointer<int> should be false");
890   static_assert(mozilla::IsRefcountedSmartPointer<RefPtr<int>>::value,
891                 "IsRefcountedSmartPointer<RefPtr<...>> should be true");
892   static_assert(mozilla::IsRefcountedSmartPointer<const RefPtr<int>>::value,
893                 "IsRefcountedSmartPointer<const RefPtr<...>> should be true");
894   static_assert(
895       mozilla::IsRefcountedSmartPointer<volatile RefPtr<int>>::value,
896       "IsRefcountedSmartPointer<volatile RefPtr<...>> should be true");
897   static_assert(
898       mozilla::IsRefcountedSmartPointer<const volatile RefPtr<int>>::value,
899       "IsRefcountedSmartPointer<const volatile RefPtr<...>> should be true");
900   static_assert(mozilla::IsRefcountedSmartPointer<nsCOMPtr<int>>::value,
901                 "IsRefcountedSmartPointer<nsCOMPtr<...>> should be true");
902   static_assert(mozilla::IsRefcountedSmartPointer<const nsCOMPtr<int>>::value,
903                 "IsRefcountedSmartPointer<const nsCOMPtr<...>> should be true");
904   static_assert(
905       mozilla::IsRefcountedSmartPointer<volatile nsCOMPtr<int>>::value,
906       "IsRefcountedSmartPointer<volatile nsCOMPtr<...>> should be true");
907   static_assert(
908       mozilla::IsRefcountedSmartPointer<const volatile nsCOMPtr<int>>::value,
909       "IsRefcountedSmartPointer<const volatile nsCOMPtr<...>> should be true");
910 
911   static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<int>::Type>,
912                 "RemoveSmartPointer<int>::Type should be int");
913   static_assert(std::is_same_v<int*, mozilla::RemoveSmartPointer<int*>::Type>,
914                 "RemoveSmartPointer<int*>::Type should be int*");
915   static_assert(
916       std::is_same_v<UniquePtr<int>,
917                      mozilla::RemoveSmartPointer<UniquePtr<int>>::Type>,
918       "RemoveSmartPointer<UniquePtr<int>>::Type should be UniquePtr<int>");
919   static_assert(
920       std::is_same_v<int, mozilla::RemoveSmartPointer<RefPtr<int>>::Type>,
921       "RemoveSmartPointer<RefPtr<int>>::Type should be int");
922   static_assert(
923       std::is_same_v<int, mozilla::RemoveSmartPointer<const RefPtr<int>>::Type>,
924       "RemoveSmartPointer<const RefPtr<int>>::Type should be int");
925   static_assert(
926       std::is_same_v<int,
927                      mozilla::RemoveSmartPointer<volatile RefPtr<int>>::Type>,
928       "RemoveSmartPointer<volatile RefPtr<int>>::Type should be int");
929   static_assert(
930       std::is_same_v<
931           int, mozilla::RemoveSmartPointer<const volatile RefPtr<int>>::Type>,
932       "RemoveSmartPointer<const volatile RefPtr<int>>::Type should be int");
933   static_assert(
934       std::is_same_v<int, mozilla::RemoveSmartPointer<nsCOMPtr<int>>::Type>,
935       "RemoveSmartPointer<nsCOMPtr<int>>::Type should be int");
936   static_assert(
937       std::is_same_v<int,
938                      mozilla::RemoveSmartPointer<const nsCOMPtr<int>>::Type>,
939       "RemoveSmartPointer<const nsCOMPtr<int>>::Type should be int");
940   static_assert(
941       std::is_same_v<int,
942                      mozilla::RemoveSmartPointer<volatile nsCOMPtr<int>>::Type>,
943       "RemoveSmartPointer<volatile nsCOMPtr<int>>::Type should be int");
944   static_assert(
945       std::is_same_v<
946           int, mozilla::RemoveSmartPointer<const volatile nsCOMPtr<int>>::Type>,
947       "RemoveSmartPointer<const volatile nsCOMPtr<int>>::Type should be int");
948 
949   static_assert(
950       std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int>::Type>,
951       "RemoveRawOrSmartPointer<int>::Type should be int");
952   static_assert(
953       std::is_same_v<UniquePtr<int>,
954                      mozilla::RemoveRawOrSmartPointer<UniquePtr<int>>::Type>,
955       "RemoveRawOrSmartPointer<UniquePtr<int>>::Type should be UniquePtr<int>");
956   static_assert(
957       std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int*>::Type>,
958       "RemoveRawOrSmartPointer<int*>::Type should be int");
959   static_assert(
960       std::is_same_v<const int,
961                      mozilla::RemoveRawOrSmartPointer<const int*>::Type>,
962       "RemoveRawOrSmartPointer<const int*>::Type should be const int");
963   static_assert(
964       std::is_same_v<volatile int,
965                      mozilla::RemoveRawOrSmartPointer<volatile int*>::Type>,
966       "RemoveRawOrSmartPointer<volatile int*>::Type should be volatile int");
967   static_assert(
968       std::is_same_v<const volatile int, mozilla::RemoveRawOrSmartPointer<
969                                              const volatile int*>::Type>,
970       "RemoveRawOrSmartPointer<const volatile int*>::Type should be const "
971       "volatile int");
972   static_assert(
973       std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<RefPtr<int>>::Type>,
974       "RemoveRawOrSmartPointer<RefPtr<int>>::Type should be int");
975   static_assert(
976       std::is_same_v<int,
977                      mozilla::RemoveRawOrSmartPointer<const RefPtr<int>>::Type>,
978       "RemoveRawOrSmartPointer<const RefPtr<int>>::Type should be int");
979   static_assert(
980       std::is_same_v<
981           int, mozilla::RemoveRawOrSmartPointer<volatile RefPtr<int>>::Type>,
982       "RemoveRawOrSmartPointer<volatile RefPtr<int>>::Type should be int");
983   static_assert(
984       std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<
985                               const volatile RefPtr<int>>::Type>,
986       "RemoveRawOrSmartPointer<const volatile RefPtr<int>>::Type should be "
987       "int");
988   static_assert(
989       std::is_same_v<int,
990                      mozilla::RemoveRawOrSmartPointer<nsCOMPtr<int>>::Type>,
991       "RemoveRawOrSmartPointer<nsCOMPtr<int>>::Type should be int");
992   static_assert(
993       std::is_same_v<
994           int, mozilla::RemoveRawOrSmartPointer<const nsCOMPtr<int>>::Type>,
995       "RemoveRawOrSmartPointer<const nsCOMPtr<int>>::Type should be int");
996   static_assert(
997       std::is_same_v<
998           int, mozilla::RemoveRawOrSmartPointer<volatile nsCOMPtr<int>>::Type>,
999       "RemoveRawOrSmartPointer<volatile nsCOMPtr<int>>::Type should be int");
1000   static_assert(
1001       std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<
1002                               const volatile nsCOMPtr<int>>::Type>,
1003       "RemoveRawOrSmartPointer<const volatile nsCOMPtr<int>>::Type should be "
1004       "int");
1005 }
1006 
1007 namespace TestThreadUtils {
1008 
1009 static bool gDebug = false;
1010 static int gAlive, gZombies;
1011 static int gAllConstructions, gConstructions, gCopyConstructions,
1012     gMoveConstructions, gDestructions, gAssignments, gMoves;
1013 struct Spy {
ClearActionsTestThreadUtils::Spy1014   static void ClearActions() {
1015     gAllConstructions = gConstructions = gCopyConstructions =
1016         gMoveConstructions = gDestructions = gAssignments = gMoves = 0;
1017   }
ClearAllTestThreadUtils::Spy1018   static void ClearAll() {
1019     ClearActions();
1020     gAlive = 0;
1021   }
1022 
SpyTestThreadUtils::Spy1023   explicit Spy(int aID) : mID(aID) {
1024     ++gAlive;
1025     ++gAllConstructions;
1026     ++gConstructions;
1027     if (gDebug) {
1028       printf("Spy[%d@%p]()\n", mID, this);
1029     }
1030   }
SpyTestThreadUtils::Spy1031   Spy(const Spy& o) : mID(o.mID) {
1032     ++gAlive;
1033     ++gAllConstructions;
1034     ++gCopyConstructions;
1035     if (gDebug) {
1036       printf("Spy[%d@%p](&[%d@%p])\n", mID, this, o.mID, &o);
1037     }
1038   }
SpyTestThreadUtils::Spy1039   Spy(Spy&& o) : mID(o.mID) {
1040     o.mID = -o.mID;
1041     ++gZombies;
1042     ++gAllConstructions;
1043     ++gMoveConstructions;
1044     if (gDebug) {
1045       printf("Spy[%d@%p](&&[%d->%d@%p])\n", mID, this, -o.mID, o.mID, &o);
1046     }
1047   }
~SpyTestThreadUtils::Spy1048   ~Spy() {
1049     if (mID >= 0) {
1050       --gAlive;
1051     } else {
1052       --gZombies;
1053     }
1054     ++gDestructions;
1055     if (gDebug) {
1056       printf("~Spy[%d@%p]()\n", mID, this);
1057     }
1058     mID = 0;
1059   }
operator =TestThreadUtils::Spy1060   Spy& operator=(const Spy& o) {
1061     ++gAssignments;
1062     if (gDebug) {
1063       printf("Spy[%d->%d@%p] = &[%d@%p]\n", mID, o.mID, this, o.mID, &o);
1064     }
1065     mID = o.mID;
1066     return *this;
1067   };
operator =TestThreadUtils::Spy1068   Spy& operator=(Spy&& o) {
1069     --gAlive;
1070     ++gZombies;
1071     ++gMoves;
1072     if (gDebug) {
1073       printf("Spy[%d->%d@%p] = &&[%d->%d@%p]\n", mID, o.mID, this, o.mID,
1074              -o.mID, &o);
1075     }
1076     mID = o.mID;
1077     o.mID = -o.mID;
1078     return *this;
1079   };
1080 
1081   int mID;  // ID given at construction, or negation if was moved from; 0 when
1082             // destroyed.
1083 };
1084 
1085 struct ISpyWithISupports : public nsISupports {
1086   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID)
1087   NS_IMETHOD_(nsrefcnt) RefCnt() = 0;
1088   NS_IMETHOD_(int32_t) ID() = 0;
1089 };
1090 NS_DEFINE_STATIC_IID_ACCESSOR(ISpyWithISupports, NS_IFOO_IID)
1091 struct SpyWithISupports : public ISpyWithISupports, public Spy {
1092  private:
1093   virtual ~SpyWithISupports() = default;
1094 
1095  public:
SpyWithISupportsTestThreadUtils::SpyWithISupports1096   explicit SpyWithISupports(int aID) : Spy(aID){};
1097   NS_DECL_ISUPPORTS
NS_IMETHOD_TestThreadUtils::SpyWithISupports1098   NS_IMETHOD_(nsrefcnt) RefCnt() override { return mRefCnt; }
IDTestThreadUtils::SpyWithISupports1099   NS_IMETHOD_(int32_t) ID() override { return mID; }
1100 };
1101 NS_IMPL_ISUPPORTS(SpyWithISupports, ISpyWithISupports)
1102 
1103 class IThreadUtilsObject : public nsISupports {
1104  public:
1105   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID)
1106 
1107   NS_IMETHOD_(nsrefcnt) RefCnt() = 0;
1108   NS_IMETHOD_(int32_t) ID() = 0;
1109 };
1110 
1111 NS_DEFINE_STATIC_IID_ACCESSOR(IThreadUtilsObject, NS_IFOO_IID)
1112 
1113 struct ThreadUtilsObjectNonRefCountedBase {
MethodFromNonRefCountedBaseTestThreadUtils::ThreadUtilsObjectNonRefCountedBase1114   virtual void MethodFromNonRefCountedBase() {}
1115 };
1116 
1117 struct ThreadUtilsObject : public IThreadUtilsObject,
1118                            public ThreadUtilsObjectNonRefCountedBase {
1119   // nsISupports implementation
1120   NS_DECL_ISUPPORTS
1121 
1122   // IThreadUtilsObject implementation
NS_IMETHOD_TestThreadUtils::ThreadUtilsObject1123   NS_IMETHOD_(nsrefcnt) RefCnt() override { return mRefCnt; }
IDTestThreadUtils::ThreadUtilsObject1124   NS_IMETHOD_(int32_t) ID() override { return 0; }
1125 
1126   int mCount;  // Number of calls + arguments processed.
1127   int mA0, mA1, mA2, mA3;
1128   Spy mSpy;
1129   const Spy* mSpyPtr;
ThreadUtilsObjectTestThreadUtils::ThreadUtilsObject1130   ThreadUtilsObject()
1131       : mCount(0), mA0(0), mA1(0), mA2(0), mA3(0), mSpy(1), mSpyPtr(nullptr) {}
1132 
1133  private:
1134   virtual ~ThreadUtilsObject() = default;
1135 
1136  public:
Test0TestThreadUtils::ThreadUtilsObject1137   void Test0() { mCount += 1; }
Test1iTestThreadUtils::ThreadUtilsObject1138   void Test1i(int a0) {
1139     mCount += 2;
1140     mA0 = a0;
1141   }
Test2iTestThreadUtils::ThreadUtilsObject1142   void Test2i(int a0, int a1) {
1143     mCount += 3;
1144     mA0 = a0;
1145     mA1 = a1;
1146   }
Test3iTestThreadUtils::ThreadUtilsObject1147   void Test3i(int a0, int a1, int a2) {
1148     mCount += 4;
1149     mA0 = a0;
1150     mA1 = a1;
1151     mA2 = a2;
1152   }
Test4iTestThreadUtils::ThreadUtilsObject1153   void Test4i(int a0, int a1, int a2, int a3) {
1154     mCount += 5;
1155     mA0 = a0;
1156     mA1 = a1;
1157     mA2 = a2;
1158     mA3 = a3;
1159   }
Test1piTestThreadUtils::ThreadUtilsObject1160   void Test1pi(int* ap) {
1161     mCount += 2;
1162     mA0 = ap ? *ap : -1;
1163   }
Test1pciTestThreadUtils::ThreadUtilsObject1164   void Test1pci(const int* ap) {
1165     mCount += 2;
1166     mA0 = ap ? *ap : -1;
1167   }
Test1riTestThreadUtils::ThreadUtilsObject1168   void Test1ri(int& ar) {
1169     mCount += 2;
1170     mA0 = ar;
1171   }
Test1rriTestThreadUtils::ThreadUtilsObject1172   void Test1rri(int&& arr) {
1173     mCount += 2;
1174     mA0 = arr;
1175   }
Test1upiTestThreadUtils::ThreadUtilsObject1176   void Test1upi(mozilla::UniquePtr<int> aup) {
1177     mCount += 2;
1178     mA0 = aup ? *aup : -1;
1179   }
Test1rupiTestThreadUtils::ThreadUtilsObject1180   void Test1rupi(mozilla::UniquePtr<int>& aup) {
1181     mCount += 2;
1182     mA0 = aup ? *aup : -1;
1183   }
Test1rrupiTestThreadUtils::ThreadUtilsObject1184   void Test1rrupi(mozilla::UniquePtr<int>&& aup) {
1185     mCount += 2;
1186     mA0 = aup ? *aup : -1;
1187   }
1188 
Test1sTestThreadUtils::ThreadUtilsObject1189   void Test1s(Spy) { mCount += 2; }
Test1psTestThreadUtils::ThreadUtilsObject1190   void Test1ps(Spy*) { mCount += 2; }
Test1rsTestThreadUtils::ThreadUtilsObject1191   void Test1rs(Spy&) { mCount += 2; }
Test1rrsTestThreadUtils::ThreadUtilsObject1192   void Test1rrs(Spy&&) { mCount += 2; }
Test1upsTestThreadUtils::ThreadUtilsObject1193   void Test1ups(mozilla::UniquePtr<Spy>) { mCount += 2; }
Test1rupsTestThreadUtils::ThreadUtilsObject1194   void Test1rups(mozilla::UniquePtr<Spy>&) { mCount += 2; }
Test1rrupsTestThreadUtils::ThreadUtilsObject1195   void Test1rrups(mozilla::UniquePtr<Spy>&&) { mCount += 2; }
1196 
1197   // Possible parameter passing styles:
TestByValueTestThreadUtils::ThreadUtilsObject1198   void TestByValue(Spy s) {
1199     if (gDebug) {
1200       printf("TestByValue(Spy[%d@%p])\n", s.mID, &s);
1201     }
1202     mSpy = s;
1203   };
TestByConstLRefTestThreadUtils::ThreadUtilsObject1204   void TestByConstLRef(const Spy& s) {
1205     if (gDebug) {
1206       printf("TestByConstLRef(Spy[%d@%p]&)\n", s.mID, &s);
1207     }
1208     mSpy = s;
1209   };
TestByRRefTestThreadUtils::ThreadUtilsObject1210   void TestByRRef(Spy&& s) {
1211     if (gDebug) {
1212       printf("TestByRRef(Spy[%d@%p]&&)\n", s.mID, &s);
1213     }
1214     mSpy = std::move(s);
1215   };
TestByLRefTestThreadUtils::ThreadUtilsObject1216   void TestByLRef(Spy& s) {
1217     if (gDebug) {
1218       printf("TestByLRef(Spy[%d@%p]&)\n", s.mID, &s);
1219     }
1220     mSpy = s;
1221     mSpyPtr = &s;
1222   };
TestByPointerTestThreadUtils::ThreadUtilsObject1223   void TestByPointer(Spy* p) {
1224     if (p) {
1225       if (gDebug) {
1226         printf("TestByPointer(&Spy[%d@%p])\n", p->mID, p);
1227       }
1228       mSpy = *p;
1229     } else {
1230       if (gDebug) {
1231         printf("TestByPointer(nullptr)\n");
1232       }
1233     }
1234     mSpyPtr = p;
1235   };
TestByPointerToConstTestThreadUtils::ThreadUtilsObject1236   void TestByPointerToConst(const Spy* p) {
1237     if (p) {
1238       if (gDebug) {
1239         printf("TestByPointerToConst(&Spy[%d@%p])\n", p->mID, p);
1240       }
1241       mSpy = *p;
1242     } else {
1243       if (gDebug) {
1244         printf("TestByPointerToConst(nullptr)\n");
1245       }
1246     }
1247     mSpyPtr = p;
1248   };
1249 };
1250 
1251 NS_IMPL_ISUPPORTS(ThreadUtilsObject, IThreadUtilsObject)
1252 
1253 class ThreadUtilsRefCountedFinal final {
1254  public:
ThreadUtilsRefCountedFinal()1255   ThreadUtilsRefCountedFinal() : m_refCount(0) {}
1256   ~ThreadUtilsRefCountedFinal() = default;
1257   // 'AddRef' and 'Release' methods with different return types, to verify
1258   // that the return type doesn't influence storage selection.
AddRef(void)1259   long AddRef(void) { return ++m_refCount; }
Release(void)1260   void Release(void) { --m_refCount; }
1261 
1262  private:
1263   long m_refCount;
1264 };
1265 
1266 class ThreadUtilsRefCountedBase {
1267  public:
ThreadUtilsRefCountedBase()1268   ThreadUtilsRefCountedBase() : m_refCount(0) {}
1269   virtual ~ThreadUtilsRefCountedBase() = default;
1270   // 'AddRef' and 'Release' methods with different return types, to verify
1271   // that the return type doesn't influence storage selection.
AddRef(void)1272   virtual void AddRef(void) { ++m_refCount; }
Release(void)1273   virtual MozExternalRefCountType Release(void) { return --m_refCount; }
1274 
1275  private:
1276   MozExternalRefCountType m_refCount;
1277 };
1278 
1279 class ThreadUtilsRefCountedDerived : public ThreadUtilsRefCountedBase {};
1280 
1281 class ThreadUtilsNonRefCounted {};
1282 
1283 }  // namespace TestThreadUtils
1284 
TEST(ThreadUtils,main)1285 TEST(ThreadUtils, main)
1286 {
1287   using namespace TestThreadUtils;
1288 
1289   static_assert(!IsParameterStorageClass<int>::value,
1290                 "'int' should not be recognized as Storage Class");
1291   static_assert(
1292       IsParameterStorageClass<StoreCopyPassByValue<int>>::value,
1293       "StoreCopyPassByValue<int> should be recognized as Storage Class");
1294   static_assert(
1295       IsParameterStorageClass<StoreCopyPassByConstLRef<int>>::value,
1296       "StoreCopyPassByConstLRef<int> should be recognized as Storage Class");
1297   static_assert(
1298       IsParameterStorageClass<StoreCopyPassByLRef<int>>::value,
1299       "StoreCopyPassByLRef<int> should be recognized as Storage Class");
1300   static_assert(
1301       IsParameterStorageClass<StoreCopyPassByRRef<int>>::value,
1302       "StoreCopyPassByRRef<int> should be recognized as Storage Class");
1303   static_assert(
1304       IsParameterStorageClass<StoreRefPassByLRef<int>>::value,
1305       "StoreRefPassByLRef<int> should be recognized as Storage Class");
1306   static_assert(
1307       IsParameterStorageClass<StoreConstRefPassByConstLRef<int>>::value,
1308       "StoreConstRefPassByConstLRef<int> should be recognized as Storage "
1309       "Class");
1310   static_assert(
1311       IsParameterStorageClass<StoreRefPtrPassByPtr<int>>::value,
1312       "StoreRefPtrPassByPtr<int> should be recognized as Storage Class");
1313   static_assert(IsParameterStorageClass<StorePtrPassByPtr<int>>::value,
1314                 "StorePtrPassByPtr<int> should be recognized as Storage Class");
1315   static_assert(
1316       IsParameterStorageClass<StoreConstPtrPassByConstPtr<int>>::value,
1317       "StoreConstPtrPassByConstPtr<int> should be recognized as Storage Class");
1318   static_assert(
1319       IsParameterStorageClass<StoreCopyPassByConstPtr<int>>::value,
1320       "StoreCopyPassByConstPtr<int> should be recognized as Storage Class");
1321   static_assert(
1322       IsParameterStorageClass<StoreCopyPassByPtr<int>>::value,
1323       "StoreCopyPassByPtr<int> should be recognized as Storage Class");
1324 
1325   RefPtr<ThreadUtilsObject> rpt(new ThreadUtilsObject);
1326   int count = 0;
1327 
1328   // Test legacy functions.
1329 
1330   nsCOMPtr<nsIRunnable> r1 =
1331       NewRunnableMethod("TestThreadUtils::ThreadUtilsObject::Test0", rpt,
1332                         &ThreadUtilsObject::Test0);
1333   r1->Run();
1334   EXPECT_EQ(count += 1, rpt->mCount);
1335 
1336   r1 = NewRunnableMethod<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt,
1337                               &ThreadUtilsObject::Test1i, 11);
1338   r1->Run();
1339   EXPECT_EQ(count += 2, rpt->mCount);
1340   EXPECT_EQ(11, rpt->mA0);
1341 
1342   // Test calling a method from a non-ref-counted base.
1343 
1344   r1 = NewRunnableMethod(
1345       "TestThreadUtils::ThreadUtilsObjectNonRefCountedBase::"
1346       "MethodFromNonRefCountedBase",
1347       rpt, &ThreadUtilsObject::MethodFromNonRefCountedBase);
1348   r1->Run();
1349   EXPECT_EQ(count, rpt->mCount);
1350 
1351   // Test variadic function with simple POD arguments.
1352 
1353   r1 = NewRunnableMethod("TestThreadUtils::ThreadUtilsObject::Test0", rpt,
1354                          &ThreadUtilsObject::Test0);
1355   r1->Run();
1356   EXPECT_EQ(count += 1, rpt->mCount);
1357 
1358   static_assert(std::is_same_v<::detail::ParameterStorage<int>::Type,
1359                                StoreCopyPassByConstLRef<int>>,
1360                 "detail::ParameterStorage<int>::Type should be "
1361                 "StoreCopyPassByConstLRef<int>");
1362   static_assert(std::is_same_v<
1363                     ::detail::ParameterStorage<StoreCopyPassByValue<int>>::Type,
1364                     StoreCopyPassByValue<int>>,
1365                 "detail::ParameterStorage<StoreCopyPassByValue<int>>::Type "
1366                 "should be StoreCopyPassByValue<int>");
1367 
1368   r1 = NewRunnableMethod<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt,
1369                               &ThreadUtilsObject::Test1i, 12);
1370   r1->Run();
1371   EXPECT_EQ(count += 2, rpt->mCount);
1372   EXPECT_EQ(12, rpt->mA0);
1373 
1374   r1 = NewRunnableMethod<int, int>("TestThreadUtils::ThreadUtilsObject::Test2i",
1375                                    rpt, &ThreadUtilsObject::Test2i, 21, 22);
1376   r1->Run();
1377   EXPECT_EQ(count += 3, rpt->mCount);
1378   EXPECT_EQ(21, rpt->mA0);
1379   EXPECT_EQ(22, rpt->mA1);
1380 
1381   r1 = NewRunnableMethod<int, int, int>(
1382       "TestThreadUtils::ThreadUtilsObject::Test3i", rpt,
1383       &ThreadUtilsObject::Test3i, 31, 32, 33);
1384   r1->Run();
1385   EXPECT_EQ(count += 4, rpt->mCount);
1386   EXPECT_EQ(31, rpt->mA0);
1387   EXPECT_EQ(32, rpt->mA1);
1388   EXPECT_EQ(33, rpt->mA2);
1389 
1390   r1 = NewRunnableMethod<int, int, int, int>(
1391       "TestThreadUtils::ThreadUtilsObject::Test4i", rpt,
1392       &ThreadUtilsObject::Test4i, 41, 42, 43, 44);
1393   r1->Run();
1394   EXPECT_EQ(count += 5, rpt->mCount);
1395   EXPECT_EQ(41, rpt->mA0);
1396   EXPECT_EQ(42, rpt->mA1);
1397   EXPECT_EQ(43, rpt->mA2);
1398   EXPECT_EQ(44, rpt->mA3);
1399 
1400   // More interesting types of arguments.
1401 
1402   // Passing a short to make sure forwarding works with an inexact type match.
1403   short int si = 11;
1404   r1 = NewRunnableMethod<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt,
1405                               &ThreadUtilsObject::Test1i, si);
1406   r1->Run();
1407   EXPECT_EQ(count += 2, rpt->mCount);
1408   EXPECT_EQ(si, rpt->mA0);
1409 
1410   // Raw pointer, possible cv-qualified.
1411   static_assert(
1412       std::is_same_v<::detail::ParameterStorage<int*>::Type,
1413                      StorePtrPassByPtr<int>>,
1414       "detail::ParameterStorage<int*>::Type should be StorePtrPassByPtr<int>");
1415   static_assert(std::is_same_v<::detail::ParameterStorage<int* const>::Type,
1416                                StorePtrPassByPtr<int>>,
1417                 "detail::ParameterStorage<int* const>::Type should be "
1418                 "StorePtrPassByPtr<int>");
1419   static_assert(std::is_same_v<::detail::ParameterStorage<int* volatile>::Type,
1420                                StorePtrPassByPtr<int>>,
1421                 "detail::ParameterStorage<int* volatile>::Type should be "
1422                 "StorePtrPassByPtr<int>");
1423   static_assert(
1424       std::is_same_v<::detail::ParameterStorage<int* const volatile>::Type,
1425                      StorePtrPassByPtr<int>>,
1426       "detail::ParameterStorage<int* const volatile>::Type should be "
1427       "StorePtrPassByPtr<int>");
1428   static_assert(
1429       std::is_same_v<::detail::ParameterStorage<int*>::Type::stored_type, int*>,
1430       "detail::ParameterStorage<int*>::Type::stored_type should be int*");
1431   static_assert(
1432       std::is_same_v<::detail::ParameterStorage<int*>::Type::passed_type, int*>,
1433       "detail::ParameterStorage<int*>::Type::passed_type should be int*");
1434   {
1435     int i = 12;
1436     r1 = NewRunnableMethod<int*>("TestThreadUtils::ThreadUtilsObject::Test1pi",
1437                                  rpt, &ThreadUtilsObject::Test1pi, &i);
1438     r1->Run();
1439     EXPECT_EQ(count += 2, rpt->mCount);
1440     EXPECT_EQ(i, rpt->mA0);
1441   }
1442 
1443   // Raw pointer to const.
1444   static_assert(std::is_same_v<::detail::ParameterStorage<const int*>::Type,
1445                                StoreConstPtrPassByConstPtr<int>>,
1446                 "detail::ParameterStorage<const int*>::Type should be "
1447                 "StoreConstPtrPassByConstPtr<int>");
1448   static_assert(
1449       std::is_same_v<::detail::ParameterStorage<const int* const>::Type,
1450                      StoreConstPtrPassByConstPtr<int>>,
1451       "detail::ParameterStorage<const int* const>::Type should be "
1452       "StoreConstPtrPassByConstPtr<int>");
1453   static_assert(
1454       std::is_same_v<::detail::ParameterStorage<const int* volatile>::Type,
1455                      StoreConstPtrPassByConstPtr<int>>,
1456       "detail::ParameterStorage<const int* volatile>::Type should be "
1457       "StoreConstPtrPassByConstPtr<int>");
1458   static_assert(std::is_same_v<
1459                     ::detail::ParameterStorage<const int* const volatile>::Type,
1460                     StoreConstPtrPassByConstPtr<int>>,
1461                 "detail::ParameterStorage<const int* const volatile>::Type "
1462                 "should be StoreConstPtrPassByConstPtr<int>");
1463   static_assert(
1464       std::is_same_v<::detail::ParameterStorage<const int*>::Type::stored_type,
1465                      const int*>,
1466       "detail::ParameterStorage<const int*>::Type::stored_type should be const "
1467       "int*");
1468   static_assert(
1469       std::is_same_v<::detail::ParameterStorage<const int*>::Type::passed_type,
1470                      const int*>,
1471       "detail::ParameterStorage<const int*>::Type::passed_type should be const "
1472       "int*");
1473   {
1474     int i = 1201;
1475     r1 = NewRunnableMethod<const int*>(
1476         "TestThreadUtils::ThreadUtilsObject::Test1pci", rpt,
1477         &ThreadUtilsObject::Test1pci, &i);
1478     r1->Run();
1479     EXPECT_EQ(count += 2, rpt->mCount);
1480     EXPECT_EQ(i, rpt->mA0);
1481   }
1482 
1483   // Raw pointer to copy.
1484   static_assert(std::is_same_v<StoreCopyPassByPtr<int>::stored_type, int>,
1485                 "StoreCopyPassByPtr<int>::stored_type should be int");
1486   static_assert(std::is_same_v<StoreCopyPassByPtr<int>::passed_type, int*>,
1487                 "StoreCopyPassByPtr<int>::passed_type should be int*");
1488   {
1489     int i = 1202;
1490     r1 = NewRunnableMethod<StoreCopyPassByPtr<int>>(
1491         "TestThreadUtils::ThreadUtilsObject::Test1pi", rpt,
1492         &ThreadUtilsObject::Test1pi, i);
1493     r1->Run();
1494     EXPECT_EQ(count += 2, rpt->mCount);
1495     EXPECT_EQ(i, rpt->mA0);
1496   }
1497 
1498   // Raw pointer to const copy.
1499   static_assert(std::is_same_v<StoreCopyPassByConstPtr<int>::stored_type, int>,
1500                 "StoreCopyPassByConstPtr<int>::stored_type should be int");
1501   static_assert(
1502       std::is_same_v<StoreCopyPassByConstPtr<int>::passed_type, const int*>,
1503       "StoreCopyPassByConstPtr<int>::passed_type should be const int*");
1504   {
1505     int i = 1203;
1506     r1 = NewRunnableMethod<StoreCopyPassByConstPtr<int>>(
1507         "TestThreadUtils::ThreadUtilsObject::Test1pci", rpt,
1508         &ThreadUtilsObject::Test1pci, i);
1509     r1->Run();
1510     EXPECT_EQ(count += 2, rpt->mCount);
1511     EXPECT_EQ(i, rpt->mA0);
1512   }
1513 
1514   // nsRefPtr to pointer.
1515   static_assert(
1516       std::is_same_v<::detail::ParameterStorage<
1517                          StoreRefPtrPassByPtr<SpyWithISupports>>::Type,
1518                      StoreRefPtrPassByPtr<SpyWithISupports>>,
1519       "ParameterStorage<StoreRefPtrPassByPtr<SpyWithISupports>>::Type should "
1520       "be StoreRefPtrPassByPtr<SpyWithISupports>");
1521   static_assert(
1522       std::is_same_v<::detail::ParameterStorage<SpyWithISupports*>::Type,
1523                      StoreRefPtrPassByPtr<SpyWithISupports>>,
1524       "ParameterStorage<SpyWithISupports*>::Type should be "
1525       "StoreRefPtrPassByPtr<SpyWithISupports>");
1526   static_assert(
1527       std::is_same_v<StoreRefPtrPassByPtr<SpyWithISupports>::stored_type,
1528                      RefPtr<SpyWithISupports>>,
1529       "StoreRefPtrPassByPtr<SpyWithISupports>::stored_type should be "
1530       "RefPtr<SpyWithISupports>");
1531   static_assert(
1532       std::is_same_v<StoreRefPtrPassByPtr<SpyWithISupports>::passed_type,
1533                      SpyWithISupports*>,
1534       "StoreRefPtrPassByPtr<SpyWithISupports>::passed_type should be "
1535       "SpyWithISupports*");
1536   // (more nsRefPtr tests below)
1537 
1538   // nsRefPtr for ref-countable classes that do not derive from ISupports.
1539   static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedFinal>::value,
1540                 "ThreadUtilsRefCountedFinal has AddRef() and Release()");
1541   static_assert(
1542       std::is_same_v<
1543           ::detail::ParameterStorage<ThreadUtilsRefCountedFinal*>::Type,
1544           StoreRefPtrPassByPtr<ThreadUtilsRefCountedFinal>>,
1545       "ParameterStorage<ThreadUtilsRefCountedFinal*>::Type should be "
1546       "StoreRefPtrPassByPtr<ThreadUtilsRefCountedFinal>");
1547   static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedBase>::value,
1548                 "ThreadUtilsRefCountedBase has AddRef() and Release()");
1549   static_assert(
1550       std::is_same_v<
1551           ::detail::ParameterStorage<ThreadUtilsRefCountedBase*>::Type,
1552           StoreRefPtrPassByPtr<ThreadUtilsRefCountedBase>>,
1553       "ParameterStorage<ThreadUtilsRefCountedBase*>::Type should be "
1554       "StoreRefPtrPassByPtr<ThreadUtilsRefCountedBase>");
1555   static_assert(
1556       ::detail::HasRefCountMethods<ThreadUtilsRefCountedDerived>::value,
1557       "ThreadUtilsRefCountedDerived has AddRef() and Release()");
1558   static_assert(
1559       std::is_same_v<
1560           ::detail::ParameterStorage<ThreadUtilsRefCountedDerived*>::Type,
1561           StoreRefPtrPassByPtr<ThreadUtilsRefCountedDerived>>,
1562       "ParameterStorage<ThreadUtilsRefCountedDerived*>::Type should be "
1563       "StoreRefPtrPassByPtr<ThreadUtilsRefCountedDerived>");
1564 
1565   static_assert(!::detail::HasRefCountMethods<ThreadUtilsNonRefCounted>::value,
1566                 "ThreadUtilsNonRefCounted doesn't have AddRef() and Release()");
1567   static_assert(!std::is_same_v<
1568                     ::detail::ParameterStorage<ThreadUtilsNonRefCounted*>::Type,
1569                     StoreRefPtrPassByPtr<ThreadUtilsNonRefCounted>>,
1570                 "ParameterStorage<ThreadUtilsNonRefCounted*>::Type should NOT "
1571                 "be StoreRefPtrPassByPtr<ThreadUtilsNonRefCounted>");
1572 
1573   // Lvalue reference.
1574   static_assert(
1575       std::is_same_v<::detail::ParameterStorage<int&>::Type,
1576                      StoreRefPassByLRef<int>>,
1577       "ParameterStorage<int&>::Type should be StoreRefPassByLRef<int>");
1578   static_assert(
1579       std::is_same_v<::detail::ParameterStorage<int&>::Type::stored_type,
1580                      StoreRefPassByLRef<int>::stored_type>,
1581       "ParameterStorage<int&>::Type::stored_type should be "
1582       "StoreRefPassByLRef<int>::stored_type");
1583   static_assert(
1584       std::is_same_v<::detail::ParameterStorage<int&>::Type::stored_type, int&>,
1585       "ParameterStorage<int&>::Type::stored_type should be int&");
1586   static_assert(
1587       std::is_same_v<::detail::ParameterStorage<int&>::Type::passed_type, int&>,
1588       "ParameterStorage<int&>::Type::passed_type should be int&");
1589   {
1590     int i = 13;
1591     r1 = NewRunnableMethod<int&>("TestThreadUtils::ThreadUtilsObject::Test1ri",
1592                                  rpt, &ThreadUtilsObject::Test1ri, i);
1593     r1->Run();
1594     EXPECT_EQ(count += 2, rpt->mCount);
1595     EXPECT_EQ(i, rpt->mA0);
1596   }
1597 
1598   // Rvalue reference -- Actually storing a copy and then moving it.
1599   static_assert(
1600       std::is_same_v<::detail::ParameterStorage<int&&>::Type,
1601                      StoreCopyPassByRRef<int>>,
1602       "ParameterStorage<int&&>::Type should be StoreCopyPassByRRef<int>");
1603   static_assert(
1604       std::is_same_v<::detail::ParameterStorage<int&&>::Type::stored_type,
1605                      StoreCopyPassByRRef<int>::stored_type>,
1606       "ParameterStorage<int&&>::Type::stored_type should be "
1607       "StoreCopyPassByRRef<int>::stored_type");
1608   static_assert(
1609       std::is_same_v<::detail::ParameterStorage<int&&>::Type::stored_type, int>,
1610       "ParameterStorage<int&&>::Type::stored_type should be int");
1611   static_assert(
1612       std::is_same_v<::detail::ParameterStorage<int&&>::Type::passed_type,
1613                      int&&>,
1614       "ParameterStorage<int&&>::Type::passed_type should be int&&");
1615   {
1616     int i = 14;
1617     r1 = NewRunnableMethod<int&&>(
1618         "TestThreadUtils::ThreadUtilsObject::Test1rri", rpt,
1619         &ThreadUtilsObject::Test1rri, std::move(i));
1620   }
1621   r1->Run();
1622   EXPECT_EQ(count += 2, rpt->mCount);
1623   EXPECT_EQ(14, rpt->mA0);
1624 
1625   // Null unique pointer, by semi-implicit store&move with "T&&" syntax.
1626   static_assert(std::is_same_v<
1627                     ::detail::ParameterStorage<mozilla::UniquePtr<int>&&>::Type,
1628                     StoreCopyPassByRRef<mozilla::UniquePtr<int>>>,
1629                 "ParameterStorage<UniquePtr<int>&&>::Type should be "
1630                 "StoreCopyPassByRRef<UniquePtr<int>>");
1631   static_assert(
1632       std::is_same_v<::detail::ParameterStorage<
1633                          mozilla::UniquePtr<int>&&>::Type::stored_type,
1634                      StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>,
1635       "ParameterStorage<UniquePtr<int>&&>::Type::stored_type should be "
1636       "StoreCopyPassByRRef<UniquePtr<int>>::stored_type");
1637   static_assert(
1638       std::is_same_v<::detail::ParameterStorage<
1639                          mozilla::UniquePtr<int>&&>::Type::stored_type,
1640                      mozilla::UniquePtr<int>>,
1641       "ParameterStorage<UniquePtr<int>&&>::Type::stored_type should be "
1642       "UniquePtr<int>");
1643   static_assert(
1644       std::is_same_v<::detail::ParameterStorage<
1645                          mozilla::UniquePtr<int>&&>::Type::passed_type,
1646                      mozilla::UniquePtr<int>&&>,
1647       "ParameterStorage<UniquePtr<int>&&>::Type::passed_type should be "
1648       "UniquePtr<int>&&");
1649   {
1650     mozilla::UniquePtr<int> upi;
1651     r1 = NewRunnableMethod<mozilla::UniquePtr<int>&&>(
1652         "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1653         &ThreadUtilsObject::Test1upi, std::move(upi));
1654   }
1655   r1->Run();
1656   EXPECT_EQ(count += 2, rpt->mCount);
1657   EXPECT_EQ(-1, rpt->mA0);
1658   rpt->mA0 = 0;
1659 
1660   // Null unique pointer, by explicit store&move with "StoreCopyPassByRRef<T>"
1661   // syntax.
1662   static_assert(
1663       std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
1664                          mozilla::UniquePtr<int>>>::Type::stored_type,
1665                      StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>,
1666       "ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::stored_"
1667       "type should be StoreCopyPassByRRef<UniquePtr<int>>::stored_type");
1668   static_assert(
1669       std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
1670                          mozilla::UniquePtr<int>>>::Type::stored_type,
1671                      StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>,
1672       "ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::stored_"
1673       "type should be StoreCopyPassByRRef<UniquePtr<int>>::stored_type");
1674   static_assert(
1675       std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
1676                          mozilla::UniquePtr<int>>>::Type::stored_type,
1677                      mozilla::UniquePtr<int>>,
1678       "ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::stored_"
1679       "type should be UniquePtr<int>");
1680   static_assert(
1681       std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
1682                          mozilla::UniquePtr<int>>>::Type::passed_type,
1683                      mozilla::UniquePtr<int>&&>,
1684       "ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::passed_"
1685       "type should be UniquePtr<int>&&");
1686   {
1687     mozilla::UniquePtr<int> upi;
1688     r1 = NewRunnableMethod<StoreCopyPassByRRef<mozilla::UniquePtr<int>>>(
1689         "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1690         &ThreadUtilsObject::Test1upi, std::move(upi));
1691   }
1692   r1->Run();
1693   EXPECT_EQ(count += 2, rpt->mCount);
1694   EXPECT_EQ(-1, rpt->mA0);
1695 
1696   // Unique pointer as xvalue.
1697   {
1698     mozilla::UniquePtr<int> upi = mozilla::MakeUnique<int>(1);
1699     r1 = NewRunnableMethod<mozilla::UniquePtr<int>&&>(
1700         "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1701         &ThreadUtilsObject::Test1upi, std::move(upi));
1702   }
1703   r1->Run();
1704   EXPECT_EQ(count += 2, rpt->mCount);
1705   EXPECT_EQ(1, rpt->mA0);
1706 
1707   {
1708     mozilla::UniquePtr<int> upi = mozilla::MakeUnique<int>(1);
1709     r1 = NewRunnableMethod<StoreCopyPassByRRef<mozilla::UniquePtr<int>>>(
1710         "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1711         &ThreadUtilsObject::Test1upi, std::move(upi));
1712   }
1713   r1->Run();
1714   EXPECT_EQ(count += 2, rpt->mCount);
1715   EXPECT_EQ(1, rpt->mA0);
1716 
1717   // Unique pointer as prvalue.
1718   r1 = NewRunnableMethod<mozilla::UniquePtr<int>&&>(
1719       "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1720       &ThreadUtilsObject::Test1upi, mozilla::MakeUnique<int>(2));
1721   r1->Run();
1722   EXPECT_EQ(count += 2, rpt->mCount);
1723   EXPECT_EQ(2, rpt->mA0);
1724 
1725   // Unique pointer as lvalue to lref.
1726   {
1727     mozilla::UniquePtr<int> upi;
1728     r1 = NewRunnableMethod<mozilla::UniquePtr<int>&>(
1729         "TestThreadUtils::ThreadUtilsObject::Test1rupi", rpt,
1730         &ThreadUtilsObject::Test1rupi, upi);
1731     // Passed as lref, so Run() must be called while local upi is still alive!
1732     r1->Run();
1733   }
1734   EXPECT_EQ(count += 2, rpt->mCount);
1735   EXPECT_EQ(-1, rpt->mA0);
1736 
1737   // Verify copy/move assumptions.
1738 
1739   Spy::ClearAll();
1740   if (gDebug) {
1741     printf("%d - Test: Store copy from lvalue, pass by value\n", __LINE__);
1742   }
1743   {  // Block around nsCOMPtr lifetime.
1744     nsCOMPtr<nsIRunnable> r2;
1745     {  // Block around Spy lifetime.
1746       if (gDebug) {
1747         printf("%d - Spy s(10)\n", __LINE__);
1748       }
1749       Spy s(10);
1750       EXPECT_EQ(1, gConstructions);
1751       EXPECT_EQ(1, gAlive);
1752       if (gDebug) {
1753         printf(
1754             "%d - r2 = "
1755             "NewRunnableMethod<StoreCopyPassByValue<Spy>>(&TestByValue, s)\n",
1756             __LINE__);
1757       }
1758       r2 = NewRunnableMethod<StoreCopyPassByValue<Spy>>(
1759           "TestThreadUtils::ThreadUtilsObject::TestByValue", rpt,
1760           &ThreadUtilsObject::TestByValue, s);
1761       EXPECT_EQ(2, gAlive);
1762       EXPECT_LE(1, gCopyConstructions);  // At least 1 copy-construction.
1763       Spy::ClearActions();
1764       if (gDebug) {
1765         printf("%d - End block with Spy s(10)\n", __LINE__);
1766       }
1767     }
1768     EXPECT_EQ(1, gDestructions);
1769     EXPECT_EQ(1, gAlive);
1770     Spy::ClearActions();
1771     if (gDebug) {
1772       printf("%d - Run()\n", __LINE__);
1773     }
1774     r2->Run();
1775     EXPECT_LE(1, gCopyConstructions);  // Another copy-construction in call.
1776     EXPECT_EQ(10, rpt->mSpy.mID);
1777     EXPECT_LE(1, gDestructions);
1778     EXPECT_EQ(1, gAlive);
1779     Spy::ClearActions();
1780     if (gDebug) {
1781       printf("%d - End block with r\n", __LINE__);
1782     }
1783   }
1784   if (gDebug) {
1785     printf("%d - After end block with r\n", __LINE__);
1786   }
1787   EXPECT_EQ(1, gDestructions);
1788   EXPECT_EQ(0, gAlive);
1789 
1790   Spy::ClearAll();
1791   if (gDebug) {
1792     printf("%d - Test: Store copy from prvalue, pass by value\n", __LINE__);
1793   }
1794   {
1795     if (gDebug) {
1796       printf(
1797           "%d - r3 = "
1798           "NewRunnableMethod<StoreCopyPassByValue<Spy>>(&TestByValue, "
1799           "Spy(11))\n",
1800           __LINE__);
1801     }
1802     nsCOMPtr<nsIRunnable> r3 = NewRunnableMethod<StoreCopyPassByValue<Spy>>(
1803         "TestThreadUtils::ThreadUtilsObject::TestByValue", rpt,
1804         &ThreadUtilsObject::TestByValue, Spy(11));
1805     EXPECT_EQ(1, gAlive);
1806     EXPECT_EQ(1, gConstructions);
1807     EXPECT_LE(1, gMoveConstructions);
1808     Spy::ClearActions();
1809     if (gDebug) {
1810       printf("%d - Run()\n", __LINE__);
1811     }
1812     r3->Run();
1813     EXPECT_LE(1, gCopyConstructions);  // Another copy-construction in call.
1814     EXPECT_EQ(11, rpt->mSpy.mID);
1815     EXPECT_LE(1, gDestructions);
1816     EXPECT_EQ(1, gAlive);
1817     Spy::ClearActions();
1818     if (gDebug) {
1819       printf("%d - End block with r\n", __LINE__);
1820     }
1821   }
1822   if (gDebug) {
1823     printf("%d - After end block with r\n", __LINE__);
1824   }
1825   EXPECT_EQ(1, gDestructions);
1826   EXPECT_EQ(0, gAlive);
1827 
1828   Spy::ClearAll();
1829   {  // Store copy from xvalue, pass by value.
1830     nsCOMPtr<nsIRunnable> r4;
1831     {
1832       Spy s(12);
1833       EXPECT_EQ(1, gConstructions);
1834       EXPECT_EQ(1, gAlive);
1835       Spy::ClearActions();
1836       r4 = NewRunnableMethod<StoreCopyPassByValue<Spy>>(
1837           "TestThreadUtils::ThreadUtilsObject::TestByValue", rpt,
1838           &ThreadUtilsObject::TestByValue, std::move(s));
1839       EXPECT_LE(1, gMoveConstructions);
1840       EXPECT_EQ(1, gAlive);
1841       EXPECT_EQ(1, gZombies);
1842       Spy::ClearActions();
1843     }
1844     EXPECT_EQ(1, gDestructions);
1845     EXPECT_EQ(1, gAlive);
1846     EXPECT_EQ(0, gZombies);
1847     Spy::ClearActions();
1848     r4->Run();
1849     EXPECT_LE(1, gCopyConstructions);  // Another copy-construction in call.
1850     EXPECT_EQ(12, rpt->mSpy.mID);
1851     EXPECT_LE(1, gDestructions);
1852     EXPECT_EQ(1, gAlive);
1853     Spy::ClearActions();
1854   }
1855   EXPECT_EQ(1, gDestructions);
1856   EXPECT_EQ(0, gAlive);
1857   // Won't test xvalues anymore, prvalues are enough to verify all rvalues.
1858 
1859   Spy::ClearAll();
1860   if (gDebug) {
1861     printf("%d - Test: Store copy from lvalue, pass by const lvalue ref\n",
1862            __LINE__);
1863   }
1864   {  // Block around nsCOMPtr lifetime.
1865     nsCOMPtr<nsIRunnable> r5;
1866     {  // Block around Spy lifetime.
1867       if (gDebug) {
1868         printf("%d - Spy s(20)\n", __LINE__);
1869       }
1870       Spy s(20);
1871       EXPECT_EQ(1, gConstructions);
1872       EXPECT_EQ(1, gAlive);
1873       if (gDebug) {
1874         printf(
1875             "%d - r5 = "
1876             "NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(&TestByConstLRef,"
1877             " s)\n",
1878             __LINE__);
1879       }
1880       r5 = NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(
1881           "TestThreadUtils::ThreadUtilsObject::TestByConstLRef", rpt,
1882           &ThreadUtilsObject::TestByConstLRef, s);
1883       EXPECT_EQ(2, gAlive);
1884       EXPECT_LE(1, gCopyConstructions);  // At least 1 copy-construction.
1885       Spy::ClearActions();
1886       if (gDebug) {
1887         printf("%d - End block with Spy s(20)\n", __LINE__);
1888       }
1889     }
1890     EXPECT_EQ(1, gDestructions);
1891     EXPECT_EQ(1, gAlive);
1892     Spy::ClearActions();
1893     if (gDebug) {
1894       printf("%d - Run()\n", __LINE__);
1895     }
1896     r5->Run();
1897     EXPECT_EQ(0, gCopyConstructions);  // No copies in call.
1898     EXPECT_EQ(20, rpt->mSpy.mID);
1899     EXPECT_EQ(0, gDestructions);
1900     EXPECT_EQ(1, gAlive);
1901     Spy::ClearActions();
1902     if (gDebug) {
1903       printf("%d - End block with r\n", __LINE__);
1904     }
1905   }
1906   if (gDebug) {
1907     printf("%d - After end block with r\n", __LINE__);
1908   }
1909   EXPECT_EQ(1, gDestructions);
1910   EXPECT_EQ(0, gAlive);
1911 
1912   Spy::ClearAll();
1913   if (gDebug) {
1914     printf("%d - Test: Store copy from prvalue, pass by const lvalue ref\n",
1915            __LINE__);
1916   }
1917   {
1918     if (gDebug) {
1919       printf(
1920           "%d - r6 = "
1921           "NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(&TestByConstLRef, "
1922           "Spy(21))\n",
1923           __LINE__);
1924     }
1925     nsCOMPtr<nsIRunnable> r6 = NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(
1926         "TestThreadUtils::ThreadUtilsObject::TestByConstLRef", rpt,
1927         &ThreadUtilsObject::TestByConstLRef, Spy(21));
1928     EXPECT_EQ(1, gAlive);
1929     EXPECT_EQ(1, gConstructions);
1930     EXPECT_LE(1, gMoveConstructions);
1931     Spy::ClearActions();
1932     if (gDebug) {
1933       printf("%d - Run()\n", __LINE__);
1934     }
1935     r6->Run();
1936     EXPECT_EQ(0, gCopyConstructions);  // No copies in call.
1937     EXPECT_EQ(21, rpt->mSpy.mID);
1938     EXPECT_EQ(0, gDestructions);
1939     EXPECT_EQ(1, gAlive);
1940     Spy::ClearActions();
1941     if (gDebug) {
1942       printf("%d - End block with r\n", __LINE__);
1943     }
1944   }
1945   if (gDebug) {
1946     printf("%d - After end block with r\n", __LINE__);
1947   }
1948   EXPECT_EQ(1, gDestructions);
1949   EXPECT_EQ(0, gAlive);
1950 
1951   Spy::ClearAll();
1952   if (gDebug) {
1953     printf("%d - Test: Store copy from lvalue, pass by rvalue ref\n", __LINE__);
1954   }
1955   {  // Block around nsCOMPtr lifetime.
1956     nsCOMPtr<nsIRunnable> r7;
1957     {  // Block around Spy lifetime.
1958       if (gDebug) {
1959         printf("%d - Spy s(30)\n", __LINE__);
1960       }
1961       Spy s(30);
1962       EXPECT_EQ(1, gConstructions);
1963       EXPECT_EQ(1, gAlive);
1964       if (gDebug) {
1965         printf(
1966             "%d - r7 = "
1967             "NewRunnableMethod<StoreCopyPassByRRef<Spy>>(&TestByRRef, s)\n",
1968             __LINE__);
1969       }
1970       r7 = NewRunnableMethod<StoreCopyPassByRRef<Spy>>(
1971           "TestThreadUtils::ThreadUtilsObject::TestByRRef", rpt,
1972           &ThreadUtilsObject::TestByRRef, s);
1973       EXPECT_EQ(2, gAlive);
1974       EXPECT_LE(1, gCopyConstructions);  // At least 1 copy-construction.
1975       Spy::ClearActions();
1976       if (gDebug) {
1977         printf("%d - End block with Spy s(30)\n", __LINE__);
1978       }
1979     }
1980     EXPECT_EQ(1, gDestructions);
1981     EXPECT_EQ(1, gAlive);
1982     Spy::ClearActions();
1983     if (gDebug) {
1984       printf("%d - Run()\n", __LINE__);
1985     }
1986     r7->Run();
1987     EXPECT_LE(1, gMoves);  // Move in call.
1988     EXPECT_EQ(30, rpt->mSpy.mID);
1989     EXPECT_EQ(0, gDestructions);
1990     EXPECT_EQ(0, gAlive);    // Spy inside Test is not counted.
1991     EXPECT_EQ(1, gZombies);  // Our local spy should now be a zombie.
1992     Spy::ClearActions();
1993     if (gDebug) {
1994       printf("%d - End block with r\n", __LINE__);
1995     }
1996   }
1997   if (gDebug) {
1998     printf("%d - After end block with r\n", __LINE__);
1999   }
2000   EXPECT_EQ(1, gDestructions);
2001   EXPECT_EQ(0, gAlive);
2002 
2003   Spy::ClearAll();
2004   if (gDebug) {
2005     printf("%d - Test: Store copy from prvalue, pass by rvalue ref\n",
2006            __LINE__);
2007   }
2008   {
2009     if (gDebug) {
2010       printf(
2011           "%d - r8 = NewRunnableMethod<StoreCopyPassByRRef<Spy>>(&TestByRRef, "
2012           "Spy(31))\n",
2013           __LINE__);
2014     }
2015     nsCOMPtr<nsIRunnable> r8 = NewRunnableMethod<StoreCopyPassByRRef<Spy>>(
2016         "TestThreadUtils::ThreadUtilsObject::TestByRRef", rpt,
2017         &ThreadUtilsObject::TestByRRef, Spy(31));
2018     EXPECT_EQ(1, gAlive);
2019     EXPECT_EQ(1, gConstructions);
2020     EXPECT_LE(1, gMoveConstructions);
2021     Spy::ClearActions();
2022     if (gDebug) {
2023       printf("%d - Run()\n", __LINE__);
2024     }
2025     r8->Run();
2026     EXPECT_LE(1, gMoves);  // Move in call.
2027     EXPECT_EQ(31, rpt->mSpy.mID);
2028     EXPECT_EQ(0, gDestructions);
2029     EXPECT_EQ(0, gAlive);    // Spy inside Test is not counted.
2030     EXPECT_EQ(1, gZombies);  // Our local spy should now be a zombie.
2031     Spy::ClearActions();
2032     if (gDebug) {
2033       printf("%d - End block with r\n", __LINE__);
2034     }
2035   }
2036   if (gDebug) {
2037     printf("%d - After end block with r\n", __LINE__);
2038   }
2039   EXPECT_EQ(1, gDestructions);
2040   EXPECT_EQ(0, gAlive);
2041 
2042   Spy::ClearAll();
2043   if (gDebug) {
2044     printf("%d - Test: Store lvalue ref, pass lvalue ref\n", __LINE__);
2045   }
2046   {
2047     if (gDebug) {
2048       printf("%d - Spy s(40)\n", __LINE__);
2049     }
2050     Spy s(40);
2051     EXPECT_EQ(1, gConstructions);
2052     EXPECT_EQ(1, gAlive);
2053     Spy::ClearActions();
2054     if (gDebug) {
2055       printf("%d - r9 = NewRunnableMethod<Spy&>(&TestByLRef, s)\n", __LINE__);
2056     }
2057     nsCOMPtr<nsIRunnable> r9 = NewRunnableMethod<Spy&>(
2058         "TestThreadUtils::ThreadUtilsObject::TestByLRef", rpt,
2059         &ThreadUtilsObject::TestByLRef, s);
2060     EXPECT_EQ(0, gAllConstructions);
2061     EXPECT_EQ(0, gDestructions);
2062     EXPECT_EQ(1, gAlive);
2063     Spy::ClearActions();
2064     if (gDebug) {
2065       printf("%d - Run()\n", __LINE__);
2066     }
2067     r9->Run();
2068     EXPECT_LE(1, gAssignments);  // Assignment from reference in call.
2069     EXPECT_EQ(40, rpt->mSpy.mID);
2070     EXPECT_EQ(&s, rpt->mSpyPtr);
2071     EXPECT_EQ(0, gDestructions);
2072     EXPECT_EQ(1, gAlive);  // Spy inside Test is not counted.
2073     Spy::ClearActions();
2074     if (gDebug) {
2075       printf("%d - End block with r\n", __LINE__);
2076     }
2077   }
2078   if (gDebug) {
2079     printf("%d - After end block with r\n", __LINE__);
2080   }
2081   EXPECT_EQ(1, gDestructions);
2082   EXPECT_EQ(0, gAlive);
2083 
2084   Spy::ClearAll();
2085   if (gDebug) {
2086     printf("%d - Test: Store nsRefPtr, pass by pointer\n", __LINE__);
2087   }
2088   {  // Block around nsCOMPtr lifetime.
2089     nsCOMPtr<nsIRunnable> r10;
2090     SpyWithISupports* ptr = 0;
2091     {  // Block around RefPtr<Spy> lifetime.
2092       if (gDebug) {
2093         printf("%d - RefPtr<SpyWithISupports> s(new SpyWithISupports(45))\n",
2094                __LINE__);
2095       }
2096       RefPtr<SpyWithISupports> s(new SpyWithISupports(45));
2097       ptr = s.get();
2098       EXPECT_EQ(1, gConstructions);
2099       EXPECT_EQ(1, gAlive);
2100       if (gDebug) {
2101         printf(
2102             "%d - r10 = "
2103             "NewRunnableMethod<StoreRefPtrPassByPtr<Spy>>(&TestByRRef, "
2104             "s.get())\n",
2105             __LINE__);
2106       }
2107       r10 = NewRunnableMethod<StoreRefPtrPassByPtr<SpyWithISupports>>(
2108           "TestThreadUtils::ThreadUtilsObject::TestByPointer", rpt,
2109           &ThreadUtilsObject::TestByPointer, s.get());
2110       EXPECT_LE(0, gAllConstructions);
2111       EXPECT_EQ(1, gAlive);
2112       Spy::ClearActions();
2113       if (gDebug) {
2114         printf("%d - End block with RefPtr<Spy> s\n", __LINE__);
2115       }
2116     }
2117     EXPECT_EQ(0, gDestructions);
2118     EXPECT_EQ(1, gAlive);
2119     Spy::ClearActions();
2120     if (gDebug) {
2121       printf("%d - Run()\n", __LINE__);
2122     }
2123     r10->Run();
2124     EXPECT_LE(1, gAssignments);  // Assignment from pointee in call.
2125     EXPECT_EQ(45, rpt->mSpy.mID);
2126     EXPECT_EQ(ptr, rpt->mSpyPtr);
2127     EXPECT_EQ(0, gDestructions);
2128     EXPECT_EQ(1, gAlive);  // Spy inside Test is not counted.
2129     Spy::ClearActions();
2130     if (gDebug) {
2131       printf("%d - End block with r\n", __LINE__);
2132     }
2133   }
2134   if (gDebug) {
2135     printf("%d - After end block with r\n", __LINE__);
2136   }
2137   EXPECT_EQ(1, gDestructions);
2138   EXPECT_EQ(0, gAlive);
2139 
2140   Spy::ClearAll();
2141   if (gDebug) {
2142     printf("%d - Test: Store pointer to lvalue, pass by pointer\n", __LINE__);
2143   }
2144   {
2145     if (gDebug) {
2146       printf("%d - Spy s(55)\n", __LINE__);
2147     }
2148     Spy s(55);
2149     EXPECT_EQ(1, gConstructions);
2150     EXPECT_EQ(1, gAlive);
2151     Spy::ClearActions();
2152     if (gDebug) {
2153       printf("%d - r11 = NewRunnableMethod<Spy*>(&TestByPointer, s)\n",
2154              __LINE__);
2155     }
2156     nsCOMPtr<nsIRunnable> r11 = NewRunnableMethod<Spy*>(
2157         "TestThreadUtils::ThreadUtilsObject::TestByPointer", rpt,
2158         &ThreadUtilsObject::TestByPointer, &s);
2159     EXPECT_EQ(0, gAllConstructions);
2160     EXPECT_EQ(0, gDestructions);
2161     EXPECT_EQ(1, gAlive);
2162     Spy::ClearActions();
2163     if (gDebug) {
2164       printf("%d - Run()\n", __LINE__);
2165     }
2166     r11->Run();
2167     EXPECT_LE(1, gAssignments);  // Assignment from pointee in call.
2168     EXPECT_EQ(55, rpt->mSpy.mID);
2169     EXPECT_EQ(&s, rpt->mSpyPtr);
2170     EXPECT_EQ(0, gDestructions);
2171     EXPECT_EQ(1, gAlive);  // Spy inside Test is not counted.
2172     Spy::ClearActions();
2173     if (gDebug) {
2174       printf("%d - End block with r\n", __LINE__);
2175     }
2176   }
2177   if (gDebug) {
2178     printf("%d - After end block with r\n", __LINE__);
2179   }
2180   EXPECT_EQ(1, gDestructions);
2181   EXPECT_EQ(0, gAlive);
2182 
2183   Spy::ClearAll();
2184   if (gDebug) {
2185     printf("%d - Test: Store pointer to const lvalue, pass by pointer\n",
2186            __LINE__);
2187   }
2188   {
2189     if (gDebug) {
2190       printf("%d - Spy s(60)\n", __LINE__);
2191     }
2192     Spy s(60);
2193     EXPECT_EQ(1, gConstructions);
2194     EXPECT_EQ(1, gAlive);
2195     Spy::ClearActions();
2196     if (gDebug) {
2197       printf("%d - r12 = NewRunnableMethod<Spy*>(&TestByPointer, s)\n",
2198              __LINE__);
2199     }
2200     nsCOMPtr<nsIRunnable> r12 = NewRunnableMethod<const Spy*>(
2201         "TestThreadUtils::ThreadUtilsObject::TestByPointerToConst", rpt,
2202         &ThreadUtilsObject::TestByPointerToConst, &s);
2203     EXPECT_EQ(0, gAllConstructions);
2204     EXPECT_EQ(0, gDestructions);
2205     EXPECT_EQ(1, gAlive);
2206     Spy::ClearActions();
2207     if (gDebug) {
2208       printf("%d - Run()\n", __LINE__);
2209     }
2210     r12->Run();
2211     EXPECT_LE(1, gAssignments);  // Assignment from pointee in call.
2212     EXPECT_EQ(60, rpt->mSpy.mID);
2213     EXPECT_EQ(&s, rpt->mSpyPtr);
2214     EXPECT_EQ(0, gDestructions);
2215     EXPECT_EQ(1, gAlive);  // Spy inside Test is not counted.
2216     Spy::ClearActions();
2217     if (gDebug) {
2218       printf("%d - End block with r\n", __LINE__);
2219     }
2220   }
2221   if (gDebug) {
2222     printf("%d - After end block with r\n", __LINE__);
2223   }
2224   EXPECT_EQ(1, gDestructions);
2225   EXPECT_EQ(0, gAlive);
2226 }
2227