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