1/* Unit tests for GCC's garbage collector (and gengtype etc).
2 Copyright (C) 2015-2023 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along 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
37struct GTY(()) test_struct
38{
39 struct test_struct *other;
40};
41
42static GTY(()) test_struct *root_test_struct;
43
44static void
45test_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
62struct GTY(()) test_of_length
63{
64 int num_elem;
65 struct test_of_length * GTY ((length ("%h.num_elem"))) elem[1];
66};
67
68static GTY(()) test_of_length *root_test_of_length;
69
70static void
71test_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
94struct GTY(()) test_other
95{
96 char dummy[256];
97 test_struct *m_ptr;
98};
99
100enum 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
108static enum which_field
109calc_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
123struct 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
134static GTY(()) test_of_union *root_test_of_union_1;
135static GTY(()) test_of_union *root_test_of_union_2;
136
137/* Verify that the above work correctly. */
138
139static void
140test_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
168class GTY(()) test_struct_with_dtor
169{
170public:
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
178int test_struct_with_dtor::dtor_call_count;
179
180static void
181test_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
205static GTY((deletable)) test_struct *test_of_deletable;
206
207static void
208test_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
222class 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
247class 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
258class 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. */
271static GTY(()) example_base *test_example_base;
272static GTY(()) some_subclass *test_some_subclass;
273static GTY(()) some_other_subclass *test_some_other_subclass;
274static GTY(()) example_base *test_some_subclass_as_base_ptr;
275static GTY(()) example_base *test_some_other_subclass_as_base_ptr;
276
277static void
278test_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
320struct 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
328static GTY(()) test_node *root_test_node;
329
330static void
331test_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
384struct GTY((user)) user_struct
385{
386 char dummy[16];
387 test_struct *m_ptr;
388};
389
390static GTY(()) user_struct *root_user_struct_ptr;
391
392/* A global for verifying that the user-provided gt_ggc_mx gets
393 called. */
394static int num_calls_to_user_gt_ggc_mx;
395
396/* User-provided implementation of gt_ggc_mx. */
397
398static void
399gt_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
407static void
408gt_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
415static void
416gt_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
423static void
424test_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
443static GTY(()) tree dummy_unittesting_tree;
444
445static void
446test_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
460namespace selftest {
461
462/* Run all of the selftests within this file. */
463
464void
465ggc_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
507EXPORTED_CONST struct ggc_root_tab gt_ggc_r_gt_ggc_tests_h[] = {
508 LAST_GGC_ROOT_TAB
509};
510
511EXPORTED_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

source code of gcc/ggc-tests.cc