[pph] Split streamer into pph-sreamer-out.c and pph-streamer-in.c (issue4333047)

Diego Novillo dnovillo@google.com
Thu Mar 31 02:33:00 GMT 2011


No functional changes.  Just some refactoring to stop mixing up
reading and writing routines in the same file.

Tested on x86_64.

cp/ChangeLog.pph
2011-03-30  Diego Novillo  <dnovillo@google.com>

	* Make-lang.in (CXX_AND_OBJCXX_OBJS): Add cp/pph-streamer-out.o
	and cp/pph-streamer-in.o.
	(cp/pph-streamer-out.o): New.
	(cp/pph-streamer-in.o): New.
	* pph-streamer.c (current_pph_file): Move to cp/pph-streamer-out.c.
	(pph_stream_init_write): Likewise.
	(pph_stream_write_ld_base): Likewise.
	(pph_stream_write_ld_min): Likewise.
	(pph_stream_write_tree_vec): Likewise.
	(pph_stream_write_cxx_binding_1): Likewise.
	(pph_stream_write_cxx_binding): Likewise.
	(pph_stream_write_class_binding): Likewise.
	(pph_stream_write_label_binding): Likewise.
	(pph_stream_write_binding_level): Likewise.
	(pph_stream_write_c_language_function): Likewise.
	(pph_stream_write_language_function): Likewise.
	(pph_stream_write_ld_fn): Likewise.
	(pph_stream_write_ld_ns): Likewise.
	(pph_stream_write_ld_parm): Likewise.
	(pph_stream_write_lang_specific_data): Likewise.
	(pph_stream_write_tree): Likewise.
	(pph_stream_pack_value_fields): Likewise.
	(pph_stream_begin_section): Likewise.
	(pph_stream_write): Likewise.
	(pph_stream_end_section): Likewise.
	(pph_stream_write_header): Likewise.
	(pph_stream_write_body): Likewise.
	(pp_stream_flush_buffers): New.  Factor out of pph_stream_close.
	(pph_get_section_data): Move to cp/pph-streamer-in.c.
	(pph_free_section_data): Likewise.
	(pph_stream_init_read): Likewise.
	(pph_stream_read_tree): Likewise.
	(pph_stream_unpack_value_fields): Likewise.
	* pph-streamer.h (pph_stream_flush_buffers): Declare.
	(pph_stream_init_write): Declare.
	(pph_stream_write_tree): Declare.
	(pph_stream_pack_value_fields): Declare.
	(pph_stream_init_read): Declare.
	(pph_stream_read_tree): Declare.
	(pph_stream_unpack_value_fields): Declare.
	* pph-streamer-out.c: New file.
	* pph-streamer-in.c: New file.

diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 70548c6..143df46 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -81,7 +81,8 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \
  cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
  cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \
  cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
- cp/cp-gimplify.o cp/pph.o cp/pph-streamer.o tree-mudflap.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o cp/pph.o cp/pph-streamer.o cp/pph-streamer-out.o \
+ cp/pph-streamer-in.o tree-mudflap.o $(CXX_C_OBJS)
 
 # Language-specific object files for C++.
 CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
@@ -337,3 +338,11 @@ cp/pph.o: cp/pph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(CPPLIB_H) \
 cp/pph-streamer.o: cp/pph-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 	$(TREE_H) tree-pretty-print.h $(LTO_STREAMER_H) $(CXX_PPH_STREAMER_H) \
 	$(CXX_PPH_H) $(TREE_PASS_H) version.h cppbuiltin.h tree-iterator.h
+cp/pph-streamer-out.o: cp/pph-streamer-out.c $(CONFIG_H) $(SYSTEM_H) \
+	coretypes.h $(TREE_H) tree-pretty-print.h $(LTO_STREAMER_H) \
+	$(CXX_PPH_STREAMER_H) $(CXX_PPH_H) $(TREE_PASS_H) version.h \
+	cppbuiltin.h tree-iterator.h
+cp/pph-streamer-in.o: cp/pph-streamer-in.c $(CONFIG_H) $(SYSTEM_H) \
+	coretypes.h $(TREE_H) tree-pretty-print.h $(LTO_STREAMER_H) \
+	$(CXX_PPH_STREAMER_H) $(CXX_PPH_H) $(TREE_PASS_H) version.h \
+	cppbuiltin.h tree-iterator.h
diff --git a/gcc/cp/pph-streamer-in.c b/gcc/cp/pph-streamer-in.c
new file mode 100644
index 0000000..aaa0a6c
--- /dev/null
+++ b/gcc/cp/pph-streamer-in.c
@@ -0,0 +1,155 @@
+/* Routines for reading PPH data.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>.
+
+   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 "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "langhooks.h"
+#include "tree-iterator.h"
+#include "tree-pretty-print.h"
+#include "lto-streamer.h"
+#include "pph-streamer.h"
+#include "pph.h"
+#include "tree-pass.h"
+#include "version.h"
+#include "cppbuiltin.h"
+
+
+/* Get the section with name NAME and type SECTION_TYPE from FILE_DATA.
+   Return a pointer to the start of the section contents and store
+   the length of the section in *LEN_P.
+
+   FIXME pph, this does not currently handle multiple sections.  It
+   assumes that the file has exactly one section.  */
+
+static const char *
+pph_get_section_data (struct lto_file_decl_data *file_data,
+		      enum lto_section_type section_type ATTRIBUTE_UNUSED,
+		      const char *name ATTRIBUTE_UNUSED,
+		      size_t *len)
+{
+  /* FIXME pph - Stop abusing lto_file_decl_data fields.  */
+  const pph_stream *stream = (const pph_stream *) file_data->file_name;
+  *len = stream->file_size - sizeof (pph_file_header);
+  return (const char *) stream->file_data + sizeof (pph_file_header);
+}
+
+
+/* Free the section data from FILE_DATA of SECTION_TYPE and NAME that
+   starts at OFFSET and has LEN bytes.  */
+
+static void
+pph_free_section_data (struct lto_file_decl_data *file_data,
+		   enum lto_section_type section_type ATTRIBUTE_UNUSED,
+		   const char *name ATTRIBUTE_UNUSED,
+		   const char *offset ATTRIBUTE_UNUSED,
+		   size_t len ATTRIBUTE_UNUSED)
+{
+  /* FIXME pph - Stop abusing lto_file_decl_data fields.  */
+  const pph_stream *stream = (const pph_stream *) file_data->file_name;
+  free (stream->file_data);
+}
+
+
+/* Read into memory the contents of the file in STREAM.  Initialize
+   internal tables and data structures needed to re-construct the
+   ASTs in the file.  */
+
+void
+pph_stream_init_read (pph_stream *stream)
+{
+  struct stat st;
+  size_t i, bytes_read, strtab_size, body_size;
+  int retcode;
+  pph_file_header *header;
+  const char *strtab, *body;
+
+  /* Read STREAM->NAME into the memory buffer STREAM->FILE_DATA.
+     FIXME pph, we are reading the whole file at once.  This seems
+     wasteful.  */
+  retcode = fstat (fileno (stream->file), &st);
+  gcc_assert (retcode == 0);
+  stream->file_size = (size_t) st.st_size;
+  stream->file_data = XCNEWVEC (char, stream->file_size);
+  bytes_read = fread (stream->file_data, 1, stream->file_size, stream->file);
+  gcc_assert (bytes_read == stream->file_size);
+
+  /* Set LTO callbacks to read the PPH file.  */
+  stream->pph_sections = XCNEWVEC (struct lto_file_decl_data *,
+				   PPH_NUM_SECTIONS);
+  for (i = 0; i < PPH_NUM_SECTIONS; i++)
+    {
+      stream->pph_sections[i] = XCNEW (struct lto_file_decl_data);
+      /* FIXME pph - Stop abusing fields in lto_file_decl_data.  */
+      stream->pph_sections[i]->file_name = (const char *) stream;
+    }
+
+  lto_set_in_hooks (stream->pph_sections, pph_get_section_data,
+		    pph_free_section_data);
+
+  header = (pph_file_header *) stream->file_data;
+  strtab = (const char *) header + sizeof (pph_file_header);
+  strtab_size = header->strtab_size;
+  body = strtab + strtab_size;
+  gcc_assert (stream->file_size >= strtab_size + sizeof (pph_file_header));
+  body_size = stream->file_size - strtab_size - sizeof (pph_file_header);
+
+  /* Create an input block structure pointing right after the string
+     table.  */
+  stream->ib = XCNEW (struct lto_input_block);
+  LTO_INIT_INPUT_BLOCK_PTR (stream->ib, body, 0, body_size);
+  stream->data_in = lto_data_in_create (stream->pph_sections[0], strtab,
+                                        strtab_size, NULL);
+}
+
+
+/* Callback for reading ASTs from a stream.  This reads all the fields
+   that are not processed by default by the common tree pickler.
+   IB, DATA_IN are as in lto_read_tree.  EXPR is the partially materialized
+   tree.  */
+
+void
+pph_stream_read_tree (struct lto_input_block *ib, struct data_in *data_in,
+		      tree expr)
+{
+  if (TREE_CODE (expr) == FUNCTION_DECL)
+    DECL_SAVED_TREE (expr) = lto_input_tree (ib, data_in);
+  else if (TREE_CODE (expr) == STATEMENT_LIST)
+    {
+      HOST_WIDE_INT i, num_trees = lto_input_sleb128 (ib);
+      for (i = 0; i < num_trees; i++)
+	{
+	  tree stmt = lto_input_tree (ib, data_in);
+	  append_to_statement_list (stmt, &expr);
+	}
+    }
+}
+
+
+/* Callback for unpacking value fields in ASTs.  BP is the bitpack 
+   we are unpacking from.  EXPR is the tree to unpack.  */
+
+void
+pph_stream_unpack_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED,
+				tree expr ATTRIBUTE_UNUSED)
+{
+  /* Do nothing for now.  */
+}
diff --git a/gcc/cp/pph-streamer-out.c b/gcc/cp/pph-streamer-out.c
new file mode 100644
index 0000000..c349d9f
--- /dev/null
+++ b/gcc/cp/pph-streamer-out.c
@@ -0,0 +1,607 @@
+/* Routines for writing PPH data.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+   Contributed by Diego Novillo <dnovillo@google.com>.
+
+   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 "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "langhooks.h"
+#include "tree-iterator.h"
+#include "tree-pretty-print.h"
+#include "lto-streamer.h"
+#include "pph-streamer.h"
+#include "pph.h"
+#include "tree-pass.h"
+#include "version.h"
+#include "cppbuiltin.h"
+
+/* FIXME pph.  This holds the FILE handle for the current PPH file
+   that we are writing.  It is necessary because the LTO callbacks do
+   not allow passing a FILE handle to them.  */
+static FILE *current_pph_file = NULL;
+
+/* Callback for packing value fields in ASTs.  BP is the bitpack 
+   we are packing into.  EXPR is the tree to pack.  */
+
+void
+pph_stream_pack_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED,
+			      tree expr ATTRIBUTE_UNUSED)
+{
+  /* Do nothing for now.  */
+}
+
+
+/* Initialize buffers and tables in STREAM for writing.  */
+
+void
+pph_stream_init_write (pph_stream *stream)
+{
+  stream->out_state = lto_new_out_decl_state ();
+  lto_push_out_decl_state (stream->out_state);
+  stream->decl_state_stream = XCNEW (struct lto_output_stream);
+  stream->ob = create_output_block (LTO_section_decls);
+  pph_set_pph_stream (stream->ob, stream);
+}
+
+
+/* Callback for lang_hooks.lto.begin_section.  Open file NAME.  */
+
+static void
+pph_stream_begin_section (const char *name ATTRIBUTE_UNUSED)
+{
+}
+
+
+/* Callback for lang_hooks.lto.append_data.  Write LEN bytes from DATA
+   into current_pph_file.  BLOCK is currently unused.  */
+
+static void
+pph_stream_write (const void *data, size_t len, void *block ATTRIBUTE_UNUSED)
+{
+  if (data)
+    fwrite (data, len, 1, current_pph_file);
+}
+
+
+/* Callback for lang_hooks.lto.end_section.  */
+
+static void
+pph_stream_end_section (void)
+{
+}
+
+
+/* Write the header for the PPH file represented by STREAM.  */
+
+static void
+pph_stream_write_header (pph_stream *stream)
+{
+  pph_file_header header;
+  struct lto_output_stream header_stream;
+  int major, minor, patchlevel;
+
+  /* Collect version information.  */
+  parse_basever (&major, &minor, &patchlevel);
+  gcc_assert (major == (char) major);
+  gcc_assert (minor == (char) minor);
+  gcc_assert (patchlevel == (char) patchlevel);
+
+  /* Write the header for the PPH file.  */
+  memset (&header, 0, sizeof (header));
+  strcpy (header.id_str, pph_id_str);
+  header.major_version = (char) major;
+  header.minor_version = (char) minor;
+  header.patchlevel = (char) patchlevel;
+  header.strtab_size = stream->ob->string_stream->total_size;
+
+  memset (&header_stream, 0, sizeof (header_stream));
+  lto_output_data_stream (&header_stream, &header, sizeof (header));
+  lto_write_stream (&header_stream);
+}
+
+
+/* Write the body of the PPH file represented by STREAM.  */
+
+static void
+pph_stream_write_body (pph_stream *stream)
+{
+  /* Write the string table.  */
+  lto_write_stream (stream->ob->string_stream);
+
+  /* Write out the physical representation for every AST in all the
+     streams in STREAM->OUT_STATE.  */
+  lto_output_decl_state_streams (stream->ob, stream->out_state);
+
+  /* Now write the vector of all AST references.  */
+  lto_output_decl_state_refs (stream->ob, stream->decl_state_stream,
+			      stream->out_state);
+
+  /* Finally, physically write all the streams.  */
+  lto_write_stream (stream->ob->main_stream);
+}
+
+
+/* Flush all the in-memory buffers for STREAM to disk.  */
+
+void
+pph_stream_flush_buffers (pph_stream *stream)
+{
+  gcc_assert (current_pph_file == NULL);
+  current_pph_file = stream->file;
+
+  /* Redirect the LTO basic I/O langhooks.  */
+  lang_hooks.lto.begin_section = pph_stream_begin_section;
+  lang_hooks.lto.append_data = pph_stream_write;
+  lang_hooks.lto.end_section = pph_stream_end_section;
+
+  /* Write the state buffers built by pph_output_*() calls.  */
+  lto_begin_section (stream->name, false);
+  pph_stream_write_header (stream);
+  pph_stream_write_body (stream);
+  lto_end_section ();
+  current_pph_file = NULL;
+}
+
+
+/* Write all the fields in lang_decl_base instance LDB to OB.  */
+
+static void
+pph_stream_write_ld_base (struct output_block *ob, struct lang_decl_base *ldb)
+{
+  struct bitpack_d bp;
+
+  if (ldb == NULL)
+    {
+      pph_output_uint (pph_get_pph_stream (ob), 0);
+      return;
+    }
+
+  bp = bitpack_create (ob->main_stream);
+  bp_pack_value (&bp, ldb->selector, 16);
+  bp_pack_value (&bp, ldb->language, 4);
+  bp_pack_value (&bp, ldb->use_template, 2);
+  bp_pack_value (&bp, ldb->not_really_extern, 1);
+  bp_pack_value (&bp, ldb->initialized_in_class, 1);
+  bp_pack_value (&bp, ldb->repo_available_p, 1);
+  bp_pack_value (&bp, ldb->threadprivate_or_deleted_p, 1);
+  bp_pack_value (&bp, ldb->anticipated_p, 1);
+  bp_pack_value (&bp, ldb->friend_attr, 1);
+  bp_pack_value (&bp, ldb->template_conv_p, 1);
+  bp_pack_value (&bp, ldb->odr_used, 1);
+  bp_pack_value (&bp, ldb->u2sel, 1);
+  lto_output_bitpack (&bp);
+}
+
+
+/* Write all the fields in lang_decl_min instance LDM to OB.  If REF_P
+   is true, all tree fields should be written as references.  */
+
+static void
+pph_stream_write_ld_min (struct output_block *ob, struct lang_decl_min *ldm,
+		         bool ref_p)
+{
+  if (ldm == 0)
+    {
+      pph_output_uint (pph_get_pph_stream (ob), 0);
+      return;
+    }
+
+  gcc_assert (ldm->base.selector == 0);
+
+  lto_output_tree_or_ref (ob, ldm->template_info, ref_p);
+  if (ldm->base.u2sel == 0)
+    lto_output_tree_or_ref (ob, ldm->u2.access, ref_p);
+  else if (ldm->base.u2sel == 1)
+    lto_output_sleb128_stream (ob->main_stream, ldm->u2.discriminator);
+  else
+    gcc_unreachable ();
+}
+
+
+/* Write all the trees in VEC V to OB.  REF_P is true if the trees should
+   be written as references.  */
+
+static void
+pph_stream_write_tree_vec (struct output_block *ob, VEC(tree,gc) *v, bool ref_p)
+{
+  unsigned i;
+  tree t;
+
+  lto_output_uleb128_stream (ob->main_stream, VEC_length (tree, v));
+  for (i = 0; VEC_iterate (tree, v, i, t); i++)
+    lto_output_tree_or_ref (ob, t, ref_p);
+}
+
+/* Forward declaration to break cyclic dependencies.  */
+static void pph_stream_write_binding_level (struct output_block *,
+					    struct cp_binding_level *, bool);
+
+
+/* Helper for pph_stream_write_cxx_binding.  OB, CB and REF_P are as in
+   pph_stream_write_cxx_binding.  */
+
+static void
+pph_stream_write_cxx_binding_1 (struct output_block *ob, cxx_binding *cb,
+				bool ref_p)
+{
+  struct bitpack_d bp;
+
+  if (cb == NULL)
+    {
+      pph_output_uint (pph_get_pph_stream (ob), 0);
+      return;
+    }
+
+  lto_output_tree_or_ref (ob, cb->value, ref_p);
+  lto_output_tree_or_ref (ob, cb->type, ref_p);
+  pph_stream_write_binding_level (ob, cb->scope, ref_p);
+  bp = bitpack_create (ob->main_stream);
+  bp_pack_value (&bp, cb->value_is_inherited, 1);
+  bp_pack_value (&bp, cb->is_local, 1);
+  lto_output_bitpack (&bp);
+}
+
+
+/* Write all the fields of cxx_binding instance CB to OB.  REF_P is
+   true if the tree fields should be written as references.  */
+
+static void
+pph_stream_write_cxx_binding (struct output_block *ob, cxx_binding *cb,
+			      bool ref_p)
+{
+  unsigned num_bindings;
+  cxx_binding *prev;
+
+  if (cb == NULL)
+    {
+      pph_output_uint (pph_get_pph_stream (ob), 0);
+      return;
+    }
+
+  for (num_bindings = 0, prev = cb->previous; prev; prev = prev->previous)
+    num_bindings++;
+
+  /* Write the list of previous bindings.  */
+  lto_output_sleb128_stream (ob->main_stream, num_bindings);
+  for (prev = cb->previous; prev; prev = prev->previous)
+    pph_stream_write_cxx_binding_1 (ob, prev, ref_p);
+
+  /* Write the current binding at the end.  */
+  pph_stream_write_cxx_binding_1 (ob, cb, ref_p);
+}
+
+
+/* Write all the fields of cp_class_binding instance CB to OB.  REF_P
+   is true if the tree fields should be written as references.  */
+
+static void
+pph_stream_write_class_binding (struct output_block *ob,
+				cp_class_binding *cb, bool ref_p)
+{
+  if (cb == NULL)
+    {
+      pph_output_uint (pph_get_pph_stream (ob), 0);
+      return;
+    }
+
+  pph_stream_write_cxx_binding (ob, &cb->base, ref_p);
+  lto_output_tree_or_ref (ob, cb->identifier, ref_p);
+}
+
+
+/* Write all the fields of cp_label_binding instance LB to OB.  If
+   REF_P is true, tree fields will be written as references.  */
+
+static void
+pph_stream_write_label_binding (struct output_block *ob,
+				cp_label_binding *lb, bool ref_p)
+{
+  if (lb == NULL)
+    {
+      pph_output_uint (pph_get_pph_stream (ob), 0);
+      return;
+    }
+
+  lto_output_tree_or_ref (ob, lb->label, ref_p);
+  lto_output_tree_or_ref (ob, lb->prev_value, ref_p);
+}
+
+
+/* Write all the fields of cp_binding_level instance BL to OB.  If
+   REF_P is true, tree fields will be written as references.  */
+
+static void
+pph_stream_write_binding_level (struct output_block *ob,
+			        struct cp_binding_level *bl, bool ref_p)
+{
+  unsigned i;
+  cp_class_binding *cs;
+  cp_label_binding *sl;
+  struct bitpack_d bp;
+
+  if (bl == NULL)
+    {
+      pph_output_uint (pph_get_pph_stream (ob), 0);
+      return;
+    }
+
+  lto_output_chain (ob, bl->names, ref_p);
+  lto_output_uleb128_stream (ob->main_stream, bl->names_size);
+  lto_output_chain (ob, bl->namespaces, ref_p);
+
+  pph_stream_write_tree_vec (ob, bl->static_decls, ref_p);
+
+  lto_output_chain (ob, bl->usings, ref_p);
+  lto_output_chain (ob, bl->using_directives, ref_p);
+
+  lto_output_uleb128_stream (ob->main_stream, VEC_length (cp_class_binding,
+					                  bl->class_shadowed));
+  for (i = 0; VEC_iterate (cp_class_binding, bl->class_shadowed, i, cs); i++)
+    pph_stream_write_class_binding (ob, cs, ref_p);
+
+  lto_output_tree_or_ref (ob, bl->type_shadowed, ref_p);
+
+  lto_output_uleb128_stream (ob->main_stream, VEC_length (cp_label_binding,
+					                  bl->shadowed_labels));
+  for (i = 0; VEC_iterate (cp_label_binding, bl->shadowed_labels, i, sl); i++)
+    pph_stream_write_label_binding (ob, sl, ref_p);
+
+  lto_output_chain (ob, bl->blocks, ref_p);
+  lto_output_tree_or_ref (ob, bl->this_entity, ref_p);
+  pph_stream_write_binding_level (ob, bl->level_chain, ref_p);
+  pph_stream_write_tree_vec (ob, bl->dead_vars_from_for, ref_p);
+  lto_output_chain (ob, bl->statement_list, ref_p);
+  lto_output_sleb128_stream (ob->main_stream, bl->binding_depth);
+
+  bp = bitpack_create (ob->main_stream);
+  bp_pack_value (&bp, bl->kind, 4);
+  bp_pack_value (&bp, bl->keep, 1);
+  bp_pack_value (&bp, bl->more_cleanups_ok, 1);
+  bp_pack_value (&bp, bl->have_cleanups, 1);
+  lto_output_bitpack (&bp);
+}
+
+
+/* Write all the fields of c_language_function instance CLF to OB.  If
+   REF_P is true, all tree fields should be written as references.  */
+
+static void
+pph_stream_write_c_language_function (struct output_block *ob,
+				      struct c_language_function *clf,
+				      bool ref_p)
+{
+  if (clf == NULL)
+    {
+      pph_output_uint (pph_get_pph_stream (ob), 0);
+      return;
+    }
+
+  lto_output_tree_or_ref (ob, clf->x_stmt_tree.x_cur_stmt_list, ref_p);
+  lto_output_sleb128_stream (ob->main_stream,
+			     clf->x_stmt_tree.stmts_are_full_exprs_p);
+}
+
+
+/* Write all the fields of language_function instance LF to OB.  If
+   REF_P is true, all tree fields should be written as references.  */
+
+static void
+pph_stream_write_language_function (struct output_block *ob,
+				    struct language_function *lf,
+				    bool ref_p)
+{
+  struct bitpack_d bp;
+
+  if (lf == NULL)
+    {
+      pph_output_uint (pph_get_pph_stream (ob), 0);
+      return;
+    }
+
+  pph_stream_write_c_language_function (ob, &lf->base, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_cdtor_label, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_current_class_ptr, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_current_class_ref, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_eh_spec_block, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_in_charge_parm, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_vtt_parm, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_return_value, ref_p);
+  bp = bitpack_create (ob->main_stream);
+  bp_pack_value (&bp, lf->x_returns_value, 1);
+  bp_pack_value (&bp, lf->x_returns_null, 1);
+  bp_pack_value (&bp, lf->x_returns_abnormally, 1);
+  bp_pack_value (&bp, lf->x_in_function_try_handler, 1);
+  bp_pack_value (&bp, lf->x_in_base_initializer, 1);
+  bp_pack_value (&bp, lf->can_throw, 1);
+  lto_output_bitpack (&bp);
+
+  /* FIXME pph.  We are not writing lf->x_named_labels.  */
+
+  pph_stream_write_binding_level (ob, lf->bindings, ref_p);
+  pph_stream_write_tree_vec (ob, lf->x_local_names, ref_p);
+
+  /* FIXME pph.  We are not writing lf->extern_decl_map.  */
+}
+
+
+/* Write all the fields of lang_decl_fn instance LDF to OB.  If REF_P
+   is true, all tree fields should be written as references.  */
+
+static void
+pph_stream_write_ld_fn (struct output_block *ob, struct lang_decl_fn *ldf,
+			bool ref_p)
+{
+  struct bitpack_d bp;
+
+  if (ldf == NULL)
+    {
+      pph_output_uint (pph_get_pph_stream (ob), 0);
+      return;
+    }
+
+  bp = bitpack_create (ob->main_stream);
+  bp_pack_value (&bp, ldf->operator_code, 16);
+  bp_pack_value (&bp, ldf->global_ctor_p, 1);
+  bp_pack_value (&bp, ldf->global_dtor_p, 1);
+  bp_pack_value (&bp, ldf->constructor_attr, 1);
+  bp_pack_value (&bp, ldf->destructor_attr, 1);
+  bp_pack_value (&bp, ldf->assignment_operator_p, 1);
+  bp_pack_value (&bp, ldf->static_function, 1);
+  bp_pack_value (&bp, ldf->pure_virtual, 1);
+  bp_pack_value (&bp, ldf->defaulted_p, 1);
+  bp_pack_value (&bp, ldf->has_in_charge_parm_p, 1);
+  bp_pack_value (&bp, ldf->has_vtt_parm_p, 1);
+  bp_pack_value (&bp, ldf->pending_inline_p, 1);
+  bp_pack_value (&bp, ldf->nonconverting, 1);
+  bp_pack_value (&bp, ldf->thunk_p, 1);
+  bp_pack_value (&bp, ldf->this_thunk_p, 1);
+  bp_pack_value (&bp, ldf->hidden_friend_p, 1);
+  lto_output_bitpack (&bp);
+
+  lto_output_tree_or_ref (ob, ldf->befriending_classes, ref_p);
+  lto_output_tree_or_ref (ob, ldf->context, ref_p);
+
+  if (ldf->thunk_p == 0)
+    lto_output_tree_or_ref (ob, ldf->u5.cloned_function, ref_p);
+  else if (ldf->thunk_p == 1)
+    lto_output_sleb128_stream (ob->main_stream, ldf->u5.fixed_offset);
+  else
+    gcc_unreachable ();
+
+  if (ldf->pending_inline_p == 1)
+    pth_save_token_cache (ldf->u.pending_inline_info, pph_get_pph_stream (ob));
+  else if (ldf->pending_inline_p == 0)
+    pph_stream_write_language_function (ob, ldf->u.saved_language_function,
+					ref_p);
+}
+
+
+/* Write all the fields of lang_decl_ns instance LDNS to OB.  If REF_P
+   is true, all tree fields should be written as references.  */
+
+static void
+pph_stream_write_ld_ns (struct output_block *ob, struct lang_decl_ns *ldns,
+			bool ref_p)
+{
+  struct cp_binding_level *level;
+
+  if (ldns == NULL)
+    {
+      pph_output_uint (pph_get_pph_stream (ob), 0);
+      return;
+    }
+
+  level = ldns->level;
+  pph_stream_write_binding_level (ob, level, ref_p);
+}
+
+
+/* Write all the fields of lang_decl_parm instance LDP to OB.  If REF_P
+   is true, all tree fields should be written as references.  */
+
+static void
+pph_stream_write_ld_parm (struct output_block *ob, struct lang_decl_parm *ldp)
+{
+  if (ldp == NULL)
+    {
+      pph_output_uint (pph_get_pph_stream (ob), 0);
+      return;
+    }
+
+  lto_output_sleb128_stream (ob->main_stream, ldp->level);
+  lto_output_sleb128_stream (ob->main_stream, ldp->index);
+}
+
+
+/* Write all the lang-specific data in DECL to OB.  REF_P is true if
+   the trees referenced in lang-specific fields should be written as
+   references.  */
+
+static void
+pph_stream_write_lang_specific_data (struct output_block *ob,
+				     tree decl, bool ref_p)
+{
+  struct lang_decl *ld;
+  struct lang_decl_base *ldb;
+
+  gcc_assert (DECL_P (decl) && DECL_LANG_SPECIFIC (decl));
+
+  ld = DECL_LANG_SPECIFIC (decl);
+  ldb = &ld->u.base;
+
+  /* Write all the fields in lang_decl_base.  */
+  pph_stream_write_ld_base (ob, ldb);
+  
+  if (ldb->selector == 0)
+    {
+      /* Write all the fields in lang_decl_min.  */
+      pph_stream_write_ld_min (ob, &ld->u.min, ref_p);
+    }
+  else if (ldb->selector == 1)
+    {
+      /* Write all the fields in lang_decl_fn.  */
+      pph_stream_write_ld_fn (ob, &ld->u.fn, ref_p);
+    }
+  else if (ldb->selector == 2)
+    {
+      /* Write all the fields in lang_decl_ns.  */
+      pph_stream_write_ld_ns (ob, &ld->u.ns, ref_p);
+    }
+  else if (ldb->selector == 3)
+    {
+      /* Write all the fields in lang_decl_parm.  */
+      pph_stream_write_ld_parm (ob, &ld->u.parm);
+    }
+  else
+    gcc_unreachable ();
+}
+
+
+/* Callback for writing ASTs to a stream.  This writes all the fields
+   that are not processed by default by the common tree pickler.
+   OB and REF_P are as in lto_write_tree.  EXPR is the tree to write.  */
+
+void
+pph_stream_write_tree (struct output_block *ob, tree expr, bool ref_p)
+{
+  if (DECL_P (expr))
+    {
+      if (DECL_LANG_SPECIFIC (expr))
+	pph_stream_write_lang_specific_data (ob, expr, ref_p);
+
+      if (TREE_CODE (expr) == FUNCTION_DECL)
+	lto_output_tree_or_ref (ob, DECL_SAVED_TREE (expr), ref_p);
+    }
+  else if (TREE_CODE (expr) == STATEMENT_LIST)
+    {
+      tree_stmt_iterator i;
+      unsigned num_stmts;
+
+      /* Compute and write the number of statements in the list.  */
+      for (num_stmts = 0, i = tsi_start (expr); !tsi_end_p (i); tsi_next (&i))
+	num_stmts++;
+
+      lto_output_sleb128_stream (ob->main_stream, num_stmts);
+
+      /* Write the statements.  */
+      for (i = tsi_start (expr); !tsi_end_p (i); tsi_next (&i))
+	lto_output_tree_or_ref (ob, tsi_stmt (i), ref_p);
+    }
+}
diff --git a/gcc/cp/pph-streamer.c b/gcc/cp/pph-streamer.c
index e7f0423..989bbbe 100644
--- a/gcc/cp/pph-streamer.c
+++ b/gcc/cp/pph-streamer.c
@@ -32,583 +32,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "version.h"
 #include "cppbuiltin.h"
 
-/* FIXME pph.  This holds the FILE handle for the current PPH file
-   that we are writing.  It is necessary because the LTO callbacks do
-   not allow passing a FILE handle to them.  */
-static FILE *current_pph_file = NULL;
-
-
-/* Get the section with name NAME and type SECTION_TYPE from FILE_DATA.
-   Return a pointer to the start of the section contents and store
-   the length of the section in *LEN_P.
-
-   FIXME pph, this does not currently handle multiple sections.  It
-   assumes that the file has exactly one section.  */
-
-static const char *
-pph_get_section_data (struct lto_file_decl_data *file_data,
-		      enum lto_section_type section_type ATTRIBUTE_UNUSED,
-		      const char *name ATTRIBUTE_UNUSED,
-		      size_t *len)
-{
-  /* FIXME pph - Stop abusing lto_file_decl_data fields.  */
-  const pph_stream *stream = (const pph_stream *) file_data->file_name;
-  *len = stream->file_size - sizeof (pph_file_header);
-  return (const char *) stream->file_data + sizeof (pph_file_header);
-}
-
-
-/* Free the section data from FILE_DATA of SECTION_TYPE and NAME that
-   starts at OFFSET and has LEN bytes.  */
-
-static void
-pph_free_section_data (struct lto_file_decl_data *file_data,
-		   enum lto_section_type section_type ATTRIBUTE_UNUSED,
-		   const char *name ATTRIBUTE_UNUSED,
-		   const char *offset ATTRIBUTE_UNUSED,
-		   size_t len ATTRIBUTE_UNUSED)
-{
-  /* FIXME pph - Stop abusing lto_file_decl_data fields.  */
-  const pph_stream *stream = (const pph_stream *) file_data->file_name;
-  free (stream->file_data);
-}
-
-
-/* Read into memory the contents of the file in STREAM.  Initialize
-   internal tables and data structures needed to re-construct the
-   ASTs in the file.  */
-
-static void
-pph_stream_init_read (pph_stream *stream)
-{
-  struct stat st;
-  size_t i, bytes_read, strtab_size, body_size;
-  int retcode;
-  pph_file_header *header;
-  const char *strtab, *body;
-
-  /* Read STREAM->NAME into the memory buffer STREAM->FILE_DATA.
-     FIXME pph, we are reading the whole file at once.  This seems
-     wasteful.  */
-  retcode = fstat (fileno (stream->file), &st);
-  gcc_assert (retcode == 0);
-  stream->file_size = (size_t) st.st_size;
-  stream->file_data = XCNEWVEC (char, stream->file_size);
-  bytes_read = fread (stream->file_data, 1, stream->file_size, stream->file);
-  gcc_assert (bytes_read == stream->file_size);
-
-  /* Set LTO callbacks to read the PPH file.  */
-  stream->pph_sections = XCNEWVEC (struct lto_file_decl_data *,
-				   PPH_NUM_SECTIONS);
-  for (i = 0; i < PPH_NUM_SECTIONS; i++)
-    {
-      stream->pph_sections[i] = XCNEW (struct lto_file_decl_data);
-      /* FIXME pph - Stop abusing fields in lto_file_decl_data.  */
-      stream->pph_sections[i]->file_name = (const char *) stream;
-    }
-
-  lto_set_in_hooks (stream->pph_sections, pph_get_section_data,
-		    pph_free_section_data);
-
-  header = (pph_file_header *) stream->file_data;
-  strtab = (const char *) header + sizeof (pph_file_header);
-  strtab_size = header->strtab_size;
-  body = strtab + strtab_size;
-  gcc_assert (stream->file_size >= strtab_size + sizeof (pph_file_header));
-  body_size = stream->file_size - strtab_size - sizeof (pph_file_header);
-
-  /* Create an input block structure pointing right after the string
-     table.  */
-  stream->ib = XCNEW (struct lto_input_block);
-  LTO_INIT_INPUT_BLOCK_PTR (stream->ib, body, 0, body_size);
-  stream->data_in = lto_data_in_create (stream->pph_sections[0], strtab,
-                                        strtab_size, NULL);
-}
-
-
-/* Initialize buffers and tables in STREAM for writing.  */
-
-static void
-pph_stream_init_write (pph_stream *stream)
-{
-  stream->out_state = lto_new_out_decl_state ();
-  lto_push_out_decl_state (stream->out_state);
-  stream->decl_state_stream = XCNEW (struct lto_output_stream);
-  stream->ob = create_output_block (LTO_section_decls);
-  pph_set_pph_stream (stream->ob, stream);
-}
-
-
-/* Write all the fields in lang_decl_base instance LDB to OB.  */
-
-static void
-pph_stream_write_ld_base (struct output_block *ob, struct lang_decl_base *ldb)
-{
-  struct bitpack_d bp;
-
-  if (ldb == NULL)
-    {
-      pph_output_uint (pph_get_pph_stream (ob), 0);
-      return;
-    }
-
-  bp = bitpack_create (ob->main_stream);
-  bp_pack_value (&bp, ldb->selector, 16);
-  bp_pack_value (&bp, ldb->language, 4);
-  bp_pack_value (&bp, ldb->use_template, 2);
-  bp_pack_value (&bp, ldb->not_really_extern, 1);
-  bp_pack_value (&bp, ldb->initialized_in_class, 1);
-  bp_pack_value (&bp, ldb->repo_available_p, 1);
-  bp_pack_value (&bp, ldb->threadprivate_or_deleted_p, 1);
-  bp_pack_value (&bp, ldb->anticipated_p, 1);
-  bp_pack_value (&bp, ldb->friend_attr, 1);
-  bp_pack_value (&bp, ldb->template_conv_p, 1);
-  bp_pack_value (&bp, ldb->odr_used, 1);
-  bp_pack_value (&bp, ldb->u2sel, 1);
-  lto_output_bitpack (&bp);
-}
-
-
-/* Write all the fields in lang_decl_min instance LDM to OB.  If REF_P
-   is true, all tree fields should be written as references.  */
-
-static void
-pph_stream_write_ld_min (struct output_block *ob, struct lang_decl_min *ldm,
-		         bool ref_p)
-{
-  if (ldm == 0)
-    {
-      pph_output_uint (pph_get_pph_stream (ob), 0);
-      return;
-    }
-
-  gcc_assert (ldm->base.selector == 0);
-
-  lto_output_tree_or_ref (ob, ldm->template_info, ref_p);
-  if (ldm->base.u2sel == 0)
-    lto_output_tree_or_ref (ob, ldm->u2.access, ref_p);
-  else if (ldm->base.u2sel == 1)
-    lto_output_sleb128_stream (ob->main_stream, ldm->u2.discriminator);
-  else
-    gcc_unreachable ();
-}
-
-
-/* Write all the trees in VEC V to OB.  REF_P is true if the trees should
-   be written as references.  */
-
-static void
-pph_stream_write_tree_vec (struct output_block *ob, VEC(tree,gc) *v, bool ref_p)
-{
-  unsigned i;
-  tree t;
-
-  lto_output_uleb128_stream (ob->main_stream, VEC_length (tree, v));
-  for (i = 0; VEC_iterate (tree, v, i, t); i++)
-    lto_output_tree_or_ref (ob, t, ref_p);
-}
-
-/* Forward declaration to break cyclic dependencies.  */
-static void pph_stream_write_binding_level (struct output_block *,
-					    struct cp_binding_level *, bool);
-
-
-/* Helper for pph_stream_write_cxx_binding.  OB, CB and REF_P are as in
-   pph_stream_write_cxx_binding.  */
-
-static void
-pph_stream_write_cxx_binding_1 (struct output_block *ob, cxx_binding *cb,
-				bool ref_p)
-{
-  struct bitpack_d bp;
-
-  if (cb == NULL)
-    {
-      pph_output_uint (pph_get_pph_stream (ob), 0);
-      return;
-    }
-
-  lto_output_tree_or_ref (ob, cb->value, ref_p);
-  lto_output_tree_or_ref (ob, cb->type, ref_p);
-  pph_stream_write_binding_level (ob, cb->scope, ref_p);
-  bp = bitpack_create (ob->main_stream);
-  bp_pack_value (&bp, cb->value_is_inherited, 1);
-  bp_pack_value (&bp, cb->is_local, 1);
-  lto_output_bitpack (&bp);
-}
-
-
-/* Write all the fields of cxx_binding instance CB to OB.  REF_P is
-   true if the tree fields should be written as references.  */
-
-static void
-pph_stream_write_cxx_binding (struct output_block *ob, cxx_binding *cb,
-			      bool ref_p)
-{
-  unsigned num_bindings;
-  cxx_binding *prev;
-
-  if (cb == NULL)
-    {
-      pph_output_uint (pph_get_pph_stream (ob), 0);
-      return;
-    }
-
-  for (num_bindings = 0, prev = cb->previous; prev; prev = prev->previous)
-    num_bindings++;
-
-  /* Write the list of previous bindings.  */
-  lto_output_sleb128_stream (ob->main_stream, num_bindings);
-  for (prev = cb->previous; prev; prev = prev->previous)
-    pph_stream_write_cxx_binding_1 (ob, prev, ref_p);
-
-  /* Write the current binding at the end.  */
-  pph_stream_write_cxx_binding_1 (ob, cb, ref_p);
-}
-
-
-/* Write all the fields of cp_class_binding instance CB to OB.  REF_P
-   is true if the tree fields should be written as references.  */
-
-static void
-pph_stream_write_class_binding (struct output_block *ob,
-				cp_class_binding *cb, bool ref_p)
-{
-  if (cb == NULL)
-    {
-      pph_output_uint (pph_get_pph_stream (ob), 0);
-      return;
-    }
-
-  pph_stream_write_cxx_binding (ob, &cb->base, ref_p);
-  lto_output_tree_or_ref (ob, cb->identifier, ref_p);
-}
-
-
-/* Write all the fields of cp_label_binding instance LB to OB.  If
-   REF_P is true, tree fields will be written as references.  */
-
-static void
-pph_stream_write_label_binding (struct output_block *ob,
-				cp_label_binding *lb, bool ref_p)
-{
-  if (lb == NULL)
-    {
-      pph_output_uint (pph_get_pph_stream (ob), 0);
-      return;
-    }
-
-  lto_output_tree_or_ref (ob, lb->label, ref_p);
-  lto_output_tree_or_ref (ob, lb->prev_value, ref_p);
-}
-
-
-/* Write all the fields of cp_binding_level instance BL to OB.  If
-   REF_P is true, tree fields will be written as references.  */
-
-static void
-pph_stream_write_binding_level (struct output_block *ob,
-			        struct cp_binding_level *bl, bool ref_p)
-{
-  unsigned i;
-  cp_class_binding *cs;
-  cp_label_binding *sl;
-  struct bitpack_d bp;
-
-  if (bl == NULL)
-    {
-      pph_output_uint (pph_get_pph_stream (ob), 0);
-      return;
-    }
-
-  lto_output_chain (ob, bl->names, ref_p);
-  lto_output_uleb128_stream (ob->main_stream, bl->names_size);
-  lto_output_chain (ob, bl->namespaces, ref_p);
-
-  pph_stream_write_tree_vec (ob, bl->static_decls, ref_p);
-
-  lto_output_chain (ob, bl->usings, ref_p);
-  lto_output_chain (ob, bl->using_directives, ref_p);
-
-  lto_output_uleb128_stream (ob->main_stream, VEC_length (cp_class_binding,
-					                  bl->class_shadowed));
-  for (i = 0; VEC_iterate (cp_class_binding, bl->class_shadowed, i, cs); i++)
-    pph_stream_write_class_binding (ob, cs, ref_p);
-
-  lto_output_tree_or_ref (ob, bl->type_shadowed, ref_p);
-
-  lto_output_uleb128_stream (ob->main_stream, VEC_length (cp_label_binding,
-					                  bl->shadowed_labels));
-  for (i = 0; VEC_iterate (cp_label_binding, bl->shadowed_labels, i, sl); i++)
-    pph_stream_write_label_binding (ob, sl, ref_p);
-
-  lto_output_chain (ob, bl->blocks, ref_p);
-  lto_output_tree_or_ref (ob, bl->this_entity, ref_p);
-  pph_stream_write_binding_level (ob, bl->level_chain, ref_p);
-  pph_stream_write_tree_vec (ob, bl->dead_vars_from_for, ref_p);
-  lto_output_chain (ob, bl->statement_list, ref_p);
-  lto_output_sleb128_stream (ob->main_stream, bl->binding_depth);
-
-  bp = bitpack_create (ob->main_stream);
-  bp_pack_value (&bp, bl->kind, 4);
-  bp_pack_value (&bp, bl->keep, 1);
-  bp_pack_value (&bp, bl->more_cleanups_ok, 1);
-  bp_pack_value (&bp, bl->have_cleanups, 1);
-  lto_output_bitpack (&bp);
-}
-
-
-/* Write all the fields of c_language_function instance CLF to OB.  If
-   REF_P is true, all tree fields should be written as references.  */
-
-static void
-pph_stream_write_c_language_function (struct output_block *ob,
-				      struct c_language_function *clf,
-				      bool ref_p)
-{
-  if (clf == NULL)
-    {
-      pph_output_uint (pph_get_pph_stream (ob), 0);
-      return;
-    }
-
-  lto_output_tree_or_ref (ob, clf->x_stmt_tree.x_cur_stmt_list, ref_p);
-  lto_output_sleb128_stream (ob->main_stream,
-			     clf->x_stmt_tree.stmts_are_full_exprs_p);
-}
-
-
-/* Write all the fields of language_function instance LF to OB.  If
-   REF_P is true, all tree fields should be written as references.  */
-
-static void
-pph_stream_write_language_function (struct output_block *ob,
-				    struct language_function *lf,
-				    bool ref_p)
-{
-  struct bitpack_d bp;
-
-  if (lf == NULL)
-    {
-      pph_output_uint (pph_get_pph_stream (ob), 0);
-      return;
-    }
-
-  pph_stream_write_c_language_function (ob, &lf->base, ref_p);
-  lto_output_tree_or_ref (ob, lf->x_cdtor_label, ref_p);
-  lto_output_tree_or_ref (ob, lf->x_current_class_ptr, ref_p);
-  lto_output_tree_or_ref (ob, lf->x_current_class_ref, ref_p);
-  lto_output_tree_or_ref (ob, lf->x_eh_spec_block, ref_p);
-  lto_output_tree_or_ref (ob, lf->x_in_charge_parm, ref_p);
-  lto_output_tree_or_ref (ob, lf->x_vtt_parm, ref_p);
-  lto_output_tree_or_ref (ob, lf->x_return_value, ref_p);
-  bp = bitpack_create (ob->main_stream);
-  bp_pack_value (&bp, lf->x_returns_value, 1);
-  bp_pack_value (&bp, lf->x_returns_null, 1);
-  bp_pack_value (&bp, lf->x_returns_abnormally, 1);
-  bp_pack_value (&bp, lf->x_in_function_try_handler, 1);
-  bp_pack_value (&bp, lf->x_in_base_initializer, 1);
-  bp_pack_value (&bp, lf->can_throw, 1);
-  lto_output_bitpack (&bp);
-
-  /* FIXME pph.  We are not writing lf->x_named_labels.  */
-
-  pph_stream_write_binding_level (ob, lf->bindings, ref_p);
-  pph_stream_write_tree_vec (ob, lf->x_local_names, ref_p);
-
-  /* FIXME pph.  We are not writing lf->extern_decl_map.  */
-}
-
-
-/* Write all the fields of lang_decl_fn instance LDF to OB.  If REF_P
-   is true, all tree fields should be written as references.  */
-
-static void
-pph_stream_write_ld_fn (struct output_block *ob, struct lang_decl_fn *ldf,
-			bool ref_p)
-{
-  struct bitpack_d bp;
-
-  if (ldf == NULL)
-    {
-      pph_output_uint (pph_get_pph_stream (ob), 0);
-      return;
-    }
-
-  bp = bitpack_create (ob->main_stream);
-  bp_pack_value (&bp, ldf->operator_code, 16);
-  bp_pack_value (&bp, ldf->global_ctor_p, 1);
-  bp_pack_value (&bp, ldf->global_dtor_p, 1);
-  bp_pack_value (&bp, ldf->constructor_attr, 1);
-  bp_pack_value (&bp, ldf->destructor_attr, 1);
-  bp_pack_value (&bp, ldf->assignment_operator_p, 1);
-  bp_pack_value (&bp, ldf->static_function, 1);
-  bp_pack_value (&bp, ldf->pure_virtual, 1);
-  bp_pack_value (&bp, ldf->defaulted_p, 1);
-  bp_pack_value (&bp, ldf->has_in_charge_parm_p, 1);
-  bp_pack_value (&bp, ldf->has_vtt_parm_p, 1);
-  bp_pack_value (&bp, ldf->pending_inline_p, 1);
-  bp_pack_value (&bp, ldf->nonconverting, 1);
-  bp_pack_value (&bp, ldf->thunk_p, 1);
-  bp_pack_value (&bp, ldf->this_thunk_p, 1);
-  bp_pack_value (&bp, ldf->hidden_friend_p, 1);
-  lto_output_bitpack (&bp);
-
-  lto_output_tree_or_ref (ob, ldf->befriending_classes, ref_p);
-  lto_output_tree_or_ref (ob, ldf->context, ref_p);
-
-  if (ldf->thunk_p == 0)
-    lto_output_tree_or_ref (ob, ldf->u5.cloned_function, ref_p);
-  else if (ldf->thunk_p == 1)
-    lto_output_sleb128_stream (ob->main_stream, ldf->u5.fixed_offset);
-  else
-    gcc_unreachable ();
-
-  if (ldf->pending_inline_p == 1)
-    pth_save_token_cache (ldf->u.pending_inline_info, pph_get_pph_stream (ob));
-  else if (ldf->pending_inline_p == 0)
-    pph_stream_write_language_function (ob, ldf->u.saved_language_function,
-					ref_p);
-}
-
-
-/* Write all the fields of lang_decl_ns instance LDNS to OB.  If REF_P
-   is true, all tree fields should be written as references.  */
-
-static void
-pph_stream_write_ld_ns (struct output_block *ob, struct lang_decl_ns *ldns,
-			bool ref_p)
-{
-  struct cp_binding_level *level;
-
-  if (ldns == NULL)
-    {
-      pph_output_uint (pph_get_pph_stream (ob), 0);
-      return;
-    }
-
-  level = ldns->level;
-  pph_stream_write_binding_level (ob, level, ref_p);
-}
-
-
-/* Write all the fields of lang_decl_parm instance LDP to OB.  If REF_P
-   is true, all tree fields should be written as references.  */
-
-static void
-pph_stream_write_ld_parm (struct output_block *ob, struct lang_decl_parm *ldp)
-{
-  if (ldp == NULL)
-    {
-      pph_output_uint (pph_get_pph_stream (ob), 0);
-      return;
-    }
-
-  lto_output_sleb128_stream (ob->main_stream, ldp->level);
-  lto_output_sleb128_stream (ob->main_stream, ldp->index);
-}
-
-
-/* Write all the lang-specific data in DECL to OB.  REF_P is true if
-   the trees referenced in lang-specific fields should be written as
-   references.  */
-
-static void
-pph_stream_write_lang_specific_data (struct output_block *ob,
-				     tree decl, bool ref_p)
-{
-  struct lang_decl *ld;
-  struct lang_decl_base *ldb;
-
-  gcc_assert (DECL_P (decl) && DECL_LANG_SPECIFIC (decl));
-
-  ld = DECL_LANG_SPECIFIC (decl);
-  ldb = &ld->u.base;
-
-  /* Write all the fields in lang_decl_base.  */
-  pph_stream_write_ld_base (ob, ldb);
-  
-  if (ldb->selector == 0)
-    {
-      /* Write all the fields in lang_decl_min.  */
-      pph_stream_write_ld_min (ob, &ld->u.min, ref_p);
-    }
-  else if (ldb->selector == 1)
-    {
-      /* Write all the fields in lang_decl_fn.  */
-      pph_stream_write_ld_fn (ob, &ld->u.fn, ref_p);
-    }
-  else if (ldb->selector == 2)
-    {
-      /* Write all the fields in lang_decl_ns.  */
-      pph_stream_write_ld_ns (ob, &ld->u.ns, ref_p);
-    }
-  else if (ldb->selector == 3)
-    {
-      /* Write all the fields in lang_decl_parm.  */
-      pph_stream_write_ld_parm (ob, &ld->u.parm);
-    }
-  else
-    gcc_unreachable ();
-}
-
-
-/* Callback for writing ASTs to a stream.  This writes all the fields
-   that are not processed by default by the common tree pickler.
-   OB and REF_P are as in lto_write_tree.  EXPR is the tree to write.  */
-
-static void
-pph_stream_write_tree (struct output_block *ob, tree expr, bool ref_p)
-{
-  if (DECL_P (expr))
-    {
-      if (DECL_LANG_SPECIFIC (expr))
-	pph_stream_write_lang_specific_data (ob, expr, ref_p);
-
-      if (TREE_CODE (expr) == FUNCTION_DECL)
-	lto_output_tree_or_ref (ob, DECL_SAVED_TREE (expr), ref_p);
-    }
-  else if (TREE_CODE (expr) == STATEMENT_LIST)
-    {
-      tree_stmt_iterator i;
-      unsigned num_stmts;
-
-      /* Compute and write the number of statements in the list.  */
-      for (num_stmts = 0, i = tsi_start (expr); !tsi_end_p (i); tsi_next (&i))
-	num_stmts++;
-
-      lto_output_sleb128_stream (ob->main_stream, num_stmts);
-
-      /* Write the statements.  */
-      for (i = tsi_start (expr); !tsi_end_p (i); tsi_next (&i))
-	lto_output_tree_or_ref (ob, tsi_stmt (i), ref_p);
-    }
-}
-
-
-/* Callback for reading ASTs from a stream.  This reads all the fields
-   that are not processed by default by the common tree pickler.
-   IB, DATA_IN are as in lto_read_tree.  EXPR is the partially materialized
-   tree.  */
-
-static void
-pph_stream_read_tree (struct lto_input_block *ib, struct data_in *data_in,
-		      tree expr)
-{
-  if (TREE_CODE (expr) == FUNCTION_DECL)
-    DECL_SAVED_TREE (expr) = lto_input_tree (ib, data_in);
-  else if (TREE_CODE (expr) == STATEMENT_LIST)
-    {
-      HOST_WIDE_INT i, num_trees = lto_input_sleb128 (ib);
-      for (i = 0; i < num_trees; i++)
-	{
-	  tree stmt = lto_input_tree (ib, data_in);
-	  append_to_statement_list (stmt, &expr);
-	}
-    }
-}
-
-
 /* Return true if the given tree T is streamable.  */
 
 static bool
@@ -621,28 +44,6 @@ pph_is_streamable (tree t ATTRIBUTE_UNUSED)
 }
 
 
-/* Callback for packing value fields in ASTs.  BP is the bitpack 
-   we are packing into.  EXPR is the tree to pack.  */
-
-static void
-pph_stream_pack_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED,
-			      tree expr ATTRIBUTE_UNUSED)
-{
-  /* Do nothing for now.  */
-}
-
-
-/* Callback for unpacking value fields in ASTs.  BP is the bitpack 
-   we are unpacking from.  EXPR is the tree to unpack.  */
-
-static void
-pph_stream_unpack_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED,
-				tree expr ATTRIBUTE_UNUSED)
-{
-  /* Do nothing for now.  */
-}
-
-
 /* Return true if T can be emitted in the decls table as a reference.
    This should only handle C++ specific declarations.  All others are
    handled by the LTO streamer directly.  */
@@ -698,83 +99,6 @@ pph_stream_open (const char *name, const char *mode)
 }
 
 
-/* Callback for lang_hooks.lto.begin_section.  Open file NAME.  */
-
-static void
-pph_stream_begin_section (const char *name ATTRIBUTE_UNUSED)
-{
-}
-
-
-/* Callback for lang_hooks.lto.append_data.  Write LEN bytes from DATA
-   into current_pph_file.  BLOCK is currently unused.  */
-
-static void
-pph_stream_write (const void *data, size_t len, void *block ATTRIBUTE_UNUSED)
-{
-  if (data)
-    fwrite (data, len, 1, current_pph_file);
-}
-
-
-/* Callback for lang_hooks.lto.end_section.  */
-
-static void
-pph_stream_end_section (void)
-{
-}
-
-
-/* Write the header for the PPH file represented by STREAM.  */
-
-static void
-pph_stream_write_header (pph_stream *stream)
-{
-  pph_file_header header;
-  struct lto_output_stream header_stream;
-  int major, minor, patchlevel;
-
-  /* Collect version information.  */
-  parse_basever (&major, &minor, &patchlevel);
-  gcc_assert (major == (char) major);
-  gcc_assert (minor == (char) minor);
-  gcc_assert (patchlevel == (char) patchlevel);
-
-  /* Write the header for the PPH file.  */
-  memset (&header, 0, sizeof (header));
-  strcpy (header.id_str, pph_id_str);
-  header.major_version = (char) major;
-  header.minor_version = (char) minor;
-  header.patchlevel = (char) patchlevel;
-  header.strtab_size = stream->ob->string_stream->total_size;
-
-  memset (&header_stream, 0, sizeof (header_stream));
-  lto_output_data_stream (&header_stream, &header, sizeof (header));
-  lto_write_stream (&header_stream);
-}
-
-
-/* Write the body of the PPH file represented by STREAM.  */
-
-static void
-pph_stream_write_body (pph_stream *stream)
-{
-  /* Write the string table.  */
-  lto_write_stream (stream->ob->string_stream);
-
-  /* Write out the physical representation for every AST in all the
-     streams in STREAM->OUT_STATE.  */
-  lto_output_decl_state_streams (stream->ob, stream->out_state);
-
-  /* Now write the vector of all AST references.  */
-  lto_output_decl_state_refs (stream->ob, stream->decl_state_stream,
-			      stream->out_state);
-
-  /* Finally, physically write all the streams.  */
-  lto_write_stream (stream->ob->main_stream);
-}
-
-
 /* Close PPH stream STREAM.  Write all the ASTs to disk and deallocate
    all memory used by it.  */
 
@@ -782,24 +106,9 @@ void
 pph_stream_close (pph_stream *stream)
 {
   if (stream->write_p)
-    {
-      gcc_assert (current_pph_file == NULL);
-      current_pph_file = stream->file;
-
-      /* Redirect the LTO basic I/O langhooks.  */
-      lang_hooks.lto.begin_section = pph_stream_begin_section;
-      lang_hooks.lto.append_data = pph_stream_write;
-      lang_hooks.lto.end_section = pph_stream_end_section;
-
-      /* Write the state buffers built by pph_output_*() calls.  */
-      lto_begin_section (stream->name, false);
-      pph_stream_write_header (stream);
-      pph_stream_write_body (stream);
-      lto_end_section ();
-    }
-
+    pph_stream_flush_buffers (stream);
   fclose (stream->file);
-  stream->file = current_pph_file = NULL;
+  stream->file = NULL;
 }
 
 
@@ -812,6 +121,7 @@ enum pph_trace_type
     PPH_TRACE_STRING
 };
 
+
 /* Print tracing information for STREAM on pph_logfile.  DATA is the
    memory area to display, SIZE is the number of bytes to print, TYPE
    is the kind of data to print.  */
diff --git a/gcc/cp/pph-streamer.h b/gcc/cp/pph-streamer.h
index 9fb7ac3..2c6f405 100644
--- a/gcc/cp/pph-streamer.h
+++ b/gcc/cp/pph-streamer.h
@@ -92,9 +92,20 @@ void pph_stream_trace_bytes (pph_stream *, const void *, size_t);
 void pph_stream_trace_string (pph_stream *, const char *);
 void pph_stream_trace_string_with_length (pph_stream *, const char *, unsigned);
 
+/* In pph-streamer-out.c.  */
+void pph_stream_flush_buffers (pph_stream *);
+void pph_stream_init_write (pph_stream *);
+void pph_stream_write_tree (struct output_block *, tree, bool ref_p);
+void pph_stream_pack_value_fields (struct bitpack_d *, tree);
+
+/* In pph-streamer-in.c.  */
+void pph_stream_init_read (pph_stream *);
+void pph_stream_read_tree (struct lto_input_block *, struct data_in *, tree);
+void pph_stream_unpack_value_fields (struct bitpack_d *, tree);
+
 /* In pph.c.  FIXME move these to pph-streamer.c.  */
 struct cp_token_cache;
-extern void pth_save_token_cache (struct cp_token_cache *, pph_stream *);
+void pth_save_token_cache (struct cp_token_cache *, pph_stream *);
 
 /* Inline functions.  */
 

--
This patch is available for review at http://codereview.appspot.com/4333047



More information about the Gcc-patches mailing list