1 | /* Unit tests for GCC's garbage collector (and gengtype etc). |
2 | Copyright (C) 2015-2023 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free |
8 | Software Foundation; either version 3, or (at your option) any later |
9 | version. |
10 | |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | #include "config.h" |
21 | #include "system.h" |
22 | #include "coretypes.h" |
23 | #include "tree-core.h" |
24 | #include "tree.h" |
25 | #include "selftest.h" |
26 | |
27 | #if CHECKING_P |
28 | |
29 | /* The various GTY markers must be outside of a namespace to be seen by |
30 | gengtype, so we don't put this file within the selftest namespace. */ |
31 | |
32 | |
33 | |
34 | /* Verify that a simple struct works, and that it can |
35 | own references to non-roots, and have them be marked. */ |
36 | |
37 | struct GTY(()) test_struct |
38 | { |
39 | struct test_struct *other; |
40 | }; |
41 | |
42 | static GTY(()) test_struct *root_test_struct; |
43 | |
44 | static void |
45 | test_basic_struct () |
46 | { |
47 | root_test_struct = ggc_cleared_alloc <test_struct> (); |
48 | root_test_struct->other = ggc_cleared_alloc <test_struct> (); |
49 | |
50 | ggc_collect (mode: GGC_COLLECT_FORCE); |
51 | |
52 | ASSERT_TRUE (ggc_marked_p (root_test_struct)); |
53 | ASSERT_TRUE (ggc_marked_p (root_test_struct->other)); |
54 | } |
55 | |
56 | |
57 | |
58 | /* Selftest for GTY((length)). */ |
59 | |
60 | /* A test struct using GTY((length)). */ |
61 | |
62 | struct GTY(()) test_of_length |
63 | { |
64 | int num_elem; |
65 | struct test_of_length * GTY ((length ("%h.num_elem" ))) elem[1]; |
66 | }; |
67 | |
68 | static GTY(()) test_of_length *root_test_of_length; |
69 | |
70 | static void |
71 | test_length () |
72 | { |
73 | const int count = 5; |
74 | size_t sz = sizeof (test_of_length) + (count- 1) * sizeof (test_of_length *); |
75 | root_test_of_length = (test_of_length *)ggc_internal_cleared_alloc (s: sz); |
76 | root_test_of_length->num_elem = count; |
77 | for (int i = 0; i < count; i++) |
78 | root_test_of_length->elem[i] = ggc_cleared_alloc <test_of_length> (); |
79 | |
80 | ggc_collect (mode: GGC_COLLECT_FORCE); |
81 | |
82 | ASSERT_TRUE (ggc_marked_p (root_test_of_length)); |
83 | for (int i = 0; i < count; i++) |
84 | ASSERT_TRUE (ggc_marked_p (root_test_of_length->elem[i])); |
85 | } |
86 | |
87 | |
88 | |
89 | /* Selftest for unions, GTY((tag)), and GTY((desc)). */ |
90 | |
91 | /* A struct with a reference that's an a different offset to test_struct, |
92 | to ensure that we're using the correct types. */ |
93 | |
94 | struct GTY(()) test_other |
95 | { |
96 | char dummy[256]; |
97 | test_struct *m_ptr; |
98 | }; |
99 | |
100 | enum which_field |
101 | { |
102 | WHICH_FIELD_USE_TEST_STRUCT, |
103 | WHICH_FIELD_USE_TEST_OTHER |
104 | }; |
105 | |
106 | /* An example function for use by a GTY((desc)) marker. */ |
107 | |
108 | static enum which_field |
109 | calc_desc (int kind) |
110 | { |
111 | switch (kind) |
112 | { |
113 | case 0: return WHICH_FIELD_USE_TEST_STRUCT; |
114 | case 1: return WHICH_FIELD_USE_TEST_OTHER; |
115 | default: |
116 | gcc_unreachable (); |
117 | } |
118 | } |
119 | |
120 | /* A struct containing an example of a union, showing the "tag" and |
121 | "desc" markers. */ |
122 | |
123 | struct GTY(()) test_of_union |
124 | { |
125 | int m_kind; |
126 | union u { |
127 | test_struct * GTY ((tag ("WHICH_FIELD_USE_TEST_STRUCT" ) )) u_test_struct; |
128 | test_other * GTY ((tag ("WHICH_FIELD_USE_TEST_OTHER" ) )) u_test_other; |
129 | } GTY ((desc ("calc_desc (%0.m_kind)" ))) m_u; |
130 | }; |
131 | |
132 | /* Example roots. */ |
133 | |
134 | static GTY(()) test_of_union *root_test_of_union_1; |
135 | static GTY(()) test_of_union *root_test_of_union_2; |
136 | |
137 | /* Verify that the above work correctly. */ |
138 | |
139 | static void |
140 | test_union () |
141 | { |
142 | root_test_of_union_1 = ggc_cleared_alloc <test_of_union> (); |
143 | root_test_of_union_1->m_kind = 0; |
144 | test_struct *ts = ggc_cleared_alloc <test_struct> (); |
145 | root_test_of_union_1->m_u.u_test_struct = ts; |
146 | |
147 | root_test_of_union_2 = ggc_cleared_alloc <test_of_union> (); |
148 | root_test_of_union_2->m_kind = 1; |
149 | test_other *other = ggc_cleared_alloc <test_other> (); |
150 | root_test_of_union_2->m_u.u_test_other = other; |
151 | test_struct *referenced_by_other = ggc_cleared_alloc <test_struct> (); |
152 | other->m_ptr = referenced_by_other; |
153 | |
154 | ggc_collect (mode: GGC_COLLECT_FORCE); |
155 | |
156 | ASSERT_TRUE (ggc_marked_p (root_test_of_union_1)); |
157 | ASSERT_TRUE (ggc_marked_p (ts)); |
158 | |
159 | ASSERT_TRUE (ggc_marked_p (root_test_of_union_2)); |
160 | ASSERT_TRUE (ggc_marked_p (other)); |
161 | ASSERT_TRUE (ggc_marked_p (referenced_by_other)); |
162 | } |
163 | |
164 | |
165 | |
166 | /* Verify that destructors get run when instances are collected. */ |
167 | |
168 | class GTY(()) test_struct_with_dtor |
169 | { |
170 | public: |
171 | /* This struct has a destructor; it *ought* to be called |
172 | by the ggc machinery when instances are collected. */ |
173 | ~test_struct_with_dtor () { dtor_call_count++; } |
174 | |
175 | static int dtor_call_count; |
176 | }; |
177 | |
178 | int test_struct_with_dtor::dtor_call_count; |
179 | |
180 | static void |
181 | test_finalization () |
182 | { |
183 | #if GCC_VERSION >= 4003 |
184 | ASSERT_FALSE (need_finalization_p <test_struct> ()); |
185 | ASSERT_TRUE (need_finalization_p <test_struct_with_dtor> ()); |
186 | #endif |
187 | |
188 | /* Create some garbage. */ |
189 | const int count = 10; |
190 | for (int i = 0; i < count; i++) |
191 | ggc_cleared_alloc <test_struct_with_dtor> (); |
192 | |
193 | test_struct_with_dtor::dtor_call_count = 0; |
194 | |
195 | ggc_collect (mode: GGC_COLLECT_FORCE); |
196 | |
197 | /* Verify that the destructor was run for each instance. */ |
198 | ASSERT_EQ (count, test_struct_with_dtor::dtor_call_count); |
199 | } |
200 | |
201 | |
202 | |
203 | /* Verify that a global can be marked as "deletable". */ |
204 | |
205 | static GTY((deletable)) test_struct *test_of_deletable; |
206 | |
207 | static void |
208 | test_deletable_global () |
209 | { |
210 | test_of_deletable = ggc_cleared_alloc <test_struct> (); |
211 | ASSERT_TRUE (test_of_deletable != NULL); |
212 | |
213 | ggc_collect (mode: GGC_COLLECT_FORCE); |
214 | |
215 | ASSERT_EQ (NULL, test_of_deletable); |
216 | } |
217 | |
218 | |
219 | |
220 | /* Verify that gengtype etc can cope with inheritance. */ |
221 | |
222 | class GTY((desc("%h.m_kind" ), tag("0" ))) example_base |
223 | { |
224 | public: |
225 | example_base () |
226 | : m_kind (0), |
227 | m_a (ggc_cleared_alloc <test_struct> ()) |
228 | {} |
229 | |
230 | void * |
231 | operator new (size_t sz) |
232 | { |
233 | return ggc_internal_cleared_alloc (s: sz); |
234 | } |
235 | |
236 | protected: |
237 | example_base (int kind) |
238 | : m_kind (kind), |
239 | m_a (ggc_cleared_alloc <test_struct> ()) |
240 | {} |
241 | |
242 | public: |
243 | int m_kind; |
244 | test_struct *m_a; |
245 | }; |
246 | |
247 | class GTY((tag("1" ))) some_subclass : public example_base |
248 | { |
249 | public: |
250 | some_subclass () |
251 | : example_base (1), |
252 | m_b (ggc_cleared_alloc <test_struct> ()) |
253 | {} |
254 | |
255 | test_struct *m_b; |
256 | }; |
257 | |
258 | class GTY((tag("2" ))) some_other_subclass : public example_base |
259 | { |
260 | public: |
261 | some_other_subclass () |
262 | : example_base (2), |
263 | m_c (ggc_cleared_alloc <test_struct> ()) |
264 | {} |
265 | |
266 | test_struct *m_c; |
267 | }; |
268 | |
269 | /* Various test roots, both expressed as a ptr to the actual class, and |
270 | as a ptr to the base class. */ |
271 | static GTY(()) example_base *test_example_base; |
272 | static GTY(()) some_subclass *test_some_subclass; |
273 | static GTY(()) some_other_subclass *test_some_other_subclass; |
274 | static GTY(()) example_base *test_some_subclass_as_base_ptr; |
275 | static GTY(()) example_base *test_some_other_subclass_as_base_ptr; |
276 | |
277 | static void |
278 | test_inheritance () |
279 | { |
280 | test_example_base = new example_base (); |
281 | test_some_subclass = new some_subclass (); |
282 | test_some_other_subclass = new some_other_subclass (); |
283 | test_some_subclass_as_base_ptr = new some_subclass (); |
284 | test_some_other_subclass_as_base_ptr = new some_other_subclass (); |
285 | |
286 | ggc_collect (mode: GGC_COLLECT_FORCE); |
287 | |
288 | /* Verify that the roots and everything referenced by them got marked |
289 | (both for fields in the base class and those in subclasses). */ |
290 | ASSERT_TRUE (ggc_marked_p (test_example_base)); |
291 | ASSERT_TRUE (ggc_marked_p (test_example_base->m_a)); |
292 | |
293 | ASSERT_TRUE (ggc_marked_p (test_some_subclass)); |
294 | ASSERT_TRUE (ggc_marked_p (test_some_subclass->m_a)); |
295 | ASSERT_TRUE (ggc_marked_p (test_some_subclass->m_b)); |
296 | |
297 | ASSERT_TRUE (ggc_marked_p (test_some_other_subclass)); |
298 | ASSERT_TRUE (ggc_marked_p (test_some_other_subclass->m_a)); |
299 | ASSERT_TRUE (ggc_marked_p (test_some_other_subclass->m_c)); |
300 | |
301 | ASSERT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr)); |
302 | ASSERT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr->m_a)); |
303 | ASSERT_TRUE (ggc_marked_p (((some_subclass *) |
304 | test_some_subclass_as_base_ptr)->m_b)); |
305 | |
306 | ASSERT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr)); |
307 | ASSERT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr->m_a)); |
308 | ASSERT_TRUE (ggc_marked_p (((some_other_subclass *) |
309 | test_some_other_subclass_as_base_ptr)->m_c)); |
310 | } |
311 | |
312 | |
313 | |
314 | /* Test of chain_next/chain_prev |
315 | |
316 | Construct a very long linked list, so that without |
317 | the chain_next/chain_prev optimization we'd have |
318 | a stack overflow when gt_ggc_mx_test_node recurses. */ |
319 | |
320 | struct GTY(( chain_next ("%h.m_next" ), |
321 | chain_prev ("%h.m_prev" ) )) test_node |
322 | { |
323 | test_node *m_prev; |
324 | test_node *m_next; |
325 | int m_idx; |
326 | }; |
327 | |
328 | static GTY(()) test_node *root_test_node; |
329 | |
330 | static void |
331 | test_chain_next () |
332 | { |
333 | /* Ideally we would construct a long list so that the number of |
334 | stack frames would be deep enough to crash if gengtype has created |
335 | something that recurses. |
336 | |
337 | However, as the list is lengthened to increase the chance of |
338 | overflowing the stack, the test will require more time and memory |
339 | to run. On a Fedora 20 x86_64 box with 128GB of RAM, count=2000000 |
340 | without the chain_next optimization reliably overflowed the stack, |
341 | but the test took 0.5s to run. |
342 | |
343 | For now this test runs with a low value for "count", which defeats |
344 | the main purpose of the test - though it at least gives us coverage |
345 | for walking a GTY((chain_next)) list. |
346 | |
347 | We could potentially increase this value once we have a better sense |
348 | of the time and space requirements of the test on different hosts, |
349 | or perhaps find a way to reduce the stack size when running this |
350 | testcase. */ |
351 | const int count = 10; |
352 | |
353 | /* Build the linked list. */ |
354 | root_test_node = ggc_cleared_alloc <test_node> (); |
355 | test_node *tail_node = root_test_node; |
356 | for (int i = 0; i < count; i++) |
357 | { |
358 | test_node *new_node = ggc_cleared_alloc <test_node> (); |
359 | tail_node->m_next = new_node; |
360 | new_node->m_prev = tail_node; |
361 | new_node->m_idx = i; |
362 | tail_node = new_node; |
363 | } |
364 | |
365 | ggc_collect (mode: GGC_COLLECT_FORCE); |
366 | |
367 | /* If we got here, we survived. */ |
368 | |
369 | /* Verify that all nodes in the list were marked. */ |
370 | ASSERT_TRUE (ggc_marked_p (root_test_node)); |
371 | test_node *iter_node = root_test_node->m_next; |
372 | for (int i = 0; i < count; i++) |
373 | { |
374 | ASSERT_TRUE (ggc_marked_p (iter_node)); |
375 | ASSERT_EQ (i, iter_node->m_idx); |
376 | iter_node = iter_node->m_next; |
377 | } |
378 | } |
379 | |
380 | |
381 | |
382 | /* Test for GTY((user)). */ |
383 | |
384 | struct GTY((user)) user_struct |
385 | { |
386 | char dummy[16]; |
387 | test_struct *m_ptr; |
388 | }; |
389 | |
390 | static GTY(()) user_struct *root_user_struct_ptr; |
391 | |
392 | /* A global for verifying that the user-provided gt_ggc_mx gets |
393 | called. */ |
394 | static int num_calls_to_user_gt_ggc_mx; |
395 | |
396 | /* User-provided implementation of gt_ggc_mx. */ |
397 | |
398 | static void |
399 | gt_ggc_mx (user_struct *p) |
400 | { |
401 | num_calls_to_user_gt_ggc_mx++; |
402 | gt_ggc_mx_test_struct (p->m_ptr); |
403 | } |
404 | |
405 | /* User-provided implementation of gt_pch_nx. */ |
406 | |
407 | static void |
408 | gt_pch_nx (user_struct *p) |
409 | { |
410 | gt_pch_nx_test_struct (p->m_ptr); |
411 | } |
412 | |
413 | /* User-provided implementation of gt_pch_nx. */ |
414 | |
415 | static void |
416 | gt_pch_nx (user_struct *p, gt_pointer_operator op, void *cookie) |
417 | { |
418 | op (&(p->m_ptr), NULL, cookie); |
419 | } |
420 | |
421 | /* Verify that GTY((user)) works. */ |
422 | |
423 | static void |
424 | test_user_struct () |
425 | { |
426 | root_user_struct_ptr = ggc_cleared_alloc <user_struct> (); |
427 | test_struct *referenced = ggc_cleared_alloc <test_struct> (); |
428 | root_user_struct_ptr->m_ptr = referenced; |
429 | |
430 | num_calls_to_user_gt_ggc_mx = 0; |
431 | |
432 | ggc_collect (mode: GGC_COLLECT_FORCE); |
433 | |
434 | ASSERT_TRUE (ggc_marked_p (root_user_struct_ptr)); |
435 | ASSERT_TRUE (ggc_marked_p (referenced)); |
436 | ASSERT_TRUE (num_calls_to_user_gt_ggc_mx > 0); |
437 | } |
438 | |
439 | |
440 | |
441 | /* Smoketest to ensure that the tree type is marked. */ |
442 | |
443 | static GTY(()) tree dummy_unittesting_tree; |
444 | |
445 | static void |
446 | test_tree_marking () |
447 | { |
448 | dummy_unittesting_tree = build_int_cst (integer_type_node, 1066); |
449 | |
450 | ggc_collect (mode: GGC_COLLECT_FORCE); |
451 | |
452 | ASSERT_TRUE (ggc_marked_p (dummy_unittesting_tree)); |
453 | } |
454 | |
455 | |
456 | |
457 | /* Ideas for other tests: |
458 | - pch-handling */ |
459 | |
460 | namespace selftest { |
461 | |
462 | /* Run all of the selftests within this file. */ |
463 | |
464 | void |
465 | ggc_tests_cc_tests () |
466 | { |
467 | test_basic_struct (); |
468 | test_length (); |
469 | test_union (); |
470 | test_finalization (); |
471 | test_deletable_global (); |
472 | test_inheritance (); |
473 | test_chain_next (); |
474 | test_user_struct (); |
475 | test_tree_marking (); |
476 | } |
477 | |
478 | } // namespace selftest |
479 | |
480 | #include "gt-ggc-tests.h" |
481 | |
482 | #else /* #if CHECKING_P */ |
483 | |
484 | /* The #if CHECKING_P code above has various GTY-marked roots. |
485 | gengtype has no knowledge of the preprocessor, and so detects |
486 | these roots and writes them out to gt-ggc-tests.h. |
487 | In a !CHECKING_P build we can ignore gt-ggc-tests.h, but the |
488 | root tables are referenced in the various generated gtype-*.c |
489 | files like this: |
490 | |
491 | ...snip... |
492 | extern const struct ggc_root_tab gt_ggc_r_gt_ggc_tests_h[]; |
493 | ...snip... |
494 | |
495 | EXPORTED_CONST struct ggc_root_tab * const gt_ggc_rtab[] = { |
496 | ...snip... |
497 | gt_ggc_r_gt_ggc_tests_h, |
498 | ...snip... |
499 | }; |
500 | |
501 | Hence to avoid a link failure, we provide dummy implementations |
502 | of these root tables in an unchecked build. |
503 | |
504 | Note that these conditional roots imply that PCH files are |
505 | incompatible between checked and unchecked builds. */ |
506 | |
507 | EXPORTED_CONST struct ggc_root_tab gt_ggc_r_gt_ggc_tests_h[] = { |
508 | LAST_GGC_ROOT_TAB |
509 | }; |
510 | |
511 | EXPORTED_CONST struct ggc_root_tab gt_ggc_rd_gt_ggc_tests_h[] = { |
512 | LAST_GGC_ROOT_TAB |
513 | }; |
514 | |
515 | #endif /* #else clause of #if CHECKING_P */ |
516 | |