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