diff --git a/gcc/cp/pph-streamer.c b/gcc/cp/pph-streamer.c
index 02fd1c0..c3dee7a 100644
--- a/gcc/cp/pph-streamer.c
+++ b/gcc/cp/pph-streamer.c
@@ -41,13 +41,13 @@ along with GCC; see the file COPYING3.  If not see
 VEC(pph_stream_ptr, heap) *pph_read_images;
 
 /* A cache of pre-loaded common tree nodes.  */
-static pph_pickle_cache *pph_preloaded_cache;
+static pph_cache *pph_preloaded_cache;
 
 /* Pre-load common tree nodes into CACHE.  These nodes are always built by the
    front end, so there is no need to pickle them.  */
 
 static void
-pph_cache_preload (pph_pickle_cache *cache)
+pph_cache_preload (pph_cache *cache)
 {
   unsigned i;
 
@@ -101,7 +101,7 @@ pph_hooks_init (void)
 /* Initialize an empty pickle CACHE.  */
 
 static void
-pph_cache_init (pph_pickle_cache *cache)
+pph_cache_init (pph_cache *cache)
 {
   cache->v = NULL;
   cache->m = pointer_map_create ();
@@ -111,7 +111,7 @@ pph_cache_init (pph_pickle_cache *cache)
 void
 pph_init_preloaded_cache (void)
 {
-  pph_preloaded_cache = XCNEW (pph_pickle_cache);
+  pph_preloaded_cache = XCNEW (pph_cache);
   pph_cache_init (pph_preloaded_cache);
   pph_cache_preload (pph_preloaded_cache);
 }
@@ -169,7 +169,7 @@ pph_stream_close (pph_stream *stream)
 
   /* Deallocate all memory used.  */
   stream->file = NULL;
-  VEC_free (void_p, heap, stream->cache.v);
+  VEC_free (pph_cache_entry, heap, stream->cache.v);
   pointer_map_destroy (stream->cache.m);
   VEC_free (pph_symtab_entry, heap, stream->symtab.v);
 
@@ -398,22 +398,31 @@ pph_trace_bitpack (pph_stream *stream, struct bitpack_d *bp)
 }
 
 
-/* Insert DATA in CACHE at slot IX.  If DATA already existed in the CACHE, IX
-   must be the same as the previous entry.  */
+/* Insert DATA in CACHE at slot IX.  We support inserting the same
+   DATA at different locations of the array (FIXME pph, this happens
+   when reading builtins, which may have been converted into builtins
+   after they were read originally.  This should be detected and
+   converted into mutated references).  */
 
 void
-pph_cache_insert_at (pph_pickle_cache *cache, void *data, unsigned ix)
+pph_cache_insert_at (pph_cache *cache, void *data, unsigned ix)
 {
   void **map_slot;
+  pph_cache_entry e = { data, 0, 0 };
 
   map_slot = pointer_map_insert (cache->m, data);
   if (*map_slot == NULL)
     {
-      *map_slot = (void *) (unsigned HOST_WIDE_INT) ix;
-      if (ix + 1 > VEC_length (void_p, cache->v))
-	VEC_safe_grow_cleared (void_p, heap, cache->v, ix + 1);
-      VEC_replace (void_p, cache->v, ix, data);
+      *map_slot = (void *) (intptr_t) ix;
+      if (ix + 1 > VEC_length (pph_cache_entry, cache->v))
+	VEC_safe_grow_cleared (pph_cache_entry, heap, cache->v, ix + 1);
+      VEC_replace (pph_cache_entry, cache->v, ix, &e);
     }
+#if 0
+  /* FIXME pph.  Re-add after mutated references are implemented.  */
+  else
+    gcc_assert (ix == (intptr_t) *((intptr_t **) map_slot));
+#endif
 }
 
 
@@ -422,7 +431,7 @@ pph_cache_insert_at (pph_pickle_cache *cache, void *data, unsigned ix)
    If CACHE is NULL use pph_preloaded_cache by default.  */
 
 bool
-pph_cache_lookup (pph_pickle_cache *cache, void *data, unsigned *ix_p)
+pph_cache_lookup (pph_cache *cache, void *data, unsigned *ix_p)
 {
   void **map_slot;
   unsigned ix;
@@ -503,7 +512,7 @@ pph_cache_lookup_in_includes (void *data, unsigned *include_ix_p,
    in the CACHE, false otherwise.  */
 
 bool
-pph_cache_add (pph_pickle_cache *cache, void *data, unsigned *ix_p)
+pph_cache_add (pph_cache *cache, void *data, unsigned *ix_p)
 {
   unsigned ix;
   bool existed_p;
@@ -513,7 +522,7 @@ pph_cache_add (pph_pickle_cache *cache, void *data, unsigned *ix_p)
   else
     {
       existed_p = false;
-      ix = VEC_length (void_p, cache->v);
+      ix = VEC_length (pph_cache_entry, cache->v);
       pph_cache_insert_at (cache, data, ix);
     }
 
@@ -524,17 +533,18 @@ pph_cache_add (pph_pickle_cache *cache, void *data, unsigned *ix_p)
 }
 
 
-/* Return the pointer at slot IX in STREAM_CACHE if MARKER is an IREF.  IF
-   MARKER is a XREF then instead of looking up in STREAM_CACHE, the pointer is
-   looked up in the CACHE of pph_read_images[INCLUDE_IX].  Finally if MARKER is
-   a PREF return the pointer at slot IX in the preloaded cache.  */
+/* Return the pointer at slot IX in STREAM_CACHE if MARKER is an IREF.
+   If MARKER is a XREF then instead of looking up in STREAM_CACHE, the
+   pointer is looked up in the CACHE of pph_read_images[INCLUDE_IX].
+   Finally if MARKER is a PREF return the pointer at slot IX in the
+   preloaded cache.  */
 
 void *
-pph_cache_get (pph_pickle_cache *stream_cache, unsigned include_ix, unsigned ix,
+pph_cache_get (pph_cache *stream_cache, unsigned include_ix, unsigned ix,
                enum pph_record_marker marker)
 {
-  void *data;
-  pph_pickle_cache *cache;
+  pph_cache_entry *e;
+  pph_cache *cache;
 
   /* Determine which cache to use.  */
   switch (marker)
@@ -552,7 +562,7 @@ pph_cache_get (pph_pickle_cache *stream_cache, unsigned include_ix, unsigned ix,
       gcc_unreachable ();
     }
 
-  data = VEC_index (void_p, cache->v, ix);
-  gcc_assert (data);
-  return data;
+  e = VEC_index (pph_cache_entry, cache->v, ix);
+  gcc_assert (e);
+  return e->data;
 }
diff --git a/gcc/cp/pph-streamer.h b/gcc/cp/pph-streamer.h
index 4e62186..2a1ef8b 100644
--- a/gcc/cp/pph-streamer.h
+++ b/gcc/cp/pph-streamer.h
@@ -52,14 +52,25 @@ enum pph_record_marker {
   /* Preloaded reference. This marker indicates that this data is a preloaded
      node created by the front-end at the beginning of compilation, which we
      do not need to stream out as it will already exist on the way in.  */
-  PPH_RECORD_PREF
+  PPH_RECORD_PREF,
+
+  /* Mutated reference.  This marker indicates that this data already
+     existed in the cache for another PPH image, but it has mutated
+     since it was inserted into the cache:
+
+     - The writer will pickle the object again as if it had not
+       been pickled before.
+
+     - The reader uses this as an indication that it should not
+       allocate a new object, it should simply unpickle the object on
+       top of the already allocated object.  */
+  PPH_RECORD_MREF
 };
 
 /* Line table markers. We only stream line table entries from the parent header
    file, other entries are referred to by the name of the file which is then
    loaded as an include at the correct point in time.  */
 enum pph_linetable_marker {
-
   /* A regular line_map entry in the line_table.  */
   PPH_LINETABLE_ENTRY = 0x01,
 
@@ -102,9 +113,30 @@ typedef struct pph_file_header {
 } pph_file_header;
 
 
-typedef void *void_p;
-DEF_VEC_P(void_p);
-DEF_VEC_ALLOC_P(void_p,heap);
+/* An entry in the pickle cache.  Each entry contains a pointer to
+   the cached data and checksum information.  This checksum is used to
+   detect mutated states.  This is common, for instance, in decl trees
+   that are first parsed as declarations and later on they are
+   converted into their definition.
+
+   When the cache notices a cache hit on a mutated data, it writes a
+   PPH_RECORD_MUTATED_REF to indicate to the reader that it is about
+   to read an already instantiated tree.  */
+typedef struct pph_cache_entry {
+  /* Pointer to cached data.  */
+  void *data;
+
+  /* Checksum information for DATA.  */
+  unsigned int crc;
+
+  /* Length of the checksummed area pointed by DATA.  Note that this
+     is *not* the size of the memory area pointed by DATA, just the
+     number of bytes in DATA that we have checksummed.  */
+  unsigned int crc_nbytes;
+} pph_cache_entry;
+
+DEF_VEC_O(pph_cache_entry);
+DEF_VEC_ALLOC_O(pph_cache_entry,heap);
 
 /* A cache for storing pickled data structures.  This is used to implement
    pointer sharing.
@@ -118,13 +150,13 @@ DEF_VEC_ALLOC_P(void_p,heap);
    first materialized, its address is saved into the same cache slot
    used when writing.  Subsequent reads will simply get the
    materialized pointer from that slot.  */
-typedef struct pph_pickle_cache {
+typedef struct pph_cache {
   /* Array of entries.  */
-  VEC(void_p,heap) *v;
+  VEC(pph_cache_entry,heap) *v;
 
   /* Map between slots in the array and pointers.  */
   struct pointer_map_t *m;
-} pph_pickle_cache;
+} pph_cache;
 
 
 /* Actions associated with each symbol table entry.  These indicate
@@ -212,7 +244,7 @@ typedef struct pph_stream {
   } encoder;
 
   /* Cache of pickled data structures.  */
-  pph_pickle_cache cache;
+  pph_cache cache;
 
   /* Nonzero if the stream was opened for writing.  */
   unsigned int write_p : 1;
@@ -243,12 +275,11 @@ void pph_trace_string_with_length (pph_stream *, const char *, unsigned);
 void pph_trace_location (pph_stream *, location_t);
 void pph_trace_chain (pph_stream *, tree);
 void pph_trace_bitpack (pph_stream *, struct bitpack_d *);
-void pph_cache_insert_at (pph_pickle_cache *, void *, unsigned);
-bool pph_cache_lookup (pph_pickle_cache *, void *, unsigned *);
+void pph_cache_insert_at (pph_cache *, void *, unsigned);
+bool pph_cache_lookup (pph_cache *, void *, unsigned *);
 bool pph_cache_lookup_in_includes (void *, unsigned *, unsigned *);
-bool pph_cache_add (pph_pickle_cache *, void *, unsigned *);
-void *pph_cache_get (pph_pickle_cache *, unsigned, unsigned,
-                     enum pph_record_marker);
+bool pph_cache_add (pph_cache *, void *, unsigned *);
+void *pph_cache_get (pph_cache *, unsigned, unsigned, enum pph_record_marker);
 
 /* In pph-streamer-out.c.  */
 void pph_flush_buffers (pph_stream *);
