diff mbox

[pph] AST streaming (2/4) (issue4303049)

Message ID 20110323221628.DBA91ED0E@topo.tor.corp.google.com
State New
Headers show

Commit Message

Diego Novillo March 23, 2011, 10:16 p.m. UTC
Main streaming support.

See http://gcc.gnu.org/ml/gcc-patches/2011-03/msg01556.html for details.

cp/ChangeLog.pph

2011-03-23  Diego Novillo  <dnovillo@google.com>

	* Make-lang.in (cp/pph-streamer.o): Add dependencies on
	tree-pretty-print.h, CXX_PPH_H, TREE_PASS_H, version.h and
	cppbuiltin.h
	* pph-streamer.c: Include tree-pretty-print.h, pph.h,
	tree-pass.h, version.h and cppbuiltin.h.
	(pph_get_section_data): New.
	(pph_free_section_data): New.
	(pph_stream_init_read): Rename from pph_file_read.
	Initialize LTO streaming data structures.
	Read pph file in memory.
	(pph_stream_init_write): Factor out of ...
	(pph_stream_open): ... here.
	(pph_stream_write_header): New.
	(pph_stream_write_body): Factor out of ...
	(pph_stream_close): ... here.
	Call pph_stream_write_header.
	(enum pph_trace_type): Declare.
	(pph_stream_trace): New.
	(pph_stream_trace_tree): New.
	(pph_stream_trace_uint): New.
	(pph_stream_trace_bytes): New.
	(pph_stream_trace_string): New.
	(pph_stream_trace_string_with_length): New.
	* pph-streamer.h (PPH_NUM_SECTIONS): Define.
	(PPH_USE_FILE_IO): Remove.  Update all users.
	(pph_id_str): Define.
	(pph_file_header): Declare.
	(pph_stream): Add fields pph_sections, file_data and file_size.
	(pph_stream_open): Change second argument to const char *.
	Update all users.
	(pph_stream_trace_tree): Declare.
	(pph_stream_trace_uint): Declare.
	(pph_stream_trace_bytes): Declare.
	(pph_stream_trace_string): Declare.
	(pph_stream_trace_string_with_length): Declare.
	(pph_output_tree): Call pph_stream_trace_tree if flag_pph_tracer
	is enabled.
	(pph_input_tree): Likewise.
	(pph_output_uint): Call pph_stream_trace_uint if flag_pph_tracer
	is enabled.
	(pph_input_uint): Likewise.
	(pph_output_bytes): Call pph_stream_trace_bytes if flag_pph_tracer
	is enabled.
	(pph_input_bytes): Likewise.
	(pph_output_string): Call pph_stream_trace_string if flag_pph_tracer
	is enabled.
	(pph_input_string): Likewise.
	(pph_output_string_with_length): Call
	pph_stream_trace_string_with_length if flag_pph_tracer is
	enabled.
	* pph.c (pph_print_macro_defs_before): Call pph_output_string.
	(pph_print_macro_defs_after): Likewise.
	(pth_load_token_value): Do not free the read string.
	(pth_load_identifiers): Likewise.
	(pth_load_include): Likewise.
	(pth_load_image): Call pph_input_bytes to read the header.
	(write_pph_print): Call pph_output_tree.
	(write_pph_file_object): Remove fprintf() call.
	(pth_include_handler): Remove FIXME marker.
	(pph_include_handler): Tidy.


--
This patch is available for review at http://codereview.appspot.com/4303049
diff mbox

Patch

diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 3a52e1f..bcb2ba1 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -324,12 +324,10 @@  cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_CORE_H) \
   $(CXX_PPH_H)
 cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) $(C_COMMON_H) \
 	$(TM_H) coretypes.h pointer-set.h tree-iterator.h
-
 cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 	$(TM_H) $(CXX_TREE_H) $(TIMEVAR_H) gt-cp-name-lookup.h \
 	$(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h tree-pretty-print.h \
 	$(CXX_PPH_H)
-
 cp/cxx-pretty-print.o: cp/cxx-pretty-print.c $(CXX_PRETTY_PRINT_H) \
   $(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h $(CXX_TREE_H) tree-pretty-print.h
 cp/pph.o: cp/pph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(CPPLIB_H) \
@@ -337,4 +335,5 @@  cp/pph.o: cp/pph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(CPPLIB_H) \
 	fixed-value.h $(TREE_PASS_H) $(TREE_INLINE_H) tree-pretty-print.h \
 	$(CXX_PARSER_H) $(CXX_PPH_H) $(CXX_PPH_STREAMER_H)
 cp/pph-streamer.o: cp/pph-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
-	$(TREE_H) $(LTO_STREAMER_H) $(CXX_PPH_STREAMER_H)
+	$(TREE_H) tree-pretty-print.h $(LTO_STREAMER_H) $(CXX_PPH_STREAMER_H) \
+	$(CXX_PPH_H) $(TREE_PASS_H) version.h cppbuiltin.h
diff --git a/gcc/cp/pph-streamer.c b/gcc/cp/pph-streamer.c
index c170f1f..cca42e6 100644
--- a/gcc/cp/pph-streamer.c
+++ b/gcc/cp/pph-streamer.c
@@ -23,68 +23,147 @@  along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tree.h"
 #include "langhooks.h"
+#include "tree-pretty-print.h"
 #include "lto-streamer.h"
 #include "pph-streamer.h"
-
-#if !defined PPH_USE_FILE_IO
+#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;
-#endif
+
+
+/* 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_file_read (pph_stream *stream)
+pph_stream_init_read (pph_stream *stream)
 {
-#if defined PPH_USE_FILE_IO
-  stream->file = fopen (stream->name, "rb");
-#else
-  void *data;
   struct stat st;
-  size_t bytes_read, data_size;
-
-  /* Read STREAM->NAME into the memory buffer DATA.  */
-  stat (stream->name, &st);
-  data_size = (size_t) st.st_size;
-  data = XCNEWVEC (char, data_size);
-  stream->file = fopen (stream->name, "rb");
-  gcc_assert (stream->file);
-  bytes_read = fread (data, 1, data_size, stream->file);
-  gcc_assert (bytes_read == data_size);
-  fclose (stream->file);
+  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, (const char *) data, 0, data_size);
-  stream->data_in = lto_data_in_create (NULL, NULL, 0, NULL);
-#endif
+  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);
 }
 
 
-/* Create a new PPH stream to be stored on the file called NAME.  If
-   TO_READ_P is true, the file is open for reading.  */
+/* Create a new PPH stream to be stored on the file called NAME.
+   MODE is passed to fopen directly.  */
 
 pph_stream *
-pph_stream_open (const char *name, bool to_read_p)
+pph_stream_open (const char *name, const char *mode)
 {
-  pph_stream *stream = XCNEW (pph_stream);
-  stream->name = xstrdup (name);
-  if (!to_read_p)
+  pph_stream *stream;
+  FILE *f;
+
+  stream = NULL;
+  f = fopen (name, mode);
+  if (f)
     {
-      stream->file = fopen (name, "wb");
-      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);
+      stream = XCNEW (pph_stream);
+      stream->file = f;
+      stream->name = xstrdup (name);
+      stream->write_p = (strchr (mode, 'w') != NULL);
+      if (stream->write_p)
+	pph_stream_init_write (stream);
+      else
+	pph_stream_init_read (stream);
     }
-  else
-    pph_file_read (stream);
 
   return stream;
 }
 
 
-#if !defined PPH_USE_FILE_IO
 /* Callback for lang_hooks.lto.begin_section.  Open file NAME.  */
 
 static void
@@ -112,31 +191,44 @@  static void
 pph_stream_end_section (void)
 {
 }
-#endif
 
 
-/* Close PPH stream STREAM.  Write all the ASTs to disk and deallocate
-   all memory used by it.  */
+/* Write the header for the PPH file represented by STREAM.  */
 
-void
-pph_stream_close (pph_stream *stream)
+static void
+pph_stream_write_header (pph_stream *stream)
 {
-#if defined PPH_USE_FILE_IO
-  fclose (stream->file);
-#else
-  gcc_assert (current_pph_file == NULL);
-  current_pph_file = stream->file;
+  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);
+}
 
-  /* 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_stream_output() calls.  */
-  lto_begin_section (stream->name, false);
+/* Write the body of the PPH file represented by STREAM.  */
 
-  /* Make string 0 be a NULL string.  */
-  lto_output_1_stream (stream->ob->string_stream, 0);
+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.  */
@@ -148,10 +240,148 @@  pph_stream_close (pph_stream *stream)
 
   /* Finally, physically write all the streams.  */
   lto_write_stream (stream->ob->main_stream);
-  lto_write_stream (stream->ob->string_stream);
+}
+
+
+/* Close PPH stream STREAM.  Write all the ASTs to disk and deallocate
+   all memory used by it.  */
+
+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 ();
+    }
 
-  lto_end_section ();
   fclose (stream->file);
-  current_pph_file = NULL;
-#endif
+  stream->file = current_pph_file = NULL;
+}
+
+
+/* Data types supported by the PPH tracer.  */
+enum pph_trace_type
+{
+    PPH_TRACE_TREE,
+    PPH_TRACE_UINT,
+    PPH_TRACE_BYTES,
+    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.  */
+
+static void
+pph_stream_trace (pph_stream *stream, const void *data, unsigned int nbytes,
+		  enum pph_trace_type type)
+{
+  const char *op = (stream->write_p) ? "write" : "read";
+  const char *type_s[] = { "tree", "uint", "bytes", "string" };
+
+  fprintf (pph_logfile, "*** %s: op=%s, type=%s, size=%u, value=",
+	   stream->name, op, type_s[type], (unsigned) nbytes);
+
+  switch (type)
+    {
+    case PPH_TRACE_TREE:
+      {
+	const_tree t = (const_tree) data;
+	print_generic_expr (pph_logfile, CONST_CAST (union tree_node *, t),
+			    TDF_SLIM);
+      }
+      break;
+
+    case PPH_TRACE_UINT:
+      {
+	unsigned int val = *((const unsigned int *) data);
+	fprintf (pph_logfile, "%u (0x%x)", val, val);
+      }
+      break;
+
+    case PPH_TRACE_BYTES:
+      {
+	size_t i;
+	const char *buffer = (const char *) data;
+	for (i = 0; i < MIN (nbytes, 100); i++)
+	  {
+	    if (ISPRINT (buffer[i]))
+	      fprintf (pph_logfile, "%c", buffer[i]);
+	    else
+	      fprintf (pph_logfile, "[0x%02x]", (unsigned int) buffer[i]);
+	  }
+      }
+      break;
+
+    case PPH_TRACE_STRING:
+      if (data)
+	fprintf (pph_logfile, "%.*s", (int) nbytes, (const char *) data);
+      else
+	fprintf (pph_logfile, "<nil>");
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  fputc ('\n', pph_logfile);
+}
+
+
+/* Show tracing information for T on STREAM.  */
+
+void
+pph_stream_trace_tree (pph_stream *stream, tree t)
+{
+  pph_stream_trace (stream, t, tree_code_size (TREE_CODE (t)), PPH_TRACE_TREE);
+}
+
+
+/* Show tracing information for VAL on STREAM.  */
+
+void
+pph_stream_trace_uint (pph_stream *stream, unsigned int val)
+{
+  pph_stream_trace (stream, &val, sizeof (val), PPH_TRACE_UINT);
+}
+
+
+/* Show tracing information for NBYTES bytes of memory area DATA on
+   STREAM.  */
+
+void
+pph_stream_trace_bytes (pph_stream *stream, const void *data, size_t nbytes)
+{
+  pph_stream_trace (stream, data, nbytes, PPH_TRACE_BYTES);
+}
+
+
+/* Show tracing information for S on STREAM.  */
+
+void
+pph_stream_trace_string (pph_stream *stream, const char *s)
+{
+  pph_stream_trace (stream, s, s ? strlen (s) : 0, PPH_TRACE_STRING);
+}
+
+
+/* Show tracing information for LEN bytes of S on STREAM.  */
+
+void
+pph_stream_trace_string_with_length (pph_stream *stream, const char *s,
+				     unsigned int len)
+{
+  pph_stream_trace (stream, s, len, PPH_TRACE_STRING);
 }
diff --git a/gcc/cp/pph-streamer.h b/gcc/cp/pph-streamer.h
index 1b04d65..afffe35 100644
--- a/gcc/cp/pph-streamer.h
+++ b/gcc/cp/pph-streamer.h
@@ -24,9 +24,32 @@  along with GCC; see the file COPYING3.  If not see
 #include "lto-streamer.h"
 #include "tree.h"
 
-/* FIXME pph - Workaround incomplete PPH streamer.  Use regular FILE I/O.  */
-#define PPH_USE_FILE_IO	1
+/* Number of sections in a PPH file.  FIXME, currently only one section
+   is supported.  To add more, it will also be necessary to handle
+   section names in pph_get_section_data and pph_free_section_data.  */
+#define PPH_NUM_SECTIONS	1
 
+/* String to identify PPH files.  Keep it to 7 characters, so it takes
+   exactly 8 bytes in the file.  */
+static const char pph_id_str[] = "PPH0x42";
+
+/* Structure of the header of a PPH file.  */
+typedef struct pph_file_header {
+  /* Identification string.  */
+  char id_str[sizeof(pph_id_str)];
+
+  /* Version information.  */
+  char major_version;
+  char minor_version;
+  char patchlevel;
+
+  /* Size of the string table in bytes.  */
+  unsigned int strtab_size;
+} pph_file_header;
+
+
+/* A PPH stream contains all the data and attributes needed to
+   write symbols, declarations and other parsing products to disk.  */
 typedef struct pph_stream {
   /* Path name of the PPH file.  */
   const char *name;
@@ -45,16 +68,29 @@  typedef struct pph_stream {
   struct lto_input_block *ib;
 
   /* String tables and other descriptors used by the LTO reading
-      routines.  */
+     routines.  NULL when the file is opened for reading.  */
   struct data_in *data_in;
 
-  /* Nonzero if the stream was open for writing.  */
+  /* Array of sections in the PPH file.  */
+  struct lto_file_decl_data **pph_sections;
+
+  /* Buffer holding the file contents.  FIXME pph, we are bringing
+     the whole file in memory at once.  This seems wasteful.  */
+  char *file_data;
+  size_t file_size;
+
+  /* Nonzero if the stream was opened for writing.  */
   unsigned int write_p : 1;
 } pph_stream;
 
 /* In pph-streamer.c.  */
-pph_stream *pph_stream_open (const char *, bool);
+pph_stream *pph_stream_open (const char *, const char *);
 void pph_stream_close (pph_stream *);
+void pph_stream_trace_tree (pph_stream *, tree);
+void pph_stream_trace_uint (pph_stream *, unsigned int);
+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);
 
 
 /* Inline functions.  */
@@ -63,52 +99,36 @@  void pph_stream_close (pph_stream *);
 static inline void
 pph_output_tree (pph_stream *stream ATTRIBUTE_UNUSED, tree t ATTRIBUTE_UNUSED)
 {
-#if defined PPH_USE_FILE_IO
-  gcc_unreachable ();
-#else
+  if (flag_pph_tracer)
+    pph_stream_trace_tree (stream, t);
   lto_output_tree (stream->ob, t, true);
-#endif
 }
 
 /* Write a uint VALUE to STREAM.  */
 static inline void
 pph_output_uint (pph_stream *stream, unsigned int value)
 {
-#if defined PPH_USE_FILE_IO
-  fwrite (&value, 1, sizeof (value), stream->file);
-#else
+  if (flag_pph_tracer)
+    pph_stream_trace_uint (stream, value);
   lto_output_sleb128_stream (stream->ob->main_stream, value);
-#endif
 }
 
 /* Write N bytes from P to STREAM.  */
 static inline void
 pph_output_bytes (pph_stream *stream, const void *p, size_t n)
 {
-#if defined PPH_USE_FILE_IO
-  fwrite (p, 1, n, stream->file);
-#else
+  if (flag_pph_tracer)
+    pph_stream_trace_bytes (stream, p, n);
   lto_output_data_stream (stream->ob->main_stream, p, n);
-#endif
 }
 
 /* Write string STR to STREAM.  */
 static inline void
 pph_output_string (pph_stream *stream, const char *str)
 {
-#if defined PPH_USE_FILE_IO
-  if (str == NULL)
-    pph_output_uint (stream, -1U);
-  else
-    {
-      unsigned length = strlen (str);
-      pph_output_uint (stream, length);
-      if (length > 0)
-	pph_output_bytes (stream, str, length);
-    }
-#else
   lto_output_string (stream->ob, stream->ob->main_stream, str);
-#endif
+  if (flag_pph_tracer)
+    pph_stream_trace_string (stream, str);
 }
 
 /* Write string STR of length LEN to STREAM.  */
@@ -116,35 +136,29 @@  static inline void
 pph_output_string_with_length (pph_stream *stream, const char *str,
 			       unsigned int len)
 {
-#if defined PPH_USE_FILE_IO
-  if (str == NULL)
-    pph_output_uint (stream, -1U);
+  if (str)
+    lto_output_string_with_length (stream->ob, stream->ob->main_stream,
+				   str, len + 1);
   else
     {
-      pph_output_uint (stream, len);
-      if (len > 0)
-	pph_output_bytes (stream, str, len);
+      /* lto_output_string_with_length does not handle NULL strings,
+	 but lto_output_string does.  */
+      pph_output_string (stream, NULL);
     }
-#else
-  lto_output_string_with_length (stream->ob, stream->ob->main_stream, str, len);
-#endif
+
+  if (flag_pph_tracer)
+    pph_stream_trace_string_with_length (stream, str, len);
 }
 
 /* Read an unsigned HOST_WIDE_INT integer from STREAM.  */
-static inline unsigned
+static inline unsigned int
 pph_input_uint (pph_stream *stream)
 {
-#if defined PPH_USE_FILE_IO
-  unsigned num;
-  size_t received;
-  received = fread (&num, sizeof num, 1, stream->file);
-  gcc_assert (received == 1);
-  return num;
-#else
   HOST_WIDE_INT unsigned n = lto_input_uleb128 (stream->ib);
   gcc_assert (n == (unsigned) n);
+  if (flag_pph_tracer)
+    pph_stream_trace_uint (stream, n);
   return (unsigned) n;
-#endif
 }
 
 /* Read N bytes from STREAM into P.  The caller is responsible for 
@@ -152,12 +166,9 @@  pph_input_uint (pph_stream *stream)
 static inline void
 pph_input_bytes (pph_stream *stream, void *p, size_t n)
 {
-#if defined PPH_USE_FILE_IO
-  size_t received = fread (p, 1, n, stream->file);
-  gcc_assert (received == n);
-#else
   lto_input_data_block (stream->ib, p, n);
-#endif
+  if (flag_pph_tracer)
+    pph_stream_trace_bytes (stream, p, n);
 }
 
 /* Read and return a string of up to MAX characters from STREAM.
@@ -167,20 +178,10 @@  pph_input_bytes (pph_stream *stream, void *p, size_t n)
 static inline const char *
 pph_input_string (pph_stream *stream)
 {
-#if defined PPH_USE_FILE_IO
-  char *buf = NULL;
-  unsigned len;
-  size_t received = fread (&len, sizeof len, 1, stream->file);
-  gcc_assert (received == 1);
-  if (len > 0 && len != -1U)
-    {
-      buf = XCNEWVEC (char, len + 1);
-      received = fread (buf, 1, len, stream->file);
-    }
-  return (const char *) buf;
-#else
-  return lto_input_string (stream->data_in, stream->ib);
-#endif
+  const char *s = lto_input_string (stream->data_in, stream->ib);
+  if (flag_pph_tracer)
+    pph_stream_trace_string (stream, s);
+  return s;
 }
 
 /* Load an AST from STREAM.  Return the corresponding tree.  */
@@ -188,11 +189,10 @@  pph_input_string (pph_stream *stream)
 static inline tree
 pph_input_tree (pph_stream *stream ATTRIBUTE_UNUSED)
 {
-#if defined PPH_USE_FILE_IO
-  gcc_unreachable ();
-#else
-  return lto_input_tree (stream->ib, stream->data_in);
-#endif
+  tree t = lto_input_tree (stream->ib, stream->data_in);
+  if (flag_pph_tracer)
+    pph_stream_trace_tree (stream, t);
+  return t;
 }
 
 #endif  /* GCC_CP_PPH_STREAMER_H  */
diff --git a/gcc/cp/pph.c b/gcc/cp/pph.c
index e0ddf24..5ec7916 100644
--- a/gcc/cp/pph.c
+++ b/gcc/cp/pph.c
@@ -197,18 +197,17 @@  pth_name_for (const char *name)
 }
 
 
-/* Open an image file for path NAME.  READ_P is true if the file should
-   be opened for reading.  */
+/* Open an image file for path NAME.  MODE is as in fopen.  */
 
 static pph_stream *
-pth_file_for (const char *name, bool read_p)
+pth_file_for (const char *name, const char *mode)
 {
   char *s;
   pph_stream *f;
 
   s = pth_name_for (name);
-  f = pph_stream_open (s, read_p);
-  if (f->file == NULL)
+  f = pph_stream_open (s, mode);
+  if (!f)
     fatal_error ("can%'t open token stream file %s: %m", s);
   free (s);
 
@@ -462,9 +461,16 @@  pph_print_macro_defs_before (pph_stream *stream, cpp_idents_used *identifiers)
       const char *before = entry->before_str;
 
       if (before)
-          fprintf (stream->file, "#define %s%s\n", ident, before);
+	{
+	  pph_output_string (stream, "#define ");
+	  pph_output_string (stream, ident);
+	  pph_output_string (stream, before);
+	}
       else
-          fprintf (stream->file, "#undef %s\n", ident);
+	{
+	  pph_output_string (stream, "#undef ");
+	  pph_output_string (stream, ident);
+	}
     }
 }
 
@@ -487,9 +493,16 @@  pph_print_macro_defs_after (pph_stream *stream, cpp_idents_used *identifiers)
       if (before != after)
         {
           if (after && (!before || strcmp (after, before) != 0))
-              fprintf (stream->file, "#define %s%s\n", ident, after);
+	    {
+	      pph_output_string (stream, "#define ");
+	      pph_output_string (stream, ident);
+	      pph_output_string (stream, after);
+	    }
           else if (before)
-              fprintf (stream->file, "#undef %s\n", ident);
+	    {
+	      pph_output_string (stream, "#undef ");
+	      pph_output_string (stream, ident);
+	    }
         }
     }
 }
@@ -864,7 +877,7 @@  pth_save_image (pth_image *image)
 
   /* Open the stream in append mode since we have already created
      it in pth_new_image.  */
-  stream = pth_file_for (image->fname, false);
+  stream = pth_file_for (image->fname, "wb");
 
   /* Write a header to recognize the file later.  */
   pth_write_header (image, stream);
@@ -984,7 +997,6 @@  pth_load_token_value (cp_token *token, pph_stream *f)
       case CPP_NAME:
 	str = pph_input_string (f);
 	token->u.value = get_identifier (str);
-	free (CONST_CAST (char *, str));
 	break;
 
       case CPP_KEYWORD:
@@ -1005,7 +1017,6 @@  pth_load_token_value (cp_token *token, pph_stream *f)
       case CPP_STRING32:
 	str = pph_input_string (f);
 	token->u.value = build_string (strlen (str), str);
-	free (CONST_CAST (char *, str));
 	break;
 
       case CPP_PRAGMA:
@@ -1051,7 +1062,6 @@  pth_load_identifiers (cpp_idents_used *identifiers, pph_stream *stream)
       identifiers->entries[j].ident_len = ident_len;
       identifiers->entries[j].ident_str =
         (const char *) obstack_copy0 (identifiers->strings, s, ident_len);
-      free (CONST_CAST (char *, s));
 
       s = pph_input_string (stream);
       if (s)
@@ -1060,7 +1070,6 @@  pth_load_identifiers (cpp_idents_used *identifiers, pph_stream *stream)
 	  identifiers->entries[j].before_len = before_len;
 	  identifiers->entries[j].before_str = (const char *)
 	      obstack_copy0 (identifiers->strings, s, before_len);
-	  free (CONST_CAST (char *, s));
 	}
       else
 	{
@@ -1077,7 +1086,6 @@  pth_load_identifiers (cpp_idents_used *identifiers, pph_stream *stream)
 	  identifiers->entries[j].after_len = after_len;
 	  identifiers->entries[j].after_str = (const char *)
 	      obstack_copy0 (identifiers->strings, s, after_len);
-	  free (CONST_CAST (char *, s));
 	}
       else
 	{
@@ -1162,7 +1170,6 @@  pth_load_include (pth_state *state, pth_image *image, cpp_reader *reader,
 
   s = pph_input_string (stream);
   include->image = pth_image_lookup (state, s, reader);
-  free (CONST_CAST (char *, s));
 
   tmp = pph_input_uint (stream);
   include->itype = (enum include_type) tmp;
@@ -1184,14 +1191,17 @@  pth_load_image (pth_state *state, pth_image *image, cpp_reader *reader)
 {
   pph_stream *stream;
   unsigned i, num;
+  char *buf;
 
   timevar_push (TV_PTH_LOAD);
 
-  stream = pth_file_for (image->fname, true);
+  stream = pth_file_for (image->fname, "rb");
 
   /* Skip over the header, as we assume that it has already been
      validated by pth_have_valid_image_for.  */
-  fseek (stream->file, (long) pth_header_len (), SEEK_SET);
+  buf = XCNEWVEC (char, pth_header_len ());
+  pph_input_bytes (stream, buf, pth_header_len ());
+  free (buf);
 
   /* Read the include-hunk (IH) sequencing vector.  */
   num = pph_input_uint (stream);
@@ -1258,7 +1268,8 @@  pth_have_valid_image_for (const char *fname, pth_image *image)
     goto invalid_img;
 
   /* If the file exists, check if it has a valid signature.  */
-  f = pph_stream_open (img_name, true);
+  f = pph_stream_open (img_name, "rb");
+  gcc_assert (f);
 
   good_id = pth_id_str ();
   id = XCNEWVEC (char, strlen (good_id) + 1);
@@ -1834,17 +1845,17 @@  pth_file_change (cpp_reader *reader, const struct line_map *map)
 
 typedef void (*write_pph_format)(pph_stream *stream, tree decl, int flags);
 
+/* Forward declarations to break cyclic references.  */
 static void
-write_pph_namespace (pph_stream *stream, tree decl, write_pph_format fmt, int flags);
+write_pph_namespace (pph_stream *, tree, write_pph_format, int);
 
 
 /* Write symbol to PPH output file like C.  */
 
 static void
-write_pph_print (pph_stream *stream, tree decl, int flags)
+write_pph_print (pph_stream *stream, tree decl, int flags ATTRIBUTE_UNUSED)
 {
-  print_generic_decl (stream->file, decl, flags | TDF_VISDEF);
-  fprintf (stream->file, "\n");
+  pph_output_tree (stream, decl);
 }
 
 
@@ -1860,7 +1871,8 @@  write_pph_dump (pph_stream *stream, tree decl, int flags)
 /* Write symbol to PPH output file.  */
 
 static void
-write_pph_symbol (pph_stream *stream, tree decl, write_pph_format fmt, int flags)
+write_pph_symbol (pph_stream *stream, tree decl, write_pph_format fmt,
+		  int flags)
 {
   if (TREE_CODE (decl) == NAMESPACE_DECL)
     write_pph_namespace (stream, decl, fmt, flags);
@@ -1884,7 +1896,8 @@  write_pph_namespace_1 (declvisitor vtor, pph_stream *stream, tree decl,
 }
 
 static void
-write_pph_namespace (pph_stream *stream, tree decl, write_pph_format fmt, int flags)
+write_pph_namespace (pph_stream *stream, tree decl, write_pph_format fmt,
+		     int flags)
 {
   struct cp_binding_level *level = NAMESPACE_LEVEL (decl);
   decl = level->namespaces;
@@ -1903,8 +1916,6 @@  write_pph_file_object (pph_stream *stream, cpp_idents_used *idents_used)
 { 
   int flags = 0;
   pth_save_identifiers (idents_used, stream);
-  fprintf (stream->file, "\n====\n");
-  /* FIX pph: Wrong format for writing decls.  */
   write_pph_namespace (stream, global_namespace, write_pph_print, flags);
 }
 
@@ -1943,7 +1954,7 @@  write_pph_file (void)
   if (flag_pph_debug >= 1)
     fprintf (pph_logfile, "PPH: Writing %s\n", pph_out_file);
 
-  stream = pph_stream_open (pph_out_file, false);
+  stream = pph_stream_open (pph_out_file, "wb");
   if (!stream)
     fatal_error ("Cannot open PPH file for writing: %s: %m", pph_out_file);
 
@@ -2040,8 +2051,8 @@  read_pph_file (const char *filename)
   if (flag_pph_debug >= 1)
     fprintf (pph_logfile, "PPH: Reading %s\n", filename);
 
-  stream = pph_stream_open (filename, true);
-  if (!stream->file)
+  stream = pph_stream_open (filename, "rb");
+  if (!stream)
     fatal_error ("Cannot open PPH file for reading: %s: %m", filename);
 
   if (flag_pph_fmt == 0)
@@ -2083,7 +2094,7 @@  pth_include_handler (cpp_reader *reader ATTRIBUTE_UNUSED,
 /* Record a #include or #include_next for PPH.  */
 
 static void
-pph_include_handler (cpp_reader *reader /*FIXME pph: ATTRIBUTE_UNUSED */,
+pph_include_handler (cpp_reader *reader,
                      location_t loc ATTRIBUTE_UNUSED,
                      const unsigned char *dname,
                      const char *name,
@@ -2101,7 +2112,7 @@  pph_include_handler (cpp_reader *reader /*FIXME pph: ATTRIBUTE_UNUSED */,
     }
 
   pph_file = query_pph_include_map (name);
-  if (pph_file != NULL && ! cpp_included_before (reader, name, input_location))
+  if (pph_file != NULL && !cpp_included_before (reader, name, input_location))
     read_pph_file (pph_file);
 }