xref: /aosp_15_r20/external/skia/tests/RefCntTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkRefCnt.h"
9 #include "include/core/SkTypes.h"
10 #include "include/private/SkWeakRefCnt.h"
11 #include "include/private/base/SkDebug.h"
12 #include "tests/Test.h"
13 
14 #include <thread>
15 #include <utility>
16 
bounce_ref(void * data)17 static void bounce_ref(void* data) {
18     SkRefCnt* ref = static_cast<SkRefCnt*>(data);
19     for (int i = 0; i < 100000; ++i) {
20         ref->ref();
21         ref->unref();
22     }
23 }
24 
test_refCnt(skiatest::Reporter * reporter)25 static void test_refCnt(skiatest::Reporter* reporter) {
26     SkRefCnt* ref = new SkRefCnt();
27 
28     std::thread thing1(bounce_ref, ref);
29     std::thread thing2(bounce_ref, ref);
30 
31     thing1.join();
32     thing2.join();
33 
34     REPORTER_ASSERT(reporter, ref->unique());
35     ref->unref();
36 }
37 
bounce_weak_ref(void * data)38 static void bounce_weak_ref(void* data) {
39     SkWeakRefCnt* ref = static_cast<SkWeakRefCnt*>(data);
40     for (int i = 0; i < 100000; ++i) {
41         if (ref->try_ref()) {
42             ref->unref();
43         }
44     }
45 }
46 
bounce_weak_weak_ref(void * data)47 static void bounce_weak_weak_ref(void* data) {
48     SkWeakRefCnt* ref = static_cast<SkWeakRefCnt*>(data);
49     for (int i = 0; i < 100000; ++i) {
50         ref->weak_ref();
51         ref->weak_unref();
52     }
53 }
54 
test_weakRefCnt(skiatest::Reporter * reporter)55 static void test_weakRefCnt(skiatest::Reporter* reporter) {
56     SkWeakRefCnt* ref = new SkWeakRefCnt();
57 
58     std::thread thing1(bounce_ref, ref);
59     std::thread thing2(bounce_ref, ref);
60     std::thread thing3(bounce_weak_ref, ref);
61     std::thread thing4(bounce_weak_weak_ref, ref);
62 
63     thing1.join();
64     thing2.join();
65     thing3.join();
66     thing4.join();
67 
68     REPORTER_ASSERT(reporter, ref->unique());
69     SkDEBUGCODE(REPORTER_ASSERT(reporter, ref->getWeakCnt() == 1));
70     ref->unref();
71 }
72 
DEF_TEST(RefCnt,reporter)73 DEF_TEST(RefCnt, reporter) {
74     test_refCnt(reporter);
75     test_weakRefCnt(reporter);
76 }
77 
78 ///////////////////////////////////////////////////////////////////////////////////////////////////
79 
80 static int gRefCounter;
81 static int gUnrefCounter;
82 static int gNewCounter;
83 static int gDeleteCounter;
84 
85 #define check(reporter, ref, unref, make, kill)        \
86     REPORTER_ASSERT(reporter, gRefCounter == ref);     \
87     REPORTER_ASSERT(reporter, gUnrefCounter == unref); \
88     REPORTER_ASSERT(reporter, gNewCounter == make);    \
89     REPORTER_ASSERT(reporter, gDeleteCounter == kill)
90 
91 class Effect {
92 public:
Effect()93     Effect() : fRefCnt(1) {
94         gNewCounter += 1;
95     }
~Effect()96     virtual ~Effect() {}
97 
98     int fRefCnt;
99 
ref()100     void ref() {
101         gRefCounter += 1;
102         fRefCnt += 1;
103     }
unref()104     void unref() {
105         gUnrefCounter += 1;
106 
107         SkASSERT(fRefCnt > 0);
108         if (0 == --fRefCnt) {
109             gDeleteCounter += 1;
110             delete this;
111         }
112     }
113 
method() const114     int* method() const { return new int; }
115 };
116 
Create()117 static sk_sp<Effect> Create() {
118     return sk_make_sp<Effect>();
119 }
120 
121 class Paint {
122 public:
123     sk_sp<Effect> fEffect;
124 
get() const125     const sk_sp<Effect>& get() const { return fEffect; }
126 
set(sk_sp<Effect> value)127     void set(sk_sp<Effect> value) {
128         fEffect = std::move(value);
129     }
130 };
131 
132 struct EffectImpl : public Effect {
~EffectImplEffectImpl133     ~EffectImpl() override {}
134 
CreateEffectImpl135     static sk_sp<EffectImpl> Create() {
136         return sk_sp<EffectImpl>(new EffectImpl);
137     }
138     int fValue;
139 };
make_effect()140 static sk_sp<Effect> make_effect() {
141     auto foo = EffectImpl::Create();
142     foo->fValue = 42;
143     return foo;
144 }
145 
reset_counters()146 static void reset_counters() {
147     gRefCounter = 0;
148     gUnrefCounter = 0;
149     gNewCounter = 0;
150     gDeleteCounter = 0;
151 }
DEF_TEST(sk_sp,reporter)152 DEF_TEST(sk_sp, reporter) {
153     reset_counters();
154 
155     Paint paint;
156     REPORTER_ASSERT(reporter, paint.fEffect.get() == nullptr);
157     REPORTER_ASSERT(reporter, !paint.get());
158     check(reporter, 0, 0, 0, 0);
159 
160     paint.set(Create());
161     check(reporter, 0, 0, 1, 0);
162     REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 1);
163 
164     if (paint.get()) {
165         REPORTER_ASSERT(reporter, true);
166     } else {
167         REPORTER_ASSERT(reporter, false);
168     }
169     if (!paint.get()) {
170         REPORTER_ASSERT(reporter, false);
171     } else {
172         REPORTER_ASSERT(reporter, true);
173     }
174 
175     paint.set(nullptr);
176     check(reporter, 0, 1, 1, 1);
177 
178     if (paint.get()) {
179         REPORTER_ASSERT(reporter, false);
180     } else {
181         REPORTER_ASSERT(reporter, true);
182     }
183     if (!paint.get()) {
184         REPORTER_ASSERT(reporter, true);
185     } else {
186         REPORTER_ASSERT(reporter, false);
187     }
188 
189     auto e = Create();
190     REPORTER_ASSERT(reporter, sizeof(e) == sizeof(void*));
191 
192     check(reporter, 0, 1, 2, 1);
193     paint.set(e);
194     check(reporter, 1, 1, 2, 1);
195     REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 2);
196 
197     Paint paint2;
198     paint2.set(paint.get());
199     check(reporter, 2, 1, 2, 1);
200     REPORTER_ASSERT(reporter, paint.fEffect.get()->fRefCnt == 3);
201 
202     // Test sk_sp::operator->
203     delete paint.get()->method();
204     check(reporter, 2, 1, 2, 1);
205 
206     // Test sk_sp::operator*
207     delete (*paint.get()).method();
208     check(reporter, 2, 1, 2, 1);
209 
210     paint.set(nullptr);
211     e = nullptr;
212     paint2.set(nullptr);
213     check(reporter, 2, 4, 2, 2);
214 
215     reset_counters();
216     {
217         // Test convertible sk_sp assignment.
218         check(reporter, 0, 0, 0, 0);
219         sk_sp<Effect> foo(nullptr);
220         REPORTER_ASSERT(reporter, !foo);
221         foo = make_effect();
222         REPORTER_ASSERT(reporter, foo);
223         check(reporter, 0, 0, 1, 0);
224     }
225     check(reporter, 0, 1, 1, 1);
226 
227     // Test passing convertible rvalue into funtion.
228     reset_counters();
229     paint.set(EffectImpl::Create());
230     check(reporter, 0, 0, 1, 0);
231     paint.set(nullptr);
232     check(reporter, 0, 1, 1, 1);
233 
234     reset_counters();
235     auto baz = EffectImpl::Create();
236     check(reporter, 0, 0, 1, 0);
237     paint.set(std::move(baz));
238     check(reporter, 0, 0, 1, 0);
239     REPORTER_ASSERT(reporter, !baz);  // NOLINT(bugprone-use-after-move)
240     paint.set(nullptr);
241     check(reporter, 0, 1, 1, 1);
242 
243     reset_counters();
244     {
245         // test comparison operator with convertible type.
246         sk_sp<EffectImpl> bar1 = EffectImpl::Create();
247         sk_sp<Effect> bar2(bar1);  // convertible copy constructor
248         check(reporter, 1, 0, 1, 0);
249         REPORTER_ASSERT(reporter, bar1);
250         REPORTER_ASSERT(reporter, bar2);
251         REPORTER_ASSERT(reporter, bar1 == bar2);
252         REPORTER_ASSERT(reporter, bar2 == bar1);
253         REPORTER_ASSERT(reporter, !(bar1 != bar2));
254         REPORTER_ASSERT(reporter, !(bar2 != bar1));
255         sk_sp<Effect> bar3(nullptr);
256         bar3 = bar1;  // convertible copy assignment
257         check(reporter, 2, 0, 1, 0);
258 
259     }
260     check(reporter, 2, 3, 1, 1);
261 
262     // test passing convertible copy into funtion.
263     reset_counters();
264     baz = EffectImpl::Create();
265     check(reporter, 0, 0, 1, 0);
266     paint.set(baz);
267     check(reporter, 1, 0, 1, 0);
268     baz = nullptr;
269     check(reporter, 1, 1, 1, 0);
270     paint.set(nullptr);
271     check(reporter, 1, 2, 1, 1);
272 
273     {
274         sk_sp<SkRefCnt> empty;
275         sk_sp<SkRefCnt> notEmpty = sk_make_sp<SkRefCnt>();
276         REPORTER_ASSERT(reporter, empty == sk_sp<SkRefCnt>());
277 
278         REPORTER_ASSERT(reporter, notEmpty != empty);
279         REPORTER_ASSERT(reporter, empty != notEmpty);
280 
281         REPORTER_ASSERT(reporter, nullptr == empty);
282         REPORTER_ASSERT(reporter, empty == nullptr);
283         REPORTER_ASSERT(reporter, empty == empty);
284     }
285 
286     {
287         sk_sp<SkRefCnt> a = sk_make_sp<SkRefCnt>();
288         sk_sp<SkRefCnt> b = sk_make_sp<SkRefCnt>();
289         REPORTER_ASSERT(reporter, a != b);
290         REPORTER_ASSERT(reporter, a == a);
291     }
292 
293     // http://wg21.cmeerw.net/lwg/issue998
294     {
295         class foo : public SkRefCnt {
296         public:
297             foo() : bar(this) {}
298             void reset() { bar.reset(); }
299         private:
300             sk_sp<foo> bar;
301         };
302         // The following should properly delete the object and not cause undefined behavior.
303         // This is an ugly example, but the same issue can arise in more subtle ways.
304         (new foo)->reset();
305     }
306 
307     // https://crrev.com/0d4ef2583a6f19c3e61be04d36eb1a60b133832c
308     {
309         struct StructB;
310         struct StructA : public SkRefCnt {
311             sk_sp<StructB> b;
312         };
313 
314         struct StructB : public SkRefCnt {
315             sk_sp<StructA> a;
316             ~StructB() override {} // Some clang versions don't emit this implicitly.
317         };
318 
319         // Create a reference cycle.
320         StructA* a = new StructA;
321         a->b.reset(new StructB);
322         a->b->a.reset(a);
323 
324         // Break the cycle by calling reset(). This will cause |a| (and hence, |a.b|)
325         // to be deleted before the call to reset() returns. This tests that the
326         // implementation of sk_sp::reset() doesn't access |this| after it
327         // deletes the underlying pointer. This behaviour is consistent with the
328         // definition of unique_ptr::reset in C++11.
329         a->b.reset();
330     }
331 }
332 
333 namespace {
334 struct FooAbstract : public SkRefCnt {
335     virtual void f() = 0;
336 };
337 struct FooConcrete : public FooAbstract {
f__anonfaee02530111::FooConcrete338     void f() override {}
339 };
340 }  // namespace
make_foo()341 static sk_sp<FooAbstract> make_foo() {
342     // can not cast FooConcrete to FooAbstract.
343     // can cast FooConcrete* to FooAbstract*.
344     return sk_make_sp<FooConcrete>();
345 }
DEF_TEST(sk_make_sp,r)346 DEF_TEST(sk_make_sp, r) {
347     auto x = make_foo();
348 }
349 
350 // Test that reset() "adopts" ownership from the caller, even if we are given the same ptr twice
351 //
DEF_TEST(sk_sp_reset,r)352 DEF_TEST(sk_sp_reset, r) {
353     SkRefCnt* rc = new SkRefCnt;
354     REPORTER_ASSERT(r, rc->unique());
355 
356     sk_sp<SkRefCnt> sp;
357     sp.reset(rc);
358     // We have transfered our ownership over to sp
359     REPORTER_ASSERT(r, rc->unique());
360 
361     rc->ref();  // now "rc" is also an owner
362     REPORTER_ASSERT(r, !rc->unique());
363 
364     sp.reset(rc);   // this should transfer our ownership over to sp
365     REPORTER_ASSERT(r, rc->unique());
366 }
367 
DEF_TEST(sk_sp_ref,r)368 DEF_TEST(sk_sp_ref, r) {
369     SkRefCnt* rc = new SkRefCnt;
370     REPORTER_ASSERT(r, rc->unique());
371 
372     {
373         sk_sp<SkRefCnt> sp = sk_ref_sp(rc);
374         REPORTER_ASSERT(r, !rc->unique());
375     }
376 
377     REPORTER_ASSERT(r, rc->unique());
378     rc->unref();
379 }
380