diff --git a/gcc/ChangeLog.pph b/gcc/ChangeLog.pph
index d95c153..2bf6c9a 100644
--- a/gcc/ChangeLog.pph
+++ b/gcc/ChangeLog.pph
@@ -1,5 +1,18 @@
 2012-03-04   Diego Novillo  <dnovillo@google.com>
 
+	* tree.c (type_hash_traverse): Declare.
+	(type_hash_table_retrieve_entry): New.
+	(type_hash_table_traverse): New.
+	(type_hash_table_length): New.
+	(CACHED_PREC_LEN): Factor out of ...
+	(nonstandard_integer_type_cache): ... here.
+	(traverse_nonstandard_integer_type_cache): New.
+	* tree.h (type_hash_table_traverse): Declare.
+	(type_hash_table_length): Declare.
+	(traverse_nonstandard_integer_type_cache): Declare.
+
+2012-03-04   Diego Novillo  <dnovillo@google.com>
+
 	Merge from trunk rev 184817.
 
 	BASE-VER: Update to 4.8.0-pph.
diff --git a/gcc/cp/ChangeLog.pph b/gcc/cp/ChangeLog.pph
index c867ca3..697ae2b 100644
--- a/gcc/cp/ChangeLog.pph
+++ b/gcc/cp/ChangeLog.pph
@@ -1,3 +1,30 @@
+2012-03-13   Diego Novillo  <dnovillo@google.com>
+
+	* decl.c (record_builtin_type): Call pph_register_builtin_type.
+	* pph-core.c (pph_cache_add_full_tree_r): New.
+	(pph_cache_add_full_tree): New.
+	(nitc_callback): New.
+	(pph_builtin_types): Declare.
+	(pph_register_builtin_type): New.
+	(pph_cache_add_builtin_types): New.
+	(pph_cache_add_canonical_type): New.
+	(pph_cache_preload): Call pph_cache_add_full_tree instead of
+	pph_cache_add.
+	Call traverse_nonstandard_integer_type_cache with nitc_callback.
+	Call pph_cache_add_builtin_types.
+	Call type_hash_table_traverse.
+	* pph-in.c (pph_in_tcc_type): Read TYP_NEXT_PTR_TO for
+	POINTER_TYPE types.
+	(pph_read_file_1): Call pph_in_canonical_template_parms.
+	* pph-out.c (pph_out_tcc_type): Write TYPE_NEXT_PTR_TO for
+	POINTER_TYPE types.
+	(pph_write_file): Call pph_out_canonical_template_parms.
+	* pph.h (pph_register_builtin_type): Declare.
+	(pph_out_canonical_template_parms): Declare.
+	(pph_in_canonical_template_parms): Declare.
+	* pt.c (pph_out_canonical_template_parms): New.
+	(pph_in_canonical_template_parms): New.
+
 2012-03-09   Lawrence Crowl  <crowl@google.com>
 
 	* name-lookup.c (pph_out_binding_table): Correct comment.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 279a9ab..ab2b7d2 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -3436,6 +3436,12 @@ record_builtin_type (enum rid rid_index,
 
   if (tdecl)
     debug_hooks->type_decl (tdecl, 0);
+
+  /* When using pre-parsed headers, we register builtin types in the PPH
+     pickle cache to avoid writing a physical representation of these types
+     and make sure that all references resolve to the same pre-built type.  */
+  if (pph_enabled_p ())
+    pph_register_builtin_type (type);
 }
 
 /* Record one of the standard Java types.
diff --git a/gcc/cp/pph-core.c b/gcc/cp/pph-core.c
index 464f39f..8c79017 100644
--- a/gcc/cp/pph-core.c
+++ b/gcc/cp/pph-core.c
@@ -472,6 +472,82 @@ pph_cache_init (pph_cache *cache)
 static pph_cache *pph_preloaded_cache;
 
 
+/* Callback for cp_walk_tree.  Called from pph_cache_add_full_tree.
+   Add the sub-tree *TP to the cache pointed to by DATA.  Always set
+   WALK_SUBTREES to 1 to traverse every sub-tree.  */
+
+static tree
+pph_cache_add_full_tree_r (tree *tp, int *walk_subtrees, void *data)
+{
+  pph_cache *cache = (pph_cache *) data;
+  pph_cache_add (cache, *tp, NULL, pph_tree_code_to_tag (*tp));
+  *walk_subtrees = 1;
+  return NULL;
+}
+
+
+/* Add tree T and all its children into CACHE.  */
+
+static void
+pph_cache_add_full_tree (pph_cache *cache, tree t)
+{
+  cp_walk_tree (&t, pph_cache_add_full_tree_r, cache, NULL);
+}
+
+
+/* Callback for traverse_nonstandard_integer_type_cache.  Add the
+   full tree TYPE to the cache pointed by DATA.  */
+
+static bool
+nitc_callback (tree type, void *data)
+{
+  pph_cache *cache = (pph_cache *) data;
+  pph_cache_add_full_tree (cache, type);
+  return true;
+}
+
+/* Vector of builtin types to register in the preloaded cache.  */
+static VEC(tree,gc) *pph_builtin_types;
+
+
+/* Register a builtin type to be preloaded when we are setting up the
+   pickle cache.  This is called from record_builtin_type.  */
+
+void
+pph_register_builtin_type (tree type)
+{
+  VEC_safe_push (tree, gc, pph_builtin_types, type);
+}
+
+
+/* Pre-load all the builtin types declared by the compiler.  */
+
+static void
+pph_cache_add_builtin_types (pph_cache *cache)
+{
+  unsigned i;
+  tree type;
+
+  FOR_EACH_VEC_ELT (tree, pph_builtin_types, i, type)
+    pph_cache_add_full_tree (cache, type);
+}
+
+
+/* Callback for type_hash_table_traverse.  DATA points to the cache
+   where we are preloading trees built by the front end on startup.
+   TYPE is the type to preload.  Always return true, so we visit the
+   whole table.  */
+
+static bool
+pph_cache_add_canonical_type (unsigned long h ATTRIBUTE_UNUSED, tree type,
+			      void *data)
+{
+  pph_cache *cache = (pph_cache *) data;
+  pph_cache_add_full_tree (cache, type);
+  return true;
+}
+
+
 /* Pre-load common tree nodes into CACHE.  These nodes are always built by the
    front end, so there is no need to pickle them.  */
 
@@ -481,24 +557,20 @@ pph_cache_preload (pph_cache *cache)
   unsigned i;
 
   for (i = itk_char; i < itk_none; i++)
-    pph_cache_add (cache, integer_types[i], NULL,
-                   pph_tree_code_to_tag (integer_types[i]));
+    pph_cache_add_full_tree (cache, integer_types[i]);
 
   for (i = 0; i < TYPE_KIND_LAST; i++)
-    pph_cache_add (cache, sizetype_tab[i], NULL,
-                   pph_tree_code_to_tag (sizetype_tab[i]));
+    pph_cache_add_full_tree (cache, sizetype_tab[i]);
 
   /* global_trees[] can have NULL entries in it.  Skip them.  */
   for (i = 0; i < TI_MAX; i++)
     if (global_trees[i])
-      pph_cache_add (cache, global_trees[i], NULL,
-                     pph_tree_code_to_tag (global_trees[i]));
+      pph_cache_add_full_tree (cache, global_trees[i]);
 
   /* c_global_trees[] can have NULL entries in it.  Skip them.  */
   for (i = 0; i < CTI_MAX; i++)
     if (c_global_trees[i])
-      pph_cache_add (cache, c_global_trees[i], NULL,
-                     pph_tree_code_to_tag (c_global_trees[i]));
+      pph_cache_add_full_tree (cache, c_global_trees[i]);
 
   /* cp_global_trees[] can have NULL entries in it.  Skip them.  */
   for (i = 0; i < CPTI_MAX; i++)
@@ -508,16 +580,22 @@ pph_cache_preload (pph_cache *cache)
 	continue;
 
       if (cp_global_trees[i])
-	pph_cache_add (cache, cp_global_trees[i], NULL,
-                       pph_tree_code_to_tag (cp_global_trees[i]));
+	pph_cache_add_full_tree (cache, cp_global_trees[i]);
     }
 
+  /* Pre-load the table of nonstandard integer types.  */
+  traverse_nonstandard_integer_type_cache (nitc_callback, (void *) cache);
+
+  /* Pre-load all the builtin types.  */
+  pph_cache_add_builtin_types (cache);
+
+  /* Pre-load the table of canonical types.  */
+  type_hash_table_traverse (pph_cache_add_canonical_type, cache);
+
   /* Add other well-known nodes that should always be taken from the
      current compilation context.  */
-  pph_cache_add (cache, global_namespace, NULL,
-                 pph_tree_code_to_tag (global_namespace));
-  pph_cache_add (cache, DECL_CONTEXT (global_namespace), NULL,
-                 pph_tree_code_to_tag (DECL_CONTEXT (global_namespace)));
+  pph_cache_add_full_tree (cache, global_namespace);
+  pph_cache_add_full_tree (cache, DECL_CONTEXT (global_namespace));
 }
 
 
diff --git a/gcc/cp/pph-in.c b/gcc/cp/pph-in.c
index caa90c8..12685a9 100644
--- a/gcc/cp/pph-in.c
+++ b/gcc/cp/pph-in.c
@@ -1959,12 +1959,13 @@ pph_in_tcc_type (pph_stream *stream, tree type)
 {
   TYPE_LANG_SPECIFIC (type) = pph_in_lang_type (stream);
   TYPE_POINTER_TO (type) = pph_in_tree (stream);
+  if (TREE_CODE (type) == POINTER_TYPE)
+    TYPE_NEXT_PTR_TO (type) = pph_in_tree (stream);
   TYPE_REFERENCE_TO (type) = pph_in_tree (stream);
   TYPE_NEXT_VARIANT (type) = pph_in_tree (stream);
   SET_TYPE_MODE (type, pph_in_machine_mode (stream));
-  /* FIXME pph - Streaming TYPE_CANONICAL generates many type comparison
-     failures.  Why?  */
-  /* FIXME pph: apparently redundant.  */
+  /* We do not read TYPE_CANONICAL.  Instead, we emit the table of
+     canonical types and re-instantiate it on read.  */
   TREE_CHAIN (type) = pph_in_tree (stream);
 
   /* The type values cache is built as constants are instantiated,
@@ -3255,7 +3256,12 @@ pph_read_file_1 (pph_stream *stream)
   static_aggregates = chainon (file_static_aggregates, static_aggregates);
   pph_in_decl2_hidden_state (stream);
 
-  /* Read and process the symbol table.  */
+  pph_in_canonical_template_parms (stream);
+
+  /* Read and process the symbol table.  This must be done at the end
+     because we have symbols coming in from children PPH images which
+     must be instantiated in the same order they were instantiated by
+     the original parser.  */
   pph_in_symtab (stream);
 
   if (flag_pph_dump_tree)
diff --git a/gcc/cp/pph-out.c b/gcc/cp/pph-out.c
index 3a56b93..c817f22 100644
--- a/gcc/cp/pph-out.c
+++ b/gcc/cp/pph-out.c
@@ -1859,11 +1859,13 @@ pph_out_tcc_type (pph_stream *stream, tree type)
 {
   pph_out_lang_type (stream, type);
   pph_out_tree (stream, TYPE_POINTER_TO (type));
+  if (TREE_CODE (type) == POINTER_TYPE)
+    pph_out_tree (stream, TYPE_NEXT_PTR_TO (type));
   pph_out_tree (stream, TYPE_REFERENCE_TO (type));
   pph_out_tree (stream, TYPE_NEXT_VARIANT (type));
   pph_out_machine_mode (stream, TYPE_MODE (type));
-  /* FIXME pph - Streaming TYPE_CANONICAL generates many type comparison
-     failures.  Why?  */
+  /* We do not write TYPE_CANONICAL.  Instead, we emit the table of
+     canonical types and re-instantiate it on read.  */
   pph_out_tree (stream, TREE_CHAIN (type));
 
   /* The type values cache is built as constants are instantiated,
@@ -2721,7 +2723,11 @@ pph_write_file (pph_stream *stream)
   pph_out_tree (stream, static_aggregates);
   pph_out_decl2_hidden_state (stream);
 
-  /* Emit the symbol table.  */
+  pph_out_canonical_template_parms (stream);
+
+  /* Emit the symbol table.  The symbol table must be emitted at the
+     end because all the symbols read from children PPH images are not
+     known in advance when we start reading this file in the reader.  */
   pph_out_symtab (stream);
 
   if (flag_pph_dump_tree)
diff --git a/gcc/cp/pph.h b/gcc/cp/pph.h
index e864978..c6ec227 100644
--- a/gcc/cp/pph.h
+++ b/gcc/cp/pph.h
@@ -147,6 +147,7 @@ extern void pph_dump_tree_name (FILE *file, tree t, int flags);
 extern void pph_dump_vec_tree (FILE *file, VEC(tree,gc) *v);
 extern void pph_init_include_tree (void);
 extern void pph_dump_includes (FILE *, pph_stream *, unsigned);
+extern void pph_register_builtin_type (tree);
 
 /* In pph-out.c.  */
 extern void pph_out_uint (pph_stream *stream, unsigned int value);
@@ -189,6 +190,10 @@ extern void pph_out_merge_key_template_state (pph_stream *);
 extern void pph_out_merge_body_template_state (pph_stream *);
 extern void pph_in_merge_key_template_state (pph_stream *);
 extern void pph_in_merge_body_template_state (pph_stream *);
+extern void pph_out_spec_entry_tables (pph_stream *);
+extern void pph_in_spec_entry_tables (pph_stream *);
+extern void pph_out_canonical_template_parms (pph_stream *);
+extern void pph_in_canonical_template_parms (pph_stream *);
 
 /* FIXME pph: These functions should be moved to tree.c on merge.  */
 extern VEC(tree,heap) *chain2vec (tree chain);  /* In pph-out.c.  */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9018237..7758dfe25 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3472,6 +3472,37 @@ canonical_type_parameter (tree type)
     }
 }
 
+
+/* Write the canonical type parameter table to STREAM.  */
+
+void
+pph_out_canonical_template_parms (pph_stream *stream)
+{
+  tree type;
+  unsigned i;
+
+  pph_out_uint (stream, VEC_length (tree, canonical_template_parms));
+  FOR_EACH_VEC_ELT (tree, canonical_template_parms, i, type)
+    pph_out_tree (stream, type);
+}
+
+
+/* Read the canonical type parameter table from STREAM.  */
+
+void
+pph_in_canonical_template_parms (pph_stream *stream)
+{
+  unsigned i, len;
+
+  len = pph_in_uint (stream);
+  for (i = 0; i < len; i++)
+    {
+      tree parm = pph_in_tree (stream);
+      VEC_safe_push (tree, gc, canonical_template_parms, parm);
+    }
+}
+
+
 /* Return a TEMPLATE_PARM_INDEX, similar to INDEX, but whose
    TEMPLATE_PARM_LEVEL has been decreased by LEVELS.  If such a
    TEMPLATE_PARM_INDEX already exists, it is returned; otherwise, a
diff --git a/gcc/tree.c b/gcc/tree.c
index 2eac37b..89bb013 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -6293,6 +6293,52 @@ type_hash_canon (unsigned int hashcode, tree type)
     }
 }
 
+/* Data structure used to pass data to the htab_traverse callback used
+   in type_hash_table_traverse.  */
+struct type_hash_traverse {
+  bool (*callback) (unsigned long, tree, void *);
+  void *data;
+};
+
+/* Helper for type_hash_table_traverse.  Retrieve a type hash table element and
+   call FN with it.  Pass DATA as an argument to FN.  If FN returns false,
+   traversal is stopped.  */
+
+static int
+type_hash_table_retrieve_entry (void **slot, void *data)
+{
+  struct type_hash *h = (struct type_hash *) *slot;
+  struct type_hash_traverse *e = (struct type_hash_traverse *) data;
+  return (e->callback (h->hash, h->type, e->data)) ? 1 : 0;
+}
+
+
+/* Walk the type hash table, calling function CALLBACK with every element.
+   CALLBACK receives three arguments:
+	unsigned long	representing the hash value
+	tree		the type with that hash value
+	data		a void * to arbitrary data used by CALLBACK.  */
+
+void
+type_hash_table_traverse (bool (*callback) (unsigned long, tree, void *),
+			  void *data)
+{
+  struct type_hash_traverse e;
+  e.callback = callback;
+  e.data = data;
+  htab_traverse (type_hash_table, type_hash_table_retrieve_entry, &e);
+}
+
+
+/* Return the number of types in the type hash table.  */
+
+size_t
+type_hash_table_length (void)
+{
+  return htab_elements (type_hash_table);
+}
+
+
 /* See if the data pointed to by the type hash table is marked.  We consider
    it marked if the type is marked or if a debug type number or symbol
    table entry has been made for the type.  */
@@ -7212,7 +7258,8 @@ build_type_no_quals (tree t)
 
 #define MAX_INT_CACHED_PREC \
   (HOST_BITS_PER_WIDE_INT > 64 ? HOST_BITS_PER_WIDE_INT : 64)
-static GTY(()) tree nonstandard_integer_type_cache[2 * MAX_INT_CACHED_PREC + 2];
+#define CACHED_PREC_LEN (2 * MAX_INT_CACHED_PREC + 2)
+static GTY(()) tree nonstandard_integer_type_cache[CACHED_PREC_LEN];
 
 /* Builds a signed or unsigned integer type of precision PRECISION.
    Used for C bitfields whose precision does not match that of
@@ -7250,6 +7297,24 @@ build_nonstandard_integer_type (unsigned HOST_WIDE_INT precision,
   return ret;
 }
 
+
+/* Walk nonstandard_integer_type_cache, calling CALLBACK on every non-NULL
+   entry.  CALLBACK is called with the current tree and DATA.  If
+   CALLBACK returns false, the walk is aborted.  */
+
+void
+traverse_nonstandard_integer_type_cache (bool (*callback) (tree, void *),
+					 void *data)
+{
+  size_t i;
+
+  for (i = 0; i < CACHED_PREC_LEN; i++)
+    if (nonstandard_integer_type_cache[i])
+      if (!callback (nonstandard_integer_type_cache[i], data))
+	return;
+}
+
+
 /* Create a range of some discrete type TYPE (an INTEGER_TYPE, ENUMERAL_TYPE
    or BOOLEAN_TYPE) with low bound LOWVAL and high bound HIGHVAL.  If SHARED
    is true, reuse such a type that has already been constructed.  */
diff --git a/gcc/tree.h b/gcc/tree.h
index b269ee4..5e61992 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5190,6 +5190,10 @@ extern void assign_assembler_name_if_neeeded (tree);
 extern void warn_deprecated_use (tree, tree);
 enum tree_node_structure_enum tree_node_structure_for_code (enum tree_code);
 void mark_ts_structures_for (enum tree_code, enum tree_node_structure_enum);
+void type_hash_table_traverse (bool (*) (unsigned long, tree, void *), void *);
+size_t type_hash_table_length (void);
+void traverse_nonstandard_integer_type_cache (bool (*callback) (tree, void *),
+					      void *);
 
 
 /* In cgraph.c */
