This patch makes gcc::pipeline and opt_pass instances be allocated
within the GC-heap, and adds traversal hooks for GC/PCH, so that passes
can own refs to other GC-allocated objects.

gcc/
        Make opt_pass and gcc::pipeline be GC-managed, so that pass
        instances can own GC refs.

        * Makefile.in (GTFILES): Add pipeline.h and tree-pass.h.
        * context.c (gcc::context::gt_ggc_mx): Traverse passes_.
        (gcc::context::gt_pch_nx): Likewise.
        (gcc::context::gt_pch_nx):  Likewise.
        * passes.c (opt_pass::operator new): New.
        (opt_pass::gt_ggc_mx): New.
        (opt_pass::gt_pch_nx): New.
        (opt_pass::gt_pch_nx_with_op): New.
        (gt_ggc_mx (opt_pass *)): New.
        (gt_pch_nx (opt_pass *)): New.
        (gt_pch_nx_opt_pass): New.
        (pipeline::operator new): New.
        (pipeline::gt_ggc_mx): New.
        (pipeline::gt_pch_nx): New.
        (pipeline::gt_pch_nx_with_op): New.
        (gt_ggc_mx (pipeline *)): New.
        (gt_pch_nx (pipeline *)): New.
        (gt_pch_nx_pipeline): New.
        * pipeline.h (class pipeline): Add GTY((user)) marking.
        (pipeline::operator new): New.
        (pipeline::gt_ggc_mx): New.
        (pipeline::gt_pch_nx): New.
        (pipeline::gt_pch_nx_with_op): New.
        (gt_ggc_mx (pipeline *)): New.
        (gt_pch_nx (pipeline *)): New.
        (gt_pch_nx_pipeline): New.
        * tree-pass.h (class opt_pass): Add GTY((user)) marking.
        (opt_pass::operator new): New.
        (opt_pass::gt_ggc_mx): New.
        (opt_pass::gt_pch_nx): New.
        (opt_pass::gt_pch_nx_with_op): New.
        (gt_ggc_mx (opt_pass *)): New.
        (gt_pch_nx (opt_pass *)): New.
        (gt_pch_nx_opt_pass): New.
---
 gcc/Makefile.in |   2 +
 gcc/context.c   |   9 ++--
 gcc/passes.c    | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/pipeline.h  |  15 +++++-
 gcc/tree-pass.h |  19 ++++++-
 5 files changed, 198 insertions(+), 7 deletions(-)

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index e9d6247..ec42f7b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -3820,6 +3820,8 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h 
$(srcdir)/coretypes.h \
   $(srcdir)/asan.c \
   $(srcdir)/tsan.c \
   $(srcdir)/context.h \
+  $(srcdir)/pipeline.h \
+  $(srcdir)/tree-pass.h \
   @all_gtfiles@
 
 # Compute the list of GT header files from the corresponding C sources,
diff --git a/gcc/context.c b/gcc/context.c
index 72135ed..4d9f0c6 100644
--- a/gcc/context.c
+++ b/gcc/context.c
@@ -42,20 +42,19 @@ gcc::context::context()
 void
 gcc::context::gt_ggc_mx ()
 {
-  /* Currently a no-op.  */
+  ::gt_ggc_mx (passes_);
 }
 
 void
 gcc::context::gt_pch_nx ()
 {
-  /* Currently a no-op.  */
+  ::gt_pch_nx (passes_);
 }
 
 void
-gcc::context::gt_pch_nx (gt_pointer_operator op ATTRIBUTE_UNUSED,
-                        void *cookie ATTRIBUTE_UNUSED)
+gcc::context::gt_pch_nx (gt_pointer_operator op, void *cookie)
 {
-  /* Currently a no-op.  */
+  op (&passes_, cookie);
 }
 
 void gt_ggc_mx (gcc::context *ctxt)
diff --git a/gcc/passes.c b/gcc/passes.c
index ce5cdeb..dd1b0ba 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -82,6 +82,33 @@ struct opt_pass *current_pass;
 
 static void register_pass_name (struct opt_pass *, const char *);
 
+void*
+opt_pass::operator new (size_t sz)
+{
+  return ggc_internal_cleared_alloc_stat (sz MEM_STAT_INFO);
+}
+
+void opt_pass::gt_ggc_mx ()
+{
+  ::gt_ggc_mx (ctxt_);
+  ::gt_ggc_mx (sub);
+  ::gt_ggc_mx (next);
+}
+
+void opt_pass::gt_pch_nx ()
+{
+  ::gt_pch_nx (ctxt_);
+  ::gt_pch_nx (sub);
+  ::gt_pch_nx (next);
+}
+
+void opt_pass::gt_pch_nx_with_op (gt_pointer_operator op, void *cookie)
+{
+  op (&(ctxt_), cookie);
+  op (&(sub), cookie);
+  op (&(next), cookie);
+}
+
 /* Most passes are single-instance (within their context) and thus don't
    need to implement cloning, but passes that support multiple instances
    *must* provide their own implementation of the clone method.
@@ -116,6 +143,118 @@ opt_pass::opt_pass(const pass_data &data, context *ctxt)
 {
 }
 
+void gt_ggc_mx (opt_pass *p)
+{
+  if (ggc_test_and_set_mark (p))
+    p->gt_ggc_mx ();
+}
+
+void gt_pch_nx (opt_pass *p)
+{
+  if (gt_pch_note_object (p, p, ::gt_pch_nx_opt_pass))
+    p->gt_pch_nx ();
+}
+
+void gt_pch_nx_opt_pass (void *this_obj, void *p,
+                        gt_pointer_operator op, void *cookie)
+{
+  opt_pass *pass = (opt_pass*)p;
+  if (p == this_obj)
+    pass->gt_pch_nx_with_op (op, cookie);
+}
+
+void*
+pipeline::operator new (size_t sz)
+{
+  return ggc_internal_cleared_alloc_stat (sz MEM_STAT_INFO);
+}
+
+void
+pipeline::gt_ggc_mx ()
+{
+  ::gt_ggc_mx (all_passes);
+  ::gt_ggc_mx (all_small_ipa_passes);
+  ::gt_ggc_mx (all_lowering_passes);
+  ::gt_ggc_mx (all_regular_ipa_passes);
+  ::gt_ggc_mx (all_lto_gen_passes);
+  ::gt_ggc_mx (all_late_ipa_passes);
+
+  for (int i = 0; i < passes_by_id_size; i++)
+    ::gt_ggc_mx (passes_by_id[i]);
+
+#define INSERT_PASSES_AFTER(PASS)
+#define PUSH_INSERT_PASSES_WITHIN(PASS)
+#define POP_INSERT_PASSES()
+#define NEXT_PASS(PASS, NUM) ::gt_ggc_mx (PASS ## _ ## NUM);
+#define TERMINATE_PASS_LIST()
+
+#include "pass-instances.def"
+
+#undef INSERT_PASSES_AFTER
+#undef PUSH_INSERT_PASSES_WITHIN
+#undef POP_INSERT_PASSES
+#undef NEXT_PASS
+#undef TERMINATE_PASS_LIST
+
+}
+
+void
+pipeline::gt_pch_nx ()
+{
+  ::gt_pch_nx (all_passes);
+  ::gt_pch_nx (all_small_ipa_passes);
+  ::gt_pch_nx (all_lowering_passes);
+  ::gt_pch_nx (all_regular_ipa_passes);
+  ::gt_pch_nx (all_lto_gen_passes);
+  ::gt_pch_nx (all_late_ipa_passes);
+
+  for (int i = 0; i < passes_by_id_size; i++)
+    ::gt_pch_nx (passes_by_id[i]);
+
+#define INSERT_PASSES_AFTER(PASS)
+#define PUSH_INSERT_PASSES_WITHIN(PASS)
+#define POP_INSERT_PASSES()
+#define NEXT_PASS(PASS, NUM) ::gt_pch_nx (PASS ## _ ## NUM);
+#define TERMINATE_PASS_LIST()
+
+#include "pass-instances.def"
+
+#undef INSERT_PASSES_AFTER
+#undef PUSH_INSERT_PASSES_WITHIN
+#undef POP_INSERT_PASSES
+#undef NEXT_PASS
+#undef TERMINATE_PASS_LIST
+
+}
+
+void
+pipeline::gt_pch_nx_with_op (gt_pointer_operator op, void *cookie)
+{
+  op (&(all_passes), cookie);
+  op (&(all_small_ipa_passes), cookie);
+  op (&(all_lowering_passes), cookie);
+  op (&(all_regular_ipa_passes), cookie);
+  op (&(all_lto_gen_passes), cookie);
+  op (&(all_late_ipa_passes), cookie);
+
+  for (int i = 0; i < passes_by_id_size; i++)
+    op (&(passes_by_id[i]), cookie);
+
+#define INSERT_PASSES_AFTER(PASS)
+#define PUSH_INSERT_PASSES_WITHIN(PASS)
+#define POP_INSERT_PASSES()
+#define NEXT_PASS(PASS, NUM) op (&(PASS ## _ ## NUM), cookie);
+#define TERMINATE_PASS_LIST()
+
+#include "pass-instances.def"
+
+#undef INSERT_PASSES_AFTER
+#undef PUSH_INSERT_PASSES_WITHIN
+#undef POP_INSERT_PASSES
+#undef NEXT_PASS
+#undef TERMINATE_PASS_LIST
+
+}
 
 void
 pipeline::execute_early_local_passes ()
@@ -129,6 +268,27 @@ pipeline::execute_pass_mode_switching ()
   return pass_mode_switching_1->execute ();
 }
 
+void gt_ggc_mx (pipeline *p)
+{
+  if (ggc_test_and_set_mark (p))
+    p->gt_ggc_mx ();
+}
+
+void gt_pch_nx (pipeline *p)
+{
+  if (gt_pch_note_object (p, p, ::gt_pch_nx_pipeline))
+    p->gt_pch_nx ();
+
+}
+
+void gt_pch_nx_pipeline (void *this_obj, void *p,
+                        gt_pointer_operator op, void *cookie)
+{
+  pipeline *passes = (pipeline *)p;
+  if (p == this_obj)
+    passes->gt_pch_nx_with_op (op, cookie);
+}
+
 
 /* Call from anywhere to find out what pass this is.  Useful for
    printing out debugging information deep inside an service
diff --git a/gcc/pipeline.h b/gcc/pipeline.h
index 60bde5c..66b8212 100644
--- a/gcc/pipeline.h
+++ b/gcc/pipeline.h
@@ -44,11 +44,19 @@ namespace gcc {
 
 class context;
 
-class pipeline
+class GTY((user)) pipeline
 {
 public:
+  /* Ensure that instances are allocated in the GC-managed heap.  */
+  void *operator new (size_t sz);
+
   pipeline(context *ctxt);
 
+  /* GTY((user)) methods.  */
+  void gt_ggc_mx ();
+  void gt_pch_nx ();
+  void gt_pch_nx_with_op (gt_pointer_operator op, void *cookie);
+
   void register_pass (struct register_pass_info *pass_info);
   void register_one_dump_file (struct opt_pass *pass);
 
@@ -122,5 +130,10 @@ private:
 
 } // namespace gcc
 
+extern void gt_ggc_mx (gcc::pipeline *passes);
+extern void gt_pch_nx (gcc::pipeline *passes);
+extern void gt_pch_nx_pipeline (void *this_obj, void *p,
+                               gt_pointer_operator op, void *cookie);
+
 #endif /* ! GCC_PIPELINE_H */
 
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 41d5d92..c3e89d4 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -76,11 +76,22 @@ namespace gcc
 
 /* An instance of a pass.  This is also "pass_data" to minimize the
    changes in existing code.  */
-class opt_pass : public pass_data
+class GTY((user)) opt_pass : public pass_data
 {
 public:
+  /* Ensure that instances are allocated in the GC-managed heap.  */
+  void *operator new (size_t sz);
+
   virtual ~opt_pass () { }
 
+  /* GTY((user)) methods, to be called once per traversal.
+     opt_pass subclasses with additional GC-managed data should overide
+     these, chain up to the base class implementation, then walk their
+     extra fields.  */
+  virtual void gt_ggc_mx ();
+  virtual void gt_pch_nx ();
+  virtual void gt_pch_nx_with_op (gt_pointer_operator op, void *cookie);
+
   /* Create a copy of this pass.
 
      Passes that can have multiple instances must provide their own
@@ -117,6 +128,12 @@ protected:
   gcc::context *ctxt_;
 };
 
+/* GTY((user)) methods.  */
+extern void gt_ggc_mx (opt_pass *p);
+extern void gt_pch_nx (opt_pass *p);
+extern void gt_pch_nx_opt_pass (void *this_obj, void *p,
+                               gt_pointer_operator op, void *cookie);
+
 /* Description of GIMPLE pass.  */
 class gimple_opt_pass : public opt_pass
 {
-- 
1.7.11.7

Reply via email to