This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 08/16] Add test-ggc.c to unittests


gcc/testsuite/ChangeLog:
	* unittests/test-ggc.c: New file.
---
 gcc/testsuite/unittests/test-ggc.c | 299 +++++++++++++++++++++++++++++++++++++
 1 file changed, 299 insertions(+)
 create mode 100644 gcc/testsuite/unittests/test-ggc.c

diff --git a/gcc/testsuite/unittests/test-ggc.c b/gcc/testsuite/unittests/test-ggc.c
new file mode 100644
index 0000000..7a16977
--- /dev/null
+++ b/gcc/testsuite/unittests/test-ggc.c
@@ -0,0 +1,299 @@
+/* Unit tests for GCC's garbage collector (and gengtype etc).
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "gtest/gtest.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "signop.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "predict.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "ggc-internal.h" /* (for ggc_force_collect).  */
+
+/* The various GTY markers must be outside of a namespace to be seen by
+   gengtype, so we don't put this file within an anonymous namespace.  */
+
+/* A test fixture for writing ggc tests.  */
+class ggc_test : public ::testing::Test
+{
+ protected:
+  void
+  forcibly_ggc_collect ()
+  {
+    ggc_force_collect = true;
+    ggc_collect ();
+    ggc_force_collect = false;
+  }
+};
+
+/* Smoketest to ensure that a GC root is marked ("tree" type).  */
+
+static GTY(()) tree dummy_unittesting_tree;
+
+TEST_F (ggc_test, tree_marking)
+{
+  dummy_unittesting_tree = build_int_cst (integer_type_node, 1066);
+
+  forcibly_ggc_collect ();
+
+  EXPECT_TRUE (ggc_marked_p (dummy_unittesting_tree));
+}
+
+/* Verify that a simple custom struct works, and that it can
+   own references to non-roots, and have them be marked.  */
+
+struct GTY(()) test_struct
+{
+  test_struct *other;
+};
+
+static GTY(()) test_struct *root_test_struct;
+
+TEST_F (ggc_test, custom_struct)
+{
+  root_test_struct = ggc_cleared_alloc <test_struct> ();
+  root_test_struct->other = ggc_cleared_alloc <test_struct> ();
+
+  forcibly_ggc_collect ();
+
+  EXPECT_TRUE (ggc_marked_p (root_test_struct));
+  EXPECT_TRUE (ggc_marked_p (root_test_struct->other));
+}
+
+/* Verify that destructors get run when instances are collected.  */
+
+struct GTY(()) test_struct_with_dtor
+{
+  /* This struct has a destructor; it *ought* to be called
+     by the ggc machinery when instances are collected.  */
+  ~test_struct_with_dtor () { dtor_call_count++; }
+
+  static int dtor_call_count;
+};
+
+int test_struct_with_dtor::dtor_call_count;
+
+TEST_F (ggc_test, finalization)
+{
+  EXPECT_FALSE (need_finalization_p <test_struct> ());
+  EXPECT_TRUE (need_finalization_p <test_struct_with_dtor> ());
+
+  /* Create some garbage.  */
+  const int count = 10;
+  for (int i = 0; i < count; i++)
+    ggc_cleared_alloc <test_struct_with_dtor> ();
+
+  test_struct_with_dtor::dtor_call_count = 0;
+
+  forcibly_ggc_collect ();
+
+  /* Verify that the destructor was run for each instance.  */
+  EXPECT_EQ (count, test_struct_with_dtor::dtor_call_count);
+}
+
+/* Verify that a global can be marked as "deletable".  */
+
+static GTY((deletable)) test_struct *test_of_deletable;
+
+/* FIXME: we can't do this test via a plugin as it stands.
+   The list of deletable roots is fixed by the main gengtype
+   run; there isn't yet a way to add extra
+   deletable roots (PLUGIN_REGISTER_GGC_ROOTS is for regular
+   roots).  */
+#if 0
+TEST_F (ggc_test, deletable_global)
+{
+  test_of_deletable = ggc_cleared_alloc <test_struct> ();
+  EXPECT_TRUE (test_of_deletable != NULL);
+
+  forcibly_ggc_collect ();
+
+  EXPECT_EQ (NULL, test_of_deletable);
+}
+#endif
+
+/* Verify that gengtype etc can cope with inheritance.  */
+
+class GTY((desc("%h.m_kind"), tag("0"))) example_base
+{
+ public:
+  example_base ()
+    : m_kind (0),
+      m_a (ggc_cleared_alloc <test_struct> ())
+  {}
+
+  void *
+  operator new (size_t sz)
+  {
+    return ggc_internal_cleared_alloc (sz);
+  }
+
+ protected:
+  example_base (int kind)
+    : m_kind (kind),
+      m_a (ggc_cleared_alloc <test_struct> ())
+  {}
+
+ public:
+  int m_kind;
+  test_struct *m_a;
+};
+
+class GTY((tag("1"))) some_subclass : public example_base
+{
+ public:
+  some_subclass ()
+    : example_base (1),
+      m_b (ggc_cleared_alloc <test_struct> ())
+  {}
+
+  test_struct *m_b;
+};
+
+class GTY((tag("2"))) some_other_subclass : public example_base
+{
+ public:
+  some_other_subclass ()
+    : example_base (2),
+      m_c (ggc_cleared_alloc <test_struct> ())
+  {}
+
+  test_struct *m_c;
+};
+
+/* Various test roots, both expressed as a ptr to the actual class, and
+   as a ptr to the base class.  */
+static GTY(()) example_base *test_example_base;
+static GTY(()) some_subclass *test_some_subclass;
+static GTY(()) some_other_subclass *test_some_other_subclass;
+static GTY(()) example_base *test_some_subclass_as_base_ptr;
+static GTY(()) example_base *test_some_other_subclass_as_base_ptr;
+
+TEST_F (ggc_test, inheritance)
+{
+  test_example_base = new example_base ();
+  test_some_subclass = new some_subclass ();
+  test_some_other_subclass = new some_other_subclass ();
+  test_some_subclass_as_base_ptr = new some_subclass ();
+  test_some_other_subclass_as_base_ptr = new some_other_subclass ();
+
+  forcibly_ggc_collect ();
+
+  /* Verify that the roots and everything referenced by them got marked
+     (both for fields in the base class and those in subclasses).  */
+  EXPECT_TRUE (ggc_marked_p (test_example_base));
+  EXPECT_TRUE (ggc_marked_p (test_example_base->m_a));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass));
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass->m_a));
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass->m_b));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass));
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass->m_a));
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass->m_c));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr));
+  EXPECT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr->m_a));
+  EXPECT_TRUE (ggc_marked_p (((some_subclass *)
+			      test_some_subclass_as_base_ptr)->m_b));
+
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr));
+  EXPECT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr->m_a));
+  EXPECT_TRUE (ggc_marked_p (((some_other_subclass *)
+			      test_some_other_subclass_as_base_ptr)->m_c));
+}
+
+/* Test of chain_next/chain_prev
+
+   Construct a very long linked list, so that without
+   the chain_next/chain_prev optimization we'd have
+   a stack overflow when gt_ggc_mx_test_node recurses.  */
+
+struct GTY(( chain_next ("%h.m_next"),
+	     chain_prev ("%h.m_prev") )) test_node
+{
+  test_node *m_prev;
+  test_node *m_next;
+  int m_idx;
+};
+
+static GTY(()) test_node *root_test_node;
+
+TEST_F (ggc_test, chain_next)
+{
+  /* 2 million nodes (and thus the same number of stack frames) ought
+     to be deep enough to crash if gengtype has created something
+     that recurses.
+
+     This length reliably causes the test to segfault without the
+     chain_next/prev optimization on this box (Fedora 20 x86_64 with 128GB
+     of RAM), but causes this test to take about 0.5s, dominating the time
+     taken by the overall testsuite.
+
+     We could perhaps lower this by not increasing the stack size so much
+     in toplev.c, or perhaps reducing the stack size when running this
+     testcase.  */
+  const int count = 2000000;
+
+  /* Build the linked list.  */
+  root_test_node = ggc_cleared_alloc <test_node> ();
+  test_node *tail_node = root_test_node;
+  for (int i = 0; i < count; i++)
+    {
+      test_node *new_node = ggc_cleared_alloc <test_node> ();
+      tail_node->m_next = new_node;
+      new_node->m_prev = tail_node;
+      new_node->m_idx = i;
+      tail_node = new_node;
+    }
+
+  forcibly_ggc_collect ();
+
+  /* If we got here, we survived.  */
+
+  /* Verify that all nodes in the list were marked.  */
+  EXPECT_TRUE (ggc_marked_p (root_test_node));
+  test_node *iter_node = root_test_node->m_next;
+  for (int i = 0; i < count; i++)
+    {
+      EXPECT_TRUE (ggc_marked_p (iter_node));
+      EXPECT_EQ (i, iter_node->m_idx);
+      iter_node = iter_node->m_next;
+    }
+}
+
+/* Ideas for other tests:
+   - pch-handling  */
+
+/* Generated by unittests-plugin.c's use of the
+   "dg-plugin-run-gengtype" directive.  */
+#include "gt-unittests-test-ggc.h"
-- 
1.8.5.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]