[v2,14/21] libcc1: share basic context code

Message ID 20210428010119.806184-15-tom@tromey.com
State New
Headers show
Series
  • C++11-based improvements for libcc1
Related show

Commit Message

Tom Tromey April 28, 2021, 1:01 a.m.
Both plugins in libcc1 share a fair amount of boilerplate.  They both
share error-emission code, context management code, and tree GC code.
This patch unifies these two bodies of code, avoiding needless
duplication.

libcc1/ChangeLog
2021-04-27  Tom Tromey  <tom@tromey.com>

	* libcc1plugin.cc: Move code to context.cc.
	* libcp1plugin.cc: Move code to context.cc.
	* context.hh: New file.
	* context.cc: New file.
	* Makefile.in: Rebuild.
	* Makefile.am (AM_CPPFLAGS): Add more gcc flags.
	(CPPFLAGS_FOR_C, CPPFLAGS_FOR_CXX): Update.
	(libcc1plugin_la_SOURCES): Add context.hh, context.cc.
	(libcp1plugin_la_SOURCES): Likewise.
---
 libcc1/ChangeLog       |  12 +++
 libcc1/Makefile.am     |  15 +--
 libcc1/Makefile.in     |  27 +++---
 libcc1/context.cc      | 171 ++++++++++++++++++++++++++++++++++
 libcc1/context.hh      | 121 ++++++++++++++++++++++++
 libcc1/libcc1plugin.cc | 204 +----------------------------------------
 libcc1/libcp1plugin.cc | 203 +---------------------------------------
 7 files changed, 333 insertions(+), 420 deletions(-)
 create mode 100644 libcc1/context.cc
 create mode 100644 libcc1/context.hh

-- 
2.26.2

Comments

Martin Sebor via Gcc-patches April 29, 2021, 12:50 p.m. | #1
On 4/27/2021 7:01 PM, Tom Tromey wrote:
> Both plugins in libcc1 share a fair amount of boilerplate.  They both

> share error-emission code, context management code, and tree GC code.

> This patch unifies these two bodies of code, avoiding needless

> duplication.

>

> libcc1/ChangeLog

> 2021-04-27  Tom Tromey  <tom@tromey.com>

>

> 	* libcc1plugin.cc: Move code to context.cc.

> 	* libcp1plugin.cc: Move code to context.cc.

> 	* context.hh: New file.

> 	* context.cc: New file.

> 	* Makefile.in: Rebuild.

> 	* Makefile.am (AM_CPPFLAGS): Add more gcc flags.

> 	(CPPFLAGS_FOR_C, CPPFLAGS_FOR_CXX): Update.

> 	(libcc1plugin_la_SOURCES): Add context.hh, context.cc.

> 	(libcp1plugin_la_SOURCES): Likewise.


OK

jeff

Patch

diff --git a/libcc1/Makefile.am b/libcc1/Makefile.am
index 3f20513d11b7..9ec021030e2d 100644
--- a/libcc1/Makefile.am
+++ b/libcc1/Makefile.am
@@ -19,11 +19,10 @@ 
 ACLOCAL_AMFLAGS = -I .. -I ../config
 gcc_build_dir = ../gcc
 AM_CPPFLAGS = -I $(srcdir)/../include -I $(srcdir)/../libgcc \
-	-I $(gcc_build_dir) -I$(srcdir)/../gcc $($@_CPPFLAGS) $(GMPINC)
-CPPFLAGS_FOR_C_FAMILY = -I $(srcdir)/../gcc/c-family \
-	-I $(srcdir)/../libcpp/include
-CPPFLAGS_FOR_C = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/c
-CPPFLAGS_FOR_CXX = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/cp
+	-I $(gcc_build_dir) -I$(srcdir)/../gcc $($@_CPPFLAGS) $(GMPINC) \
+	-I $(srcdir)/../gcc/c-family -I $(srcdir)/../libcpp/include
+CPPFLAGS_FOR_C = -I $(srcdir)/../gcc/c
+CPPFLAGS_FOR_CXX = -I $(srcdir)/../gcc/cp
 AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR) $(visibility) $(CET_HOST_FLAGS)
 if DARWIN_DYNAMIC_LOOKUP
 AM_CXXFLAGS += -Wl,-undefined,dynamic_lookup
@@ -55,7 +54,8 @@  marshall_c_source = marshall-c.hh
 marshall_cxx_source = marshall-cp.hh
 
 libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
-libcc1plugin_la_SOURCES = libcc1plugin.cc $(shared_source) $(marshall_c_source)
+libcc1plugin_la_SOURCES = libcc1plugin.cc context.cc context.hh \
+	$(shared_source) $(marshall_c_source)
 libcc1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_C)
 libcc1plugin_la_LIBADD = $(libiberty)
 libcc1plugin_la_DEPENDENCIES = $(libiberty_dep)
@@ -64,7 +64,8 @@  libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
 	$(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
 
 libcp1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcp1plugin.sym
-libcp1plugin_la_SOURCES = libcp1plugin.cc $(shared_source) $(marshall_cxx_source)
+libcp1plugin_la_SOURCES = libcp1plugin.cc context.cc context.hh \
+	$(shared_source) $(marshall_cxx_source)
 libcp1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_CXX)
 libcp1plugin_la_LIBADD = $(libiberty)
 libcp1plugin_la_DEPENDENCIES = $(libiberty_dep)
diff --git a/libcc1/Makefile.in b/libcc1/Makefile.in
index d76893e3a24e..395f01a98215 100644
--- a/libcc1/Makefile.in
+++ b/libcc1/Makefile.in
@@ -148,12 +148,12 @@  am_libcc1_la_OBJECTS = findcomp.lo libcc1.lo libcp1.lo compiler.lo \
 	names.lo $(am__objects_1) $(am__objects_2) $(am__objects_2)
 libcc1_la_OBJECTS = $(am_libcc1_la_OBJECTS)
 @ENABLE_PLUGIN_TRUE@am_libcc1_la_rpath = -rpath $(cc1libdir)
-am_libcc1plugin_la_OBJECTS = libcc1plugin.lo $(am__objects_1) \
-	$(am__objects_2)
+am_libcc1plugin_la_OBJECTS = libcc1plugin.lo context.lo \
+	$(am__objects_1) $(am__objects_2)
 libcc1plugin_la_OBJECTS = $(am_libcc1plugin_la_OBJECTS)
 @ENABLE_PLUGIN_TRUE@am_libcc1plugin_la_rpath = -rpath $(plugindir)
-am_libcp1plugin_la_OBJECTS = libcp1plugin.lo $(am__objects_1) \
-	$(am__objects_2)
+am_libcp1plugin_la_OBJECTS = libcp1plugin.lo context.lo \
+	$(am__objects_1) $(am__objects_2)
 libcp1plugin_la_OBJECTS = $(am_libcp1plugin_la_OBJECTS)
 @ENABLE_PLUGIN_TRUE@am_libcp1plugin_la_rpath = -rpath $(plugindir)
 AM_V_P = $(am__v_P_@AM_V@)
@@ -379,13 +379,11 @@  visibility = @visibility@
 ACLOCAL_AMFLAGS = -I .. -I ../config
 gcc_build_dir = ../gcc
 AM_CPPFLAGS = -I $(srcdir)/../include -I $(srcdir)/../libgcc \
-	-I $(gcc_build_dir) -I$(srcdir)/../gcc $($@_CPPFLAGS) $(GMPINC)
+	-I $(gcc_build_dir) -I$(srcdir)/../gcc $($@_CPPFLAGS) $(GMPINC) \
+	-I $(srcdir)/../gcc/c-family -I $(srcdir)/../libcpp/include
 
-CPPFLAGS_FOR_C_FAMILY = -I $(srcdir)/../gcc/c-family \
-	-I $(srcdir)/../libcpp/include
-
-CPPFLAGS_FOR_C = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/c
-CPPFLAGS_FOR_CXX = $(CPPFLAGS_FOR_C_FAMILY) -I $(srcdir)/../gcc/cp
+CPPFLAGS_FOR_C = -I $(srcdir)/../gcc/c
+CPPFLAGS_FOR_CXX = -I $(srcdir)/../gcc/cp
 AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR) $(visibility) $(CET_HOST_FLAGS) \
 	$(am__append_1)
 # Can be simplified when libiberty becomes a normal convenience library.
@@ -408,7 +406,9 @@  shared_source = callbacks.cc callbacks.hh connection.cc connection.hh \
 marshall_c_source = marshall-c.hh
 marshall_cxx_source = marshall-cp.hh
 libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
-libcc1plugin_la_SOURCES = libcc1plugin.cc $(shared_source) $(marshall_c_source)
+libcc1plugin_la_SOURCES = libcc1plugin.cc context.cc context.hh \
+	$(shared_source) $(marshall_c_source)
+
 libcc1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_C)
 libcc1plugin_la_LIBADD = $(libiberty)
 libcc1plugin_la_DEPENDENCIES = $(libiberty_dep)
@@ -417,7 +417,9 @@  libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
 	$(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
 
 libcp1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcp1plugin.sym
-libcp1plugin_la_SOURCES = libcp1plugin.cc $(shared_source) $(marshall_cxx_source)
+libcp1plugin_la_SOURCES = libcp1plugin.cc context.cc context.hh \
+	$(shared_source) $(marshall_cxx_source)
+
 libcp1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_CXX)
 libcp1plugin_la_LIBADD = $(libiberty)
 libcp1plugin_la_DEPENDENCIES = $(libiberty_dep)
@@ -579,6 +581,7 @@  distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callbacks.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compiler.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/context.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/findcomp.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcc1.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcc1plugin.Plo@am__quote@
diff --git a/libcc1/context.cc b/libcc1/context.cc
new file mode 100644
index 000000000000..3d5ff921df8a
--- /dev/null
+++ b/libcc1/context.cc
@@ -0,0 +1,171 @@ 
+/* Generic plugin context
+   Copyright (C) 2020 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 <cc1plugin-config.h>
+
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
+#include "../gcc/config.h"
+
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "stringpool.h"
+#include "hash-set.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+
+#include "gcc-interface.h"
+
+#include "context.hh"
+#include "marshall.hh"
+
+
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+int plugin_is_GPL_compatible;
+#ifdef __GNUC__
+#pragma GCC visibility pop
+#endif
+
+cc1_plugin::plugin_context *cc1_plugin::current_context;
+
+
+
+// This is put into the lang hooks when the plugin starts.
+
+static void
+plugin_print_error_function (diagnostic_context *context, const char *file,
+			     diagnostic_info *diagnostic)
+{
+  if (current_function_decl != NULL_TREE
+      && DECL_NAME (current_function_decl) != NULL_TREE
+      && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
+		 GCC_FE_WRAPPER_FUNCTION) == 0)
+    return;
+  lhd_print_error_function (context, file, diagnostic);
+}
+
+
+
+location_t
+cc1_plugin::plugin_context::get_location_t (const char *filename,
+					    unsigned int line_number)
+{
+  if (filename == NULL)
+    return UNKNOWN_LOCATION;
+
+  filename = intern_filename (filename);
+  linemap_add (line_table, LC_ENTER, false, filename, line_number);
+  location_t loc = linemap_line_start (line_table, line_number, 0);
+  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+  return loc;
+}
+
+// Add a file name to FILE_NAMES and return the canonical copy.
+const char *
+cc1_plugin::plugin_context::intern_filename (const char *filename)
+{
+  const char **slot = file_names.find_slot (filename, INSERT);
+  if (*slot == NULL)
+    {
+      /* The file name must live as long as the line map, which
+	 effectively means as long as this compilation.  So, we copy
+	 the string here but never free it.  */
+      *slot = xstrdup (filename);
+    }
+  return *slot;
+}
+
+void
+cc1_plugin::plugin_context::mark ()
+{
+  for (const auto &item : address_map)
+    {
+      ggc_mark (item->decl);
+      ggc_mark (item->address);
+    }
+
+  for (const auto &item : preserved)
+    ggc_mark (&item);
+}
+
+
+
+// Perform GC marking.
+
+static void
+gc_mark (void *, void *)
+{
+  if (cc1_plugin::current_context != NULL)
+    cc1_plugin::current_context->mark ();
+}
+
+void
+cc1_plugin::generic_plugin_init (struct plugin_name_args *plugin_info,
+				 unsigned int version)
+{
+  long fd = -1;
+  for (int i = 0; i < plugin_info->argc; ++i)
+    {
+      if (strcmp (plugin_info->argv[i].key, "fd") == 0)
+	{
+	  char *tail;
+	  errno = 0;
+	  fd = strtol (plugin_info->argv[i].value, &tail, 0);
+	  if (*tail != '\0' || errno != 0)
+	    fatal_error (input_location,
+			 "%s: invalid file descriptor argument to plugin",
+			 plugin_info->base_name);
+	  break;
+	}
+    }
+  if (fd == -1)
+    fatal_error (input_location,
+		 "%s: required plugin argument %<fd%> is missing",
+		 plugin_info->base_name);
+
+  current_context = new plugin_context (fd);
+
+  // Handshake.
+  cc1_plugin::protocol_int h_version;
+  if (!current_context->require ('H')
+      || ! ::cc1_plugin::unmarshall (current_context, &h_version))
+    fatal_error (input_location,
+		 "%s: handshake failed", plugin_info->base_name);
+  if (h_version != version)
+    fatal_error (input_location,
+		 "%s: unknown version in handshake", plugin_info->base_name);
+
+  register_callback (plugin_info->base_name, PLUGIN_GGC_MARKING,
+		     gc_mark, NULL);
+
+  lang_hooks.print_error_function = plugin_print_error_function;
+}
diff --git a/libcc1/context.hh b/libcc1/context.hh
new file mode 100644
index 000000000000..21a8262ad4be
--- /dev/null
+++ b/libcc1/context.hh
@@ -0,0 +1,121 @@ 
+/* Generic plugin context
+   Copyright (C) 2020 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/>.  */
+
+#ifndef CC1_PLUGIN_CONTEXT_HH
+#define CC1_PLUGIN_CONTEXT_HH
+
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+
+#include "connection.hh"
+
+namespace cc1_plugin
+{
+  static inline unsigned long long
+  convert_out (tree t)
+  {
+    return (unsigned long long) (uintptr_t) t;
+  }
+
+  static inline tree
+  convert_in (unsigned long long v)
+  {
+    return (tree) (uintptr_t) v;
+  }
+
+  struct decl_addr_value
+  {
+    tree decl;
+    tree address;
+  };
+
+  struct decl_addr_hasher : free_ptr_hash<decl_addr_value>
+  {
+    static hashval_t hash (const decl_addr_value *e)
+    {
+      return DECL_UID (e->decl);
+    }
+
+    static bool equal (const decl_addr_value *p1,
+		       const decl_addr_value *p2)
+    {
+      return p1->decl == p2->decl;
+    }
+  };
+
+  struct string_hasher : nofree_ptr_hash<const char>
+  {
+    static inline hashval_t hash (const char *s)
+    {
+      return htab_hash_string (s);
+    }
+
+    static inline bool equal (const char *p1, const char *p2)
+    {
+      return strcmp (p1, p2) == 0;
+    }
+  };
+
+  struct plugin_context : public cc1_plugin::connection
+  {
+    plugin_context (int fd)
+      : cc1_plugin::connection (fd),
+	address_map (30),
+	preserved (30),
+	file_names (30)
+    {
+    }
+
+    // Map decls to addresses.
+    hash_table<decl_addr_hasher> address_map;
+
+    // A collection of trees that are preserved for the GC.
+    hash_table< nofree_ptr_hash<tree_node> > preserved;
+
+    // File name cache.
+    hash_table<string_hasher> file_names;
+
+    // Perform GC marking.
+    void mark ();
+
+    // Preserve a tree during the plugin's operation.
+    tree preserve (tree t)
+    {
+      tree_node **slot = preserved.find_slot (t, INSERT);
+      *slot = t;
+      return t;
+    }
+
+    location_t get_location_t (const char *filename,
+			       unsigned int line_number);
+
+  private:
+
+    // Add a file name to FILE_NAMES and return the canonical copy.
+    const char *intern_filename (const char *filename);
+  };
+
+  extern plugin_context *current_context;
+
+  void generic_plugin_init (struct plugin_name_args *plugin_info,
+			    unsigned int version);
+}
+
+#endif // CC1_PLUGIN_CONTEXT_HH
diff --git a/libcc1/libcc1plugin.cc b/libcc1/libcc1plugin.cc
index 2a75faba7652..d6951ab1a4d2 100644
--- a/libcc1/libcc1plugin.cc
+++ b/libcc1/libcc1plugin.cc
@@ -66,87 +66,11 @@ 
 #include "marshall.hh"
 #include "rpc.hh"
 #include "gcc-c-interface.h"
+#include "context.hh"
 
 #include <vector>
 
-#ifdef __GNUC__
-#pragma GCC visibility push(default)
-#endif
-int plugin_is_GPL_compatible;
-#ifdef __GNUC__
-#pragma GCC visibility pop
-#endif
-
-
-
-// This is put into the lang hooks when the plugin starts.
-
-static void
-plugin_print_error_function (diagnostic_context *context, const char *file,
-			     diagnostic_info *diagnostic)
-{
-  if (current_function_decl != NULL_TREE
-      && DECL_NAME (current_function_decl) != NULL_TREE
-      && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
-		 GCC_FE_WRAPPER_FUNCTION) == 0)
-    return;
-  lhd_print_error_function (context, file, diagnostic);
-}
-
-
-
-static unsigned long long
-convert_out (tree t)
-{
-  return (unsigned long long) (uintptr_t) t;
-}
-
-static tree
-convert_in (unsigned long long v)
-{
-  return (tree) (uintptr_t) v;
-}
-
-
-
-struct decl_addr_value
-{
-  tree decl;
-  tree address;
-};
-
-struct decl_addr_hasher : free_ptr_hash<decl_addr_value>
-{
-  static inline hashval_t hash (const decl_addr_value *);
-  static inline bool equal (const decl_addr_value *, const decl_addr_value *);
-};
-
-inline hashval_t
-decl_addr_hasher::hash (const decl_addr_value *e)
-{
-  return IDENTIFIER_HASH_VALUE (DECL_NAME (e->decl));
-}
-
-inline bool
-decl_addr_hasher::equal (const decl_addr_value *p1, const decl_addr_value *p2)
-{
-  return p1->decl == p2->decl;
-}
-
-
-
-struct string_hasher : nofree_ptr_hash<const char>
-{
-  static inline hashval_t hash (const char *s)
-  {
-    return htab_hash_string (s);
-  }
-
-  static inline bool equal (const char *p1, const char *p2)
-  {
-    return strcmp (p1, p2) == 0;
-  }
-};
+using namespace cc1_plugin;
 
 
 
@@ -166,85 +90,6 @@  pushdecl_safe (tree decl)
 
 
 
-struct plugin_context : public cc1_plugin::connection
-{
-  plugin_context (int fd);
-
-  // Map decls to addresses.
-  hash_table<decl_addr_hasher> address_map;
-
-  // A collection of trees that are preserved for the GC.
-  hash_table< nofree_ptr_hash<tree_node> > preserved;
-
-  // File name cache.
-  hash_table<string_hasher> file_names;
-
-  // Perform GC marking.
-  void mark ();
-
-  // Preserve a tree during the plugin's operation.
-  tree preserve (tree t)
-  {
-    tree_node **slot = preserved.find_slot (t, INSERT);
-    *slot = t;
-    return t;
-  }
-
-  location_t get_location_t (const char *filename,
-			     unsigned int line_number)
-  {
-    if (filename == NULL)
-      return UNKNOWN_LOCATION;
-
-    filename = intern_filename (filename);
-    linemap_add (line_table, LC_ENTER, false, filename, line_number);
-    location_t loc = linemap_line_start (line_table, line_number, 0);
-    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
-    return loc;
-  }
-
-private:
-
-  // Add a file name to FILE_NAMES and return the canonical copy.
-  const char *intern_filename (const char *filename)
-  {
-    const char **slot = file_names.find_slot (filename, INSERT);
-    if (*slot == NULL)
-      {
-	/* The file name must live as long as the line map, which
-	   effectively means as long as this compilation.  So, we copy
-	   the string here but never free it.  */
-	*slot = xstrdup (filename);
-      }
-    return *slot;
-  }
-};
-
-static plugin_context *current_context;
-
-
-
-plugin_context::plugin_context (int fd)
-  : cc1_plugin::connection (fd),
-    address_map (30),
-    preserved (30),
-    file_names (30)
-{
-}
-
-void
-plugin_context::mark ()
-{
-  for (const auto &item : address_map)
-    {
-      ggc_mark (item->decl);
-      ggc_mark (item->address);
-    }
-
-  for (const auto &item : preserved)
-    ggc_mark (&item);
-}
-
 static void
 plugin_binding_oracle (enum c_oracle_request kind, tree identifier)
 {
@@ -899,15 +744,6 @@  plugin_error (cc1_plugin::connection *,
 
 
 
-// Perform GC marking.
-
-static void
-gc_mark (void *, void *)
-{
-  if (current_context != NULL)
-    current_context->mark ();
-}
-
 #ifdef __GNUC__
 #pragma GCC visibility push(default)
 #endif
@@ -916,46 +752,12 @@  int
 plugin_init (struct plugin_name_args *plugin_info,
 	     struct plugin_gcc_version *)
 {
-  long fd = -1;
-  for (int i = 0; i < plugin_info->argc; ++i)
-    {
-      if (strcmp (plugin_info->argv[i].key, "fd") == 0)
-	{
-	  char *tail;
-	  errno = 0;
-	  fd = strtol (plugin_info->argv[i].value, &tail, 0);
-	  if (*tail != '\0' || errno != 0)
-	    fatal_error (input_location,
-			 "%s: invalid file descriptor argument to plugin",
-			 plugin_info->base_name);
-	  break;
-	}
-    }
-  if (fd == -1)
-    fatal_error (input_location,
-		 "%s: required plugin argument %<fd%> is missing",
-		 plugin_info->base_name);
-
-  current_context = new plugin_context (fd);
-
-  // Handshake.
-  cc1_plugin::protocol_int version;
-  if (!current_context->require ('H')
-      || ! ::cc1_plugin::unmarshall (current_context, &version))
-    fatal_error (input_location,
-		 "%s: handshake failed", plugin_info->base_name);
-  if (version != GCC_C_FE_VERSION_1)
-    fatal_error (input_location,
-		 "%s: unknown version in handshake", plugin_info->base_name);
+  generic_plugin_init (plugin_info, GCC_C_FE_VERSION_1);
 
   register_callback (plugin_info->base_name, PLUGIN_PRAGMAS,
 		     plugin_init_extra_pragmas, NULL);
   register_callback (plugin_info->base_name, PLUGIN_PRE_GENERICIZE,
 		     rewrite_decls_to_addresses, NULL);
-  register_callback (plugin_info->base_name, PLUGIN_GGC_MARKING,
-		     gc_mark, NULL);
-
-  lang_hooks.print_error_function = plugin_print_error_function;
 
 #define GCC_METHOD0(R, N)			\
   {						\
diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc
index ba6c5ef2efce..64cde651139c 100644
--- a/libcc1/libcp1plugin.cc
+++ b/libcc1/libcp1plugin.cc
@@ -38,7 +38,6 @@ 
 #include "stringpool.h"
 
 #include "gcc-interface.h"
-#include "hash-set.h"
 #include "machmode.h"
 #include "vec.h"
 #include "double-int.h"
@@ -69,172 +68,19 @@ 
 #include "connection.hh"
 #include "marshall-cp.hh"
 #include "rpc.hh"
+#include "context.hh"
 
 #include <vector>
 
-#ifdef __GNUC__
-#pragma GCC visibility push(default)
-#endif
-int plugin_is_GPL_compatible;
-#ifdef __GNUC__
-#pragma GCC visibility pop
-#endif
+using namespace cc1_plugin;
 
 
 
 static_assert (GCC_CP_SYMBOL_MASK >= GCC_CP_SYMBOL_END,
 	       "GCC_CP_SYMBOL_MASK >= GCC_CP_SYMBOL_END");
 
-// This is put into the lang hooks when the plugin starts.
-
-static void
-plugin_print_error_function (diagnostic_context *context, const char *file,
-			     diagnostic_info *diagnostic)
-{
-  if (current_function_decl != NULL_TREE
-      && DECL_NAME (current_function_decl) != NULL_TREE
-      && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
-		 GCC_FE_WRAPPER_FUNCTION) == 0)
-    return;
-  lhd_print_error_function (context, file, diagnostic);
-}
-
 
 
-static unsigned long long
-convert_out (tree t)
-{
-  return (unsigned long long) (uintptr_t) t;
-}
-
-static tree
-convert_in (unsigned long long v)
-{
-  return (tree) (uintptr_t) v;
-}
-
-
-
-struct decl_addr_value
-{
-  tree decl;
-  tree address;
-};
-
-struct decl_addr_hasher : free_ptr_hash<decl_addr_value>
-{
-  static inline hashval_t hash (const decl_addr_value *);
-  static inline bool equal (const decl_addr_value *, const decl_addr_value *);
-};
-
-inline hashval_t
-decl_addr_hasher::hash (const decl_addr_value *e)
-{
-  return DECL_UID (e->decl);
-}
-
-inline bool
-decl_addr_hasher::equal (const decl_addr_value *p1, const decl_addr_value *p2)
-{
-  return p1->decl == p2->decl;
-}
-
-
-
-struct string_hasher : nofree_ptr_hash<const char>
-{
-  static inline hashval_t hash (const char *s)
-  {
-    return htab_hash_string (s);
-  }
-
-  static inline bool equal (const char *p1, const char *p2)
-  {
-    return strcmp (p1, p2) == 0;
-  }
-};
-
-
-
-struct plugin_context : public cc1_plugin::connection
-{
-  plugin_context (int fd);
-
-  // Map decls to addresses.
-  hash_table<decl_addr_hasher> address_map;
-
-  // A collection of trees that are preserved for the GC.
-  hash_table< nofree_ptr_hash<tree_node> > preserved;
-
-  // File name cache.
-  hash_table<string_hasher> file_names;
-
-  // Perform GC marking.
-  void mark ();
-
-  // Preserve a tree during the plugin's operation.
-  tree preserve (tree t)
-  {
-    tree_node **slot = preserved.find_slot (t, INSERT);
-    *slot = t;
-    return t;
-  }
-
-  location_t get_location_t (const char *filename,
-			     unsigned int line_number)
-  {
-    if (filename == NULL)
-      return UNKNOWN_LOCATION;
-
-    filename = intern_filename (filename);
-    linemap_add (line_table, LC_ENTER, false, filename, line_number);
-    location_t loc = linemap_line_start (line_table, line_number, 0);
-    linemap_add (line_table, LC_LEAVE, false, NULL, 0);
-    return loc;
-  }
-
-private:
-
-  // Add a file name to FILE_NAMES and return the canonical copy.
-  const char *intern_filename (const char *filename)
-  {
-    const char **slot = file_names.find_slot (filename, INSERT);
-    if (*slot == NULL)
-      {
-	/* The file name must live as long as the line map, which
-	   effectively means as long as this compilation.  So, we copy
-	   the string here but never free it.  */
-	*slot = xstrdup (filename);
-      }
-    return *slot;
-  }
-};
-
-static plugin_context *current_context;
-
-
-
-plugin_context::plugin_context (int fd)
-  : cc1_plugin::connection (fd),
-    address_map (30),
-    preserved (30),
-    file_names (30)
-{
-}
-
-void
-plugin_context::mark ()
-{
-  for (const auto &item : address_map)
-    {
-      ggc_mark (item->decl);
-      ggc_mark (item->address);
-    }
-
-  for (const auto &item : preserved)
-    ggc_mark (&item);
-}
-
 static void
 plugin_binding_oracle (enum cp_oracle_request kind, tree identifier)
 {
@@ -3645,15 +3491,6 @@  plugin_add_static_assert (cc1_plugin::connection *self,
 
 
 
-// Perform GC marking.
-
-static void
-gc_mark (void *, void *)
-{
-  if (current_context != NULL)
-    current_context->mark ();
-}
-
 #ifdef __GNUC__
 #pragma GCC visibility push(default)
 #endif
@@ -3662,46 +3499,12 @@  int
 plugin_init (struct plugin_name_args *plugin_info,
 	     struct plugin_gcc_version *)
 {
-  long fd = -1;
-  for (int i = 0; i < plugin_info->argc; ++i)
-    {
-      if (strcmp (plugin_info->argv[i].key, "fd") == 0)
-	{
-	  char *tail;
-	  errno = 0;
-	  fd = strtol (plugin_info->argv[i].value, &tail, 0);
-	  if (*tail != '\0' || errno != 0)
-	    fatal_error (input_location,
-			 "%s: invalid file descriptor argument to plugin",
-			 plugin_info->base_name);
-	  break;
-	}
-    }
-  if (fd == -1)
-    fatal_error (input_location,
-		 "%s: required plugin argument %<fd%> is missing",
-		 plugin_info->base_name);
-
-  current_context = new plugin_context (fd);
-
-  // Handshake.
-  cc1_plugin::protocol_int version;
-  if (!current_context->require ('H')
-      || ! ::cc1_plugin::unmarshall (current_context, &version))
-    fatal_error (input_location,
-		 "%s: handshake failed", plugin_info->base_name);
-  if (version != GCC_CP_FE_VERSION_0)
-    fatal_error (input_location,
-		 "%s: unknown version in handshake", plugin_info->base_name);
+  generic_plugin_init (plugin_info, GCC_CP_FE_VERSION_0);
 
   register_callback (plugin_info->base_name, PLUGIN_PRAGMAS,
 		     plugin_init_extra_pragmas, NULL);
   register_callback (plugin_info->base_name, PLUGIN_PRE_GENERICIZE,
 		     rewrite_decls_to_addresses, NULL);
-  register_callback (plugin_info->base_name, PLUGIN_GGC_MARKING,
-		     gc_mark, NULL);
-
-  lang_hooks.print_error_function = plugin_print_error_function;
 
 #define GCC_METHOD0(R, N)			\
   {						\