Branch data Line data Source code
1 : : /* Unit tests for GCC's garbage collector (and gengtype etc).
2 : : Copyright (C) 2015-2024 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 : 4 : test_basic_struct ()
46 : : {
47 : 4 : root_test_struct = ggc_cleared_alloc <test_struct> ();
48 : 4 : root_test_struct->other = ggc_cleared_alloc <test_struct> ();
49 : :
50 : 4 : ggc_collect (GGC_COLLECT_FORCE);
51 : :
52 : 4 : ASSERT_TRUE (ggc_marked_p (root_test_struct));
53 : 4 : ASSERT_TRUE (ggc_marked_p (root_test_struct->other));
54 : 4 : }
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 : 4 : test_length ()
72 : : {
73 : 4 : const int count = 5;
74 : 4 : size_t sz = sizeof (test_of_length) + (count- 1) * sizeof (test_of_length *);
75 : 4 : root_test_of_length = (test_of_length *)ggc_internal_cleared_alloc (sz);
76 : 4 : root_test_of_length->num_elem = count;
77 : 24 : for (int i = 0; i < count; i++)
78 : 20 : root_test_of_length->elem[i] = ggc_cleared_alloc <test_of_length> ();
79 : :
80 : 4 : ggc_collect (GGC_COLLECT_FORCE);
81 : :
82 : 4 : ASSERT_TRUE (ggc_marked_p (root_test_of_length));
83 : 24 : for (int i = 0; i < count; i++)
84 : 20 : ASSERT_TRUE (ggc_marked_p (root_test_of_length->elem[i]));
85 : 4 : }
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 : 88 : calc_desc (int kind)
110 : : {
111 : 88 : switch (kind)
112 : : {
113 : : case 0: return WHICH_FIELD_USE_TEST_STRUCT;
114 : 44 : case 1: return WHICH_FIELD_USE_TEST_OTHER;
115 : 0 : default:
116 : 0 : 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 : 4 : test_union ()
141 : : {
142 : 4 : root_test_of_union_1 = ggc_cleared_alloc <test_of_union> ();
143 : 4 : root_test_of_union_1->m_kind = 0;
144 : 4 : test_struct *ts = ggc_cleared_alloc <test_struct> ();
145 : 4 : root_test_of_union_1->m_u.u_test_struct = ts;
146 : :
147 : 4 : root_test_of_union_2 = ggc_cleared_alloc <test_of_union> ();
148 : 4 : root_test_of_union_2->m_kind = 1;
149 : 4 : test_other *other = ggc_cleared_alloc <test_other> ();
150 : 4 : root_test_of_union_2->m_u.u_test_other = other;
151 : 4 : test_struct *referenced_by_other = ggc_cleared_alloc <test_struct> ();
152 : 4 : other->m_ptr = referenced_by_other;
153 : :
154 : 4 : ggc_collect (GGC_COLLECT_FORCE);
155 : :
156 : 4 : ASSERT_TRUE (ggc_marked_p (root_test_of_union_1));
157 : 4 : ASSERT_TRUE (ggc_marked_p (ts));
158 : :
159 : 4 : ASSERT_TRUE (ggc_marked_p (root_test_of_union_2));
160 : 4 : ASSERT_TRUE (ggc_marked_p (other));
161 : 4 : ASSERT_TRUE (ggc_marked_p (referenced_by_other));
162 : 4 : }
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 : 40 : ~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 : 4 : test_finalization ()
182 : : {
183 : : #if GCC_VERSION >= 4003
184 : 4 : ASSERT_FALSE (need_finalization_p <test_struct> ());
185 : 4 : ASSERT_TRUE (need_finalization_p <test_struct_with_dtor> ());
186 : : #endif
187 : :
188 : : /* Create some garbage. */
189 : 4 : const int count = 10;
190 : 44 : for (int i = 0; i < count; i++)
191 : 40 : ggc_cleared_alloc <test_struct_with_dtor> ();
192 : :
193 : 4 : test_struct_with_dtor::dtor_call_count = 0;
194 : :
195 : 4 : ggc_collect (GGC_COLLECT_FORCE);
196 : :
197 : : /* Verify that the destructor was run for each instance. */
198 : 4 : ASSERT_EQ (count, test_struct_with_dtor::dtor_call_count);
199 : 4 : }
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 : 4 : test_deletable_global ()
209 : : {
210 : 4 : test_of_deletable = ggc_cleared_alloc <test_struct> ();
211 : 4 : ASSERT_TRUE (test_of_deletable != NULL);
212 : :
213 : 4 : ggc_collect (GGC_COLLECT_FORCE);
214 : :
215 : 4 : ASSERT_EQ (NULL, test_of_deletable);
216 : 4 : }
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 : 4 : example_base ()
226 : 4 : : m_kind (0),
227 : 8 : m_a (ggc_cleared_alloc <test_struct> ())
228 : : {}
229 : :
230 : : void *
231 : 20 : operator new (size_t sz)
232 : : {
233 : 40 : return ggc_internal_cleared_alloc (sz);
234 : : }
235 : :
236 : : protected:
237 : 16 : example_base (int kind)
238 : 16 : : m_kind (kind),
239 : 32 : 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 : 8 : some_subclass ()
251 : 8 : : example_base (1),
252 : 8 : m_b (ggc_cleared_alloc <test_struct> ())
253 : 8 : {}
254 : :
255 : : test_struct *m_b;
256 : : };
257 : :
258 : : class GTY((tag("2"))) some_other_subclass : public example_base
259 : : {
260 : : public:
261 : 8 : some_other_subclass ()
262 : 8 : : example_base (2),
263 : 8 : m_c (ggc_cleared_alloc <test_struct> ())
264 : 8 : {}
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 : 4 : test_inheritance ()
279 : : {
280 : 4 : test_example_base = new example_base ();
281 : 4 : test_some_subclass = new some_subclass ();
282 : 4 : test_some_other_subclass = new some_other_subclass ();
283 : 4 : test_some_subclass_as_base_ptr = new some_subclass ();
284 : 4 : test_some_other_subclass_as_base_ptr = new some_other_subclass ();
285 : :
286 : 4 : ggc_collect (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 : 4 : ASSERT_TRUE (ggc_marked_p (test_example_base));
291 : 4 : ASSERT_TRUE (ggc_marked_p (test_example_base->m_a));
292 : :
293 : 4 : ASSERT_TRUE (ggc_marked_p (test_some_subclass));
294 : 4 : ASSERT_TRUE (ggc_marked_p (test_some_subclass->m_a));
295 : 4 : ASSERT_TRUE (ggc_marked_p (test_some_subclass->m_b));
296 : :
297 : 4 : ASSERT_TRUE (ggc_marked_p (test_some_other_subclass));
298 : 4 : ASSERT_TRUE (ggc_marked_p (test_some_other_subclass->m_a));
299 : 4 : ASSERT_TRUE (ggc_marked_p (test_some_other_subclass->m_c));
300 : :
301 : 4 : ASSERT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr));
302 : 4 : ASSERT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr->m_a));
303 : 4 : ASSERT_TRUE (ggc_marked_p (((some_subclass *)
304 : : test_some_subclass_as_base_ptr)->m_b));
305 : :
306 : 4 : ASSERT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr));
307 : 4 : ASSERT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr->m_a));
308 : 4 : ASSERT_TRUE (ggc_marked_p (((some_other_subclass *)
309 : : test_some_other_subclass_as_base_ptr)->m_c));
310 : 4 : }
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 : 4 : 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 : 4 : const int count = 10;
352 : :
353 : : /* Build the linked list. */
354 : 4 : root_test_node = ggc_cleared_alloc <test_node> ();
355 : 4 : test_node *tail_node = root_test_node;
356 : 44 : for (int i = 0; i < count; i++)
357 : : {
358 : 40 : test_node *new_node = ggc_cleared_alloc <test_node> ();
359 : 40 : tail_node->m_next = new_node;
360 : 40 : new_node->m_prev = tail_node;
361 : 40 : new_node->m_idx = i;
362 : 40 : tail_node = new_node;
363 : : }
364 : :
365 : 4 : ggc_collect (GGC_COLLECT_FORCE);
366 : :
367 : : /* If we got here, we survived. */
368 : :
369 : : /* Verify that all nodes in the list were marked. */
370 : 4 : ASSERT_TRUE (ggc_marked_p (root_test_node));
371 : 4 : test_node *iter_node = root_test_node->m_next;
372 : 44 : for (int i = 0; i < count; i++)
373 : : {
374 : 40 : ASSERT_TRUE (ggc_marked_p (iter_node));
375 : 40 : ASSERT_EQ (i, iter_node->m_idx);
376 : 40 : iter_node = iter_node->m_next;
377 : : }
378 : 4 : }
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 : 24 : gt_ggc_mx (user_struct *p)
400 : : {
401 : 24 : num_calls_to_user_gt_ggc_mx++;
402 : 24 : gt_ggc_mx_test_struct (p->m_ptr);
403 : 24 : }
404 : :
405 : : /* User-provided implementation of gt_pch_nx. */
406 : :
407 : : static void
408 : 0 : gt_pch_nx (user_struct *p)
409 : : {
410 : 0 : gt_pch_nx_test_struct (p->m_ptr);
411 : 0 : }
412 : :
413 : : /* User-provided implementation of gt_pch_nx. */
414 : :
415 : : static void
416 : 0 : gt_pch_nx (user_struct *p, gt_pointer_operator op, void *cookie)
417 : : {
418 : 0 : op (&(p->m_ptr), NULL, cookie);
419 : 0 : }
420 : :
421 : : /* Verify that GTY((user)) works. */
422 : :
423 : : static void
424 : 4 : test_user_struct ()
425 : : {
426 : 4 : root_user_struct_ptr = ggc_cleared_alloc <user_struct> ();
427 : 4 : test_struct *referenced = ggc_cleared_alloc <test_struct> ();
428 : 4 : root_user_struct_ptr->m_ptr = referenced;
429 : :
430 : 4 : num_calls_to_user_gt_ggc_mx = 0;
431 : :
432 : 4 : ggc_collect (GGC_COLLECT_FORCE);
433 : :
434 : 4 : ASSERT_TRUE (ggc_marked_p (root_user_struct_ptr));
435 : 4 : ASSERT_TRUE (ggc_marked_p (referenced));
436 : 4 : ASSERT_TRUE (num_calls_to_user_gt_ggc_mx > 0);
437 : 4 : }
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 : 4 : test_tree_marking ()
447 : : {
448 : 4 : dummy_unittesting_tree = build_int_cst (integer_type_node, 1066);
449 : :
450 : 4 : ggc_collect (GGC_COLLECT_FORCE);
451 : :
452 : 4 : ASSERT_TRUE (ggc_marked_p (dummy_unittesting_tree));
453 : 4 : }
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 : 4 : ggc_tests_cc_tests ()
466 : : {
467 : 4 : test_basic_struct ();
468 : 4 : test_length ();
469 : 4 : test_union ();
470 : 4 : test_finalization ();
471 : 4 : test_deletable_global ();
472 : 4 : test_inheritance ();
473 : 4 : test_chain_next ();
474 : 4 : test_user_struct ();
475 : 4 : test_tree_marking ();
476 : 4 : }
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 */
|