]>
Commit | Line | Data |
---|---|---|
f61d7248 | 1 | /* Unit tests for GCC's garbage collector (and gengtype etc). |
fbd26352 | 2 | Copyright (C) 2015-2019 Free Software Foundation, Inc. |
f61d7248 | 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 | ||
f61d7248 | 30 | /* A helper function for writing ggc tests. */ |
31 | ||
09c2dc4c | 32 | void |
33 | selftest::forcibly_ggc_collect () | |
f61d7248 | 34 | { |
35 | ggc_force_collect = true; | |
36 | ggc_collect (); | |
37 | ggc_force_collect = false; | |
38 | } | |
39 | ||
09c2dc4c | 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 | ||
f61d7248 | 43 | \f |
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 | ||
09c2dc4c | 61 | selftest::forcibly_ggc_collect (); |
f61d7248 | 62 | |
63 | ASSERT_TRUE (ggc_marked_p (root_test_struct)); | |
64 | ASSERT_TRUE (ggc_marked_p (root_test_struct->other)); | |
65 | } | |
66 | ||
67 | \f | |
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 | ||
09c2dc4c | 91 | selftest::forcibly_ggc_collect (); |
f61d7248 | 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 | \f | |
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 | ||
09c2dc4c | 165 | selftest::forcibly_ggc_collect (); |
f61d7248 | 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 | \f | |
176 | ||
177 | /* Verify that destructors get run when instances are collected. */ | |
178 | ||
251317e4 | 179 | class GTY(()) test_struct_with_dtor |
f61d7248 | 180 | { |
251317e4 | 181 | public: |
f61d7248 | 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 | { | |
60c6a5a6 | 194 | #if GCC_VERSION >= 4003 |
f61d7248 | 195 | ASSERT_FALSE (need_finalization_p <test_struct> ()); |
196 | ASSERT_TRUE (need_finalization_p <test_struct_with_dtor> ()); | |
60c6a5a6 | 197 | #endif |
f61d7248 | 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 | ||
09c2dc4c | 206 | selftest::forcibly_ggc_collect (); |
f61d7248 | 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 | \f | |
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 | ||
09c2dc4c | 224 | selftest::forcibly_ggc_collect (); |
f61d7248 | 225 | |
226 | ASSERT_EQ (NULL, test_of_deletable); | |
227 | } | |
228 | ||
229 | \f | |
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 | ||
09c2dc4c | 297 | selftest::forcibly_ggc_collect (); |
f61d7248 | 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 | \f | |
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 | ||
09c2dc4c | 376 | selftest::forcibly_ggc_collect (); |
f61d7248 | 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 | \f | |
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 | ||
09c2dc4c | 443 | selftest::forcibly_ggc_collect (); |
f61d7248 | 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 | \f | |
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 | ||
09c2dc4c | 461 | selftest::forcibly_ggc_collect (); |
f61d7248 | 462 | |
463 | ASSERT_TRUE (ggc_marked_p (dummy_unittesting_tree)); | |
464 | } | |
465 | ||
466 | \f | |
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 */ |