xref: /netbsd/external/gpl3/gcc/dist/gcc/ggc-tests.cc (revision f0fbc68b)
1 /* Unit tests for GCC's garbage collector (and gengtype etc).
2    Copyright (C) 2015-2022 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
test_basic_struct()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 (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
test_length()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 (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 (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
calc_desc(int kind)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
test_union()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 (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.  */
~test_struct_with_dtor()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
test_finalization()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 (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
test_deletable_global()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 (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:
example_base()225   example_base ()
226     : m_kind (0),
227       m_a (ggc_cleared_alloc <test_struct> ())
228   {}
229 
230   void *
operator new(size_t sz)231   operator new (size_t sz)
232   {
233     return ggc_internal_cleared_alloc (sz);
234   }
235 
236  protected:
example_base(int kind)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:
some_subclass()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:
some_other_subclass()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
test_inheritance()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 (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
test_chain_next()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 (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
gt_ggc_mx(user_struct * p)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
gt_pch_nx(user_struct * p)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
gt_pch_nx(user_struct * p,gt_pointer_operator op,void * cookie)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
test_user_struct()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 (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
test_tree_marking()446 test_tree_marking ()
447 {
448   dummy_unittesting_tree = build_int_cst (integer_type_node, 1066);
449 
450   ggc_collect (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
ggc_tests_cc_tests()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